Parcourir la source

Merge remote-tracking branch 'origin/development' 3/27/2013

MichPerry-GG il y a 12 ans
Parent
commit
3cdb5b5f55
100 fichiers modifiés avec 6180 ajouts et 4339 suppressions
  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. 21 0
      engine/source/2d/assets/AnimationAsset.cc
  8. 2 1
      engine/source/2d/assets/AnimationAsset.h
  9. 0 336
      engine/source/2d/assets/AnimationController.cc
  10. 0 94
      engine/source/2d/assets/AnimationController.h
  11. 262 164
      engine/source/2d/assets/ImageAsset.cc
  12. 5 0
      engine/source/2d/assets/ImageAsset.h
  13. 17 4
      engine/source/2d/assets/ParticleAsset.cc
  14. 1 0
      engine/source/2d/assets/ParticleAsset.h
  15. 18 5
      engine/source/2d/assets/ParticleAssetEmitter.cc
  16. 11 15
      engine/source/2d/assets/ParticleAssetEmitter.h
  17. 103 32
      engine/source/2d/assets/ParticleAssetField.cc
  18. 2 0
      engine/source/2d/assets/ParticleAssetField.h
  19. 37 3
      engine/source/2d/assets/ParticleAssetFieldCollection.cc
  20. 2 0
      engine/source/2d/assets/ParticleAssetFieldCollection.h
  21. 42 42
      engine/source/2d/controllers/BuoyancyController.cc
  22. 14 14
      engine/source/2d/controllers/BuoyancyController.h
  23. 30 9
      engine/source/2d/controllers/PointForceController.cc
  24. 17 4
      engine/source/2d/controllers/PointForceController.h
  25. 23 0
      engine/source/2d/controllers/PointForceController_ScriptBinding.h
  26. 51 0
      engine/source/2d/core/ImageFrameProvider.cc
  27. 47 0
      engine/source/2d/core/ImageFrameProvider.h
  28. 586 0
      engine/source/2d/core/ImageFrameProviderCore.cc
  29. 153 0
      engine/source/2d/core/ImageFrameProviderCore.h
  30. 6 5
      engine/source/2d/core/ParticleSystem.h
  31. 2 6
      engine/source/2d/core/RenderProxy.cc
  32. 11 19
      engine/source/2d/core/RenderProxy.h
  33. 28 32
      engine/source/2d/core/RenderProxy_ScriptBinding.h
  34. 7 11
      engine/source/2d/core/SpriteBase.cc
  35. 11 19
      engine/source/2d/core/SpriteBase.h
  36. 31 35
      engine/source/2d/core/SpriteBase_ScriptBinding.h
  37. 157 74
      engine/source/2d/core/SpriteBatch.cc
  38. 11 4
      engine/source/2d/core/SpriteBatch.h
  39. 192 62
      engine/source/2d/core/SpriteBatchItem.cc
  40. 19 13
      engine/source/2d/core/SpriteBatchItem.h
  41. 61 21
      engine/source/2d/core/SpriteBatchQuery.cc
  42. 10 6
      engine/source/2d/core/SpriteBatchQuery.h
  43. 0 413
      engine/source/2d/core/SpriteProxyBase.cc
  44. 0 117
      engine/source/2d/core/SpriteProxyBase.h
  45. 310 0
      engine/source/2d/experimental/composites/WaveComposite.cc
  46. 98 0
      engine/source/2d/experimental/composites/WaveComposite.h
  47. 22 0
      engine/source/2d/experimental/composites/WaveComposite_ScriptBinding.h
  48. 114 39
      engine/source/2d/gui/SceneWindow.cc
  49. 25 29
      engine/source/2d/gui/SceneWindow.h
  50. 46 0
      engine/source/2d/gui/SceneWindow_ScriptBinding.h
  51. 8 8
      engine/source/2d/gui/guiSpriteCtrl.cc
  52. 8 12
      engine/source/2d/gui/guiSpriteCtrl.h
  53. 7 7
      engine/source/2d/gui/guiSpriteCtrl_ScriptBindings.h
  54. 11 6
      engine/source/2d/scene/ContactFilter.cc
  55. 373 289
      engine/source/2d/scene/Scene.cc
  56. 44 22
      engine/source/2d/scene/Scene.h
  57. 3 3
      engine/source/2d/scene/SceneRenderState.h
  58. 268 152
      engine/source/2d/scene/Scene_ScriptBinding.h
  59. 305 57
      engine/source/2d/scene/WorldQuery.cc
  60. 30 15
      engine/source/2d/scene/WorldQuery.h
  61. 44 26
      engine/source/2d/sceneobject/CompositeSprite.cc
  62. 6 1
      engine/source/2d/sceneobject/CompositeSprite.h
  63. 20 13
      engine/source/2d/sceneobject/CompositeSprite_ScriptBinding.h
  64. 39 54
      engine/source/2d/sceneobject/ParticlePlayer.cc
  65. 9 13
      engine/source/2d/sceneobject/ParticlePlayer.h
  66. 397 59
      engine/source/2d/sceneobject/SceneObject.cc
  67. 1 3
      engine/source/2d/sceneobject/SceneObject.h
  68. 67 14
      engine/source/2d/sceneobject/SceneObject_ScriptBinding.h
  69. 4 27
      engine/source/2d/sceneobject/Scroller.cc
  70. 14 171
      engine/source/2d/sceneobject/ShapeVector.cc
  71. 16 30
      engine/source/2d/sceneobject/ShapeVector.h
  72. 166 33
      engine/source/2d/sceneobject/ShapeVector_ScriptBinding.h
  73. 1 1
      engine/source/2d/sceneobject/Sprite.cc
  74. 0 1
      engine/source/2d/sceneobject/Sprite.h
  75. 25 4
      engine/source/assets/assetBase.cc
  76. 1 0
      engine/source/assets/assetBase.h
  77. 13 163
      engine/source/assets/assetManager.cc
  78. 29 12
      engine/source/assets/assetManager.h
  79. 37 68
      engine/source/assets/assetManager_ScriptBinding.h
  80. 2 2
      engine/source/assets/assetPtr.h
  81. 21 0
      engine/source/audio/AudioAsset.cc
  82. 1 0
      engine/source/audio/AudioAsset.h
  83. 0 2
      engine/source/collection/undo.cc
  84. 0 10
      engine/source/collection/undo.h
  85. 353 358
      engine/source/component/behaviors/behaviorComponent.cpp
  86. 0 7
      engine/source/component/behaviors/behaviorComponent.h
  87. 0 1
      engine/source/component/behaviors/behaviorInstance.cpp
  88. 0 2
      engine/source/component/simComponent.cpp
  89. 20 18
      engine/source/console/compiledEval.cc
  90. 49 3
      engine/source/console/consoleObject.cc
  91. 582 495
      engine/source/console/consoleObject.h
  92. 0 20
      engine/source/graphics/PNGImage.cpp
  93. 0 6
      engine/source/graphics/PNGImage.h
  94. 4 0
      engine/source/graphics/TextureHandle.cc
  95. 4 0
      engine/source/graphics/TextureHandle.h
  96. 30 42
      engine/source/graphics/color.cc
  97. 40 0
      engine/source/graphics/color.h
  98. 383 384
      engine/source/gui/buttons/guiButtonBaseCtrl.cc
  99. 0 10
      engine/source/gui/editor/guiInspector.cc
  100. 0 3
      engine/source/gui/editor/guiInspector.h

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

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

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

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

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

+ 262 - 164
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 )
 
 //-----------------------------------------------------------------------------
@@ -103,17 +107,11 @@ ConsoleSetType( TypeImageAssetPtr )
 
 //------------------------------------------------------------------------------
 
-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 +175,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;
-    }
 }
 
 //------------------------------------------------------------------------------
@@ -264,6 +249,57 @@ void ImageAsset::setImageFile( const char* pImageFile )
 
 //------------------------------------------------------------------------------
 
+void ImageAsset::copyTo(SimObject* object)
+{
+    // Call to parent.
+    Parent::copyTo(object);
+
+    // Cast to asset.
+    ImageAsset* pAsset = static_cast<ImageAsset*>(object);
+
+    // Sanity!
+    AssertFatal(pAsset != NULL, "ImageAsset::copyTo() - Object is not the correct type.");
+
+    // Copy state.
+    pAsset->setImageFile( getImageFile() );
+    pAsset->setForce16Bit( getForce16Bit() );
+    pAsset->setFilterMode( getFilterMode() );
+    pAsset->setExplicitMode( getExplicitMode() );
+    pAsset->setCellRowOrder( getCellRowOrder() );
+    pAsset->setCellOffsetX( getCellCountX() );
+    pAsset->setCellOffsetY( getCellCountY() );
+    pAsset->setCellStrideX( getCellStrideX() );
+    pAsset->setCellStrideY( getCellStrideY() );
+    pAsset->setCellCountX( getCellCountX() );
+    pAsset->setCellCountY( getCellCountY() );
+    pAsset->setCellWidth( getCellWidth() );
+    pAsset->setCellHeight( getCellHeight() );
+
+    // Finish if not in explicit mode.
+    if ( !getExplicitMode() )
+        return;
+
+    // Fetch the explicit cell count.
+    const S32 explicitCellCount = getExplicitCellCount();
+
+    // Finish if no explicit cells exist.
+    if ( explicitCellCount == 0 )
+        return;
+
+    // Copy explicit cells.
+    pAsset->clearExplicitCells();
+    for( S32 index = 0; index < explicitCellCount; ++index )
+    {
+        // Fetch the cell pixel area.
+        const FrameArea::PixelArea& pixelArea = getImageFrameArea( index ).mPixelArea;
+
+        // Add the explicit cell.
+        pAsset->addExplicitCell( pixelArea.mPixelOffset.x, pixelArea.mPixelOffset.y, pixelArea.mPixelWidth, pixelArea.mPixelHeight );
+    }
+}
+
+//------------------------------------------------------------------------------
+
 void ImageAsset::setForce16Bit( const bool force16Bit )
 {
     // Ignore no change,
@@ -865,146 +901,6 @@ void ImageAsset::onTamlPostWrite( void )
 
 //------------------------------------------------------------------------------
 
-void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite);
-
-    // Call parent.
-    Parent::onTamlCustomWrite( customNodes );
-
-    // Finish if not in explicit mode.
-    if ( !mExplicitMode )
-        return;
-
-    // Add cell custom node.
-    TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeName );
-
-    // Iterate explicit frames.
-    for( typeExplicitFrameAreaVector::iterator frameItr = mExplicitFrames.begin(); frameItr != mExplicitFrames.end(); ++frameItr )
-    {
-        // Fetch pixel area.
-        const FrameArea::PixelArea& pixelArea = *frameItr;
-
-        // Add cell alias.
-        TamlCustomNode* pCellNode = pCustomCellNodes->addNode( cellNodeName );
-
-        // Add cell properties.
-        pCellNode->addField( cellOffsetName, pixelArea.mPixelOffset );
-        pCellNode->addField( cellWidthName, pixelArea.mPixelWidth );
-        pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
-
-    // Call parent.
-    Parent::onTamlCustomRead( customNodes );
-
-    // Find cell custom node.
-    const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeName );
-
-    // Finish if we don't have explicit cells.
-    if ( pCustomCellNodes == NULL )
-        return;
-
-    // Set explicit mode.
-    mExplicitMode = true;
-
-    // Fetch children cell nodes.
-    const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
-
-    // Iterate cells.
-    for( TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr )
-    {
-        // Fetch cell node.
-        TamlCustomNode* pCellNode = *cellNodeItr;
-
-        // Fetch node name.
-        StringTableEntry nodeName = pCellNode->getNodeName();
-
-        // Is this a valid alias?
-        if ( nodeName != cellNodeName )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, cellNodeName );
-            continue;
-        }
-
-        Point2I cellOffset(-1, -1);
-        S32 cellWidth = 0;
-        S32 cellHeight = 0;
-
-        // Fetch fields.
-        const TamlCustomFieldVector& fields = pCellNode->getFields();
-
-        // Iterate property fields.
-        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
-        {
-            // Fetch field.
-            const TamlCustomField* pField = *fieldItr;
-
-            // Fetch field name.
-            StringTableEntry fieldName = pField->getFieldName();
-
-            // Check common fields.
-            if ( fieldName == cellOffsetName )
-            {
-                pField->getFieldValue( cellOffset );
-            }
-            else if ( fieldName == cellWidthName )
-            {
-                pField->getFieldValue( cellWidth );
-            }
-            else if ( fieldName == cellHeightName )
-            {
-                pField->getFieldValue( cellHeight );
-            }
-            else
-            {
-                // Unknown name so warn.
-                Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName );
-                continue;
-            }
-        }
-
-        // Is cell offset valid?
-        if ( cellOffset.x < 0 || cellOffset.y < 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell offset of '(%d,%d)' is invalid or was not set.", cellOffset.x, cellOffset.y );
-            continue;
-        }
-
-        // Is cell width valid?
-        if ( cellWidth <= 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell width of '%d' is invalid or was not set.", cellWidth );
-            continue;
-        }
-
-        // Is cell height valid?
-        if ( cellHeight <= 0 )
-        {
-            // No, so warn.
-            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell height of '%d' is invalid or was not set.", cellHeight );
-            continue;
-        }
-
-        // Add explicit frame.
-        FrameArea::PixelArea pixelArea( cellOffset.x, cellOffset.y, cellWidth, cellHeight );
-        mExplicitFrames.push_back( pixelArea );
-    }
-}
-
-//------------------------------------------------------------------------------
-
 void ImageAsset::calculateImage( void )
 {
     // Debug Profiling.
@@ -1278,3 +1174,205 @@ bool ImageAsset::setFilterMode( void* obj, const char* data )
     static_cast<ImageAsset*>(obj)->setFilterMode(getFilterModeEnum(data));
     return false;
 }
+
+//------------------------------------------------------------------------------
+
+void ImageAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(ImageAsset_OnTamlCustomWrite);
+
+    // Call parent.
+    Parent::onTamlCustomWrite( customNodes );
+
+    // Finish if not in explicit mode.
+    if ( !mExplicitMode )
+        return;
+
+    // Add cell custom node.
+    TamlCustomNode* pCustomCellNodes = customNodes.addNode( cellCustomNodeName );
+
+    // Iterate explicit frames.
+    for( typeExplicitFrameAreaVector::iterator frameItr = mExplicitFrames.begin(); frameItr != mExplicitFrames.end(); ++frameItr )
+    {
+        // Fetch pixel area.
+        const FrameArea::PixelArea& pixelArea = *frameItr;
+
+        // Add cell alias.
+        TamlCustomNode* pCellNode = pCustomCellNodes->addNode( cellNodeName );
+
+        // Add cell properties.
+        pCellNode->addField( cellOffsetName, pixelArea.mPixelOffset );
+        pCellNode->addField( cellWidthName, pixelArea.mPixelWidth );
+        pCellNode->addField( cellHeightName, pixelArea.mPixelHeight );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(ImageAsset_OnTamlCustomRead);
+
+    // Call parent.
+    Parent::onTamlCustomRead( customNodes );
+
+    // Find cell custom node.
+    const TamlCustomNode* pCustomCellNodes = customNodes.findNode( cellCustomNodeName );
+
+    // Finish if we don't have explicit cells.
+    if ( pCustomCellNodes == NULL )
+        return;
+
+    // Set explicit mode.
+    mExplicitMode = true;
+
+    // Fetch children cell nodes.
+    const TamlCustomNodeVector& cellNodes = pCustomCellNodes->getChildren();
+
+    // Iterate cells.
+    for( TamlCustomNodeVector::const_iterator cellNodeItr = cellNodes.begin(); cellNodeItr != cellNodes.end(); ++cellNodeItr )
+    {
+        // Fetch cell node.
+        TamlCustomNode* pCellNode = *cellNodeItr;
+
+        // Fetch node name.
+        StringTableEntry nodeName = pCellNode->getNodeName();
+
+        // Is this a valid alias?
+        if ( nodeName != cellNodeName )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom name of '%s'.  Only '%s' is valid.", nodeName, cellNodeName );
+            continue;
+        }
+
+        Point2I cellOffset(-1, -1);
+        S32 cellWidth = 0;
+        S32 cellHeight = 0;
+
+        // Fetch fields.
+        const TamlCustomFieldVector& fields = pCellNode->getFields();
+
+        // Iterate property fields.
+        for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr )
+        {
+            // Fetch field.
+            const TamlCustomField* pField = *fieldItr;
+
+            // Fetch field name.
+            StringTableEntry fieldName = pField->getFieldName();
+
+            // Check common fields.
+            if ( fieldName == cellOffsetName )
+            {
+                pField->getFieldValue( cellOffset );
+            }
+            else if ( fieldName == cellWidthName )
+            {
+                pField->getFieldValue( cellWidth );
+            }
+            else if ( fieldName == cellHeightName )
+            {
+                pField->getFieldValue( cellHeight );
+            }
+            else
+            {
+                // Unknown name so warn.
+                Con::warnf( "ImageAsset::onTamlCustomRead() - Encountered an unknown custom field name of '%s'.", fieldName );
+                continue;
+            }
+        }
+
+        // Is cell offset valid?
+        if ( cellOffset.x < 0 || cellOffset.y < 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell offset of '(%d,%d)' is invalid or was not set.", cellOffset.x, cellOffset.y );
+            continue;
+        }
+
+        // Is cell width valid?
+        if ( cellWidth <= 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell width of '%d' is invalid or was not set.", cellWidth );
+            continue;
+        }
+
+        // Is cell height valid?
+        if ( cellHeight <= 0 )
+        {
+            // No, so warn.
+            Con::warnf( "ImageAsset::onTamlCustomRead() - Cell height of '%d' is invalid or was not set.", cellHeight );
+            continue;
+        }
+
+        // Add explicit frame.
+        FrameArea::PixelArea pixelArea( cellOffset.x, cellOffset.y, cellWidth, cellHeight );
+        mExplicitFrames.push_back( pixelArea );
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ImageAsset::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ImageAsset::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create ImageAsset node element.
+    TiXmlElement* pImageAssetNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), cellCustomNodeName );
+    pImageAssetNodeElement->SetAttribute( "name", buffer );
+    pImageAssetNodeElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pImageAssetNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pImageAssetNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pImageAssetNodeElement->LinkEndChild( pImageAssetNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pImageAssetNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pImageAssetNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pImageAssetNodeComplexTypeElement->LinkEndChild( pImageAssetNodeChoiceElement );
+
+    // Create ImageAsset element.
+    TiXmlElement* pImageAssetElement = new TiXmlElement( "xs:element" );
+    pImageAssetElement->SetAttribute( "name", cellNodeName );
+    pImageAssetElement->SetAttribute( "minOccurs", 0 );
+    pImageAssetElement->SetAttribute( "maxOccurs", 1 );
+    pImageAssetNodeChoiceElement->LinkEndChild( pImageAssetElement );
+
+    // Create complex type Element.
+    TiXmlElement* pImageAssetComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pImageAssetElement->LinkEndChild( pImageAssetComplexTypeElement );
+
+    // Create "Offset" attribute.
+    TiXmlElement* pImageAssetOffset = new TiXmlElement( "xs:attribute" );
+    pImageAssetOffset->SetAttribute( "name", cellOffsetName );
+    pImageAssetOffset->SetAttribute( "type", "Point2I_ConsoleType" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetOffset );
+
+    // Create "Width" attribute.
+    TiXmlElement* pImageAssetWidth = new TiXmlElement( "xs:attribute" );
+    pImageAssetWidth->SetAttribute( "name", cellWidthName );
+    pImageAssetWidth->SetAttribute( "type", "xs:unsignedInt" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetWidth );
+
+    // Create "Height" attribute.
+    TiXmlElement* pImageAssetHeight = new TiXmlElement( "xs:attribute" );
+    pImageAssetHeight->SetAttribute( "name", cellHeightName );
+    pImageAssetHeight->SetAttribute( "type", "xs:unsignedInt" );
+    pImageAssetComplexTypeElement->LinkEndChild( pImageAssetHeight );
+}
+
+//------------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(ImageAsset, WriteCustomTamlSchema);

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

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

+ 17 - 4
engine/source/2d/assets/ParticleAsset.cc

@@ -119,10 +119,6 @@ ConsoleSetType( TypeParticleAssetPtr )
     Con::warnf( "(TypeParticleAssetPtr) - Cannot set multiple args to a single asset." );
 }
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(ParticleAsset);
-
 //------------------------------------------------------------------------------
 
 ParticleAsset::ParticleAsset() :
@@ -493,3 +489,20 @@ void ParticleAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Read the fields.
     mParticleFields.onTamlCustomRead( customNodes );
 }
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAsset::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAsset::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Write the particle asset fields.
+    ParticleAsset particleAsset;
+    particleAsset.getParticleFields().WriteCustomTamlSchema( pClassRep, pParentElement );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_CHILDREN_SCHEMA(ParticleAsset, WriteCustomTamlSchema);

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

@@ -45,6 +45,7 @@ class ParticleAsset : public AssetBase, public TamlChildren
 {
 private:
     typedef AssetBase  Parent;
+    typedef ParticleAssetEmitter Children;
     typedef Vector<ParticleAssetEmitter*> typeEmitterVector;
 
 public:

+ 18 - 5
engine/source/2d/assets/ParticleAssetEmitter.cc

@@ -128,10 +128,6 @@ const char* ParticleAssetEmitter::getOrientationTypeDescription( const ParticleO
 
 //------------------------------------------------------------------------------
 
-IMPLEMENT_CONOBJECT(ParticleAssetEmitter);
-
-//------------------------------------------------------------------------------
-
 ParticleAssetEmitter::ParticleAssetEmitter() :
                             mEmitterName( StringTable->EmptyString ),
                             mOwner( NULL ),
@@ -295,7 +291,7 @@ void ParticleAssetEmitter::copyTo(SimObject* object)
    pParticleAssetEmitter->setAlphaTest( getAlphaTest() );
 
    pParticleAssetEmitter->setRandomImageFrame( getRandomImageFrame() );
-   if ( pParticleAssetEmitter->isStaticMode() )
+   if ( pParticleAssetEmitter->isStaticFrameProvider() )
    {
        pParticleAssetEmitter->setImage( getImage() );
        pParticleAssetEmitter->setImageFrame( getImageFrame() );
@@ -509,3 +505,20 @@ void ParticleAssetEmitter::onTamlCustomRead( const TamlCustomNodes& customNodes
     mParticleFields.onTamlCustomRead( customNodes );
 }
 
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetEmitter::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetEmitter::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Write the particle asset emitter fields.
+    ParticleAssetEmitter particleAssetEmitter;
+    particleAssetEmitter.getParticleFields().WriteCustomTamlSchema( pClassRep, pParentElement );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(ParticleAssetEmitter, WriteCustomTamlSchema);

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

+ 103 - 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;
-    }
 }
 
 //-----------------------------------------------------------------------------
@@ -703,3 +682,95 @@ void ParticleAssetField::onTamlCustomRead( const TamlCustomNode* pCustomNode )
     // Set the data keys.
     mDataKeys = keys;
 }
+
+//-----------------------------------------------------------------------------
+
+void ParticleAssetField::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetField::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetField::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create Field element.
+    TiXmlElement* pFieldElement = new TiXmlElement( "xs:element" );
+    pFieldElement->SetAttribute( "name", getFieldName() );
+    pFieldElement->SetAttribute( "minOccurs", 0 );
+    pFieldElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pFieldElement );
+
+    // Create complex type Element.
+    TiXmlElement* pFieldComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pFieldElement->LinkEndChild( pFieldComplexTypeElement );
+
+    // Create choice element.
+    TiXmlElement* pFieldChoiceElement = new TiXmlElement( "xs:choice" );
+    pFieldChoiceElement->SetAttribute( "minOccurs", 0 );
+    pFieldChoiceElement->SetAttribute( "maxOccurs", 1 );
+    pFieldComplexTypeElement->LinkEndChild( pFieldChoiceElement );
+
+    // Create key element.
+    TiXmlElement* pKeyElement = new TiXmlElement( "xs:element" );
+    pKeyElement->SetAttribute( "name", particleAssetFieldDataKeyName );
+    pKeyElement->SetAttribute( "minOccurs", 0 );
+    pKeyElement->SetAttribute( "maxOccurs", "unbounded" );
+    pFieldChoiceElement->LinkEndChild( pKeyElement );
+
+    // Create complex type Element.
+    TiXmlElement* pKeyComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pKeyElement->LinkEndChild( pKeyComplexTypeElement );
+
+    // Create "Time" attribute.
+    TiXmlElement* pKeyTimeAttribute = new TiXmlElement( "xs:attribute" );
+    pKeyTimeAttribute->SetAttribute( "name", particleAssetFieldDataKeyTimeName );
+    pKeyComplexTypeElement->LinkEndChild( pKeyTimeAttribute );
+    TiXmlElement* pKeyTimeSimpleType = new TiXmlElement( "xs:simpleType" );
+    pKeyTimeAttribute->LinkEndChild( pKeyTimeSimpleType );
+    TiXmlElement* pKeyTimeRestriction = new TiXmlElement( "xs:restriction" );
+    pKeyTimeRestriction->SetAttribute( "base", "xs:float" );
+    pKeyTimeSimpleType->LinkEndChild( pKeyTimeRestriction );
+    TiXmlElement* pKeyTimeMinRestriction = new TiXmlElement( "xs:minInclusive" );
+    pKeyTimeMinRestriction->SetAttribute( "value", "0" );
+    pKeyTimeRestriction->LinkEndChild( pKeyTimeMinRestriction );
+
+    // Create "Value" attribute.
+    TiXmlElement* pKeyValueAttribute = new TiXmlElement( "xs:attribute" );
+    pKeyValueAttribute->SetAttribute( "name", particleAssetFieldDataKeyValueName );
+    pKeyValueAttribute->SetAttribute( "type", "xs:float" );
+    pKeyComplexTypeElement->LinkEndChild( pKeyValueAttribute );
+
+    // Create "Min Value" attribute.
+    TiXmlElement* pFieldMinValue = new TiXmlElement( "xs:attribute" );
+    pFieldMinValue->SetAttribute( "name", particleAssetFieldMinValueName );
+    pFieldMinValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMinValue );
+
+    // Create "Max Value" attribute.
+    TiXmlElement* pFieldMaxValue = new TiXmlElement( "xs:attribute" );
+    pFieldMaxValue->SetAttribute( "name", particleAssetFieldMaxValueName );
+    pFieldMaxValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMaxValue );
+
+    // Create "Max Time" attribute.
+    TiXmlElement* pFieldMaxTime = new TiXmlElement( "xs:attribute" );
+    pFieldMaxTime->SetAttribute( "name", particleAssetFieldMaxTimeName );
+    pFieldMaxTime->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldMaxTime );
+
+    // Create "Default Value" attribute.
+    TiXmlElement* pFieldDefaultValue = new TiXmlElement( "xs:attribute" );
+    pFieldDefaultValue->SetAttribute( "name", particleAssetFieldDefaultValueName );
+    pFieldDefaultValue->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldDefaultValue );
+
+    // Create "Value Scale" attribute.
+    TiXmlElement* pFieldValueScale = new TiXmlElement( "xs:attribute" );
+    pFieldValueScale->SetAttribute( "name", particleAssetFieldValueScaleName );
+    pFieldValueScale->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldValueScale );
+
+    // Create "Repeat Time" attribute.
+    TiXmlElement* pFieldRepeatTime = new TiXmlElement( "xs:attribute" );
+    pFieldRepeatTime->SetAttribute( "name", particleAssetFieldRepeatTimeName );
+    pFieldRepeatTime->SetAttribute( "type", "xs:float" );
+    pFieldComplexTypeElement->LinkEndChild( pFieldRepeatTime );
+}

+ 2 - 0
engine/source/2d/assets/ParticleAssetField.h

@@ -111,6 +111,8 @@ public:
 
     void onTamlCustomWrite( TamlCustomNode* pCustomNode  );
     void onTamlCustomRead( const TamlCustomNode* pCustomNode );
+
+    void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
 };
 
 //-----------------------------------------------------------------------------

+ 37 - 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");
 }
 
 //-----------------------------------------------------------------------------
@@ -483,5 +482,40 @@ void ParticleAssetFieldCollection::onTamlCustomRead( const TamlCustomNodes& cust
     }
 }
 
+//-----------------------------------------------------------------------------
+
+void ParticleAssetFieldCollection::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement ) const
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "ParticleAssetFieldCollection::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "ParticleAssetFieldCollection::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create Fields node element.
+    TiXmlElement* pFieldsNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), particleAssetFieldNodeName );
+    pFieldsNodeElement->SetAttribute( "name", buffer );
+    pFieldsNodeElement->SetAttribute( "minOccurs", 0 );
+    pFieldsNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pFieldsNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pFieldsNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pFieldsNodeElement->LinkEndChild( pFieldsNodeComplexTypeElement );
+    
+    // Create choice element.
+    TiXmlElement* pFieldsNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pFieldsNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pFieldsNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pFieldsNodeComplexTypeElement->LinkEndChild( pFieldsNodeChoiceElement );
+
+    // Iterate the fields.
+    for( typeFieldHash::const_iterator fieldItr = mFields.begin(); fieldItr != mFields.end(); ++fieldItr )
+    {
+        // Write schema for the field.
+        fieldItr->value->WriteCustomTamlSchema( pClassRep, pFieldsNodeChoiceElement );
+    }
+}
 
 

+ 2 - 0
engine/source/2d/assets/ParticleAssetFieldCollection.h

@@ -83,6 +83,8 @@ public:
 
     void onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+    void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement ) const;
 };
 
 #endif // ParticleAssetFieldCollection

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

@@ -107,7 +107,7 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
 
     // Query for candidate objects.
-    pWorldQuery->anyQueryArea( mFluidArea ); 
+    pWorldQuery->anyQueryAABB( mFluidArea ); 
 
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
@@ -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 );

+ 30 - 9
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,13 +103,16 @@ 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 ); 
+    pWorldQuery->anyQueryAABB( aabb ); 
 
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
@@ -123,28 +134,38 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     const F32 linearDrag = mClampF( mLinearDrag, 0.0f, 1.0f ) * elapsedTime;
     const F32 angularDrag = mClampF( mAngularDrag, 0.0f, 1.0f ) * elapsedTime;
 
+    // Fetch the tracked object.
+    const SceneObject* pTrackedObject = mTrackedObject;
+
     // Iterate the results.
     for ( U32 n = 0; n < resultCount; n++ )
     {
         // Fetch the scene object.
         SceneObject* pSceneObject = queryResults[n].mpSceneObject;
 
+        // Ignore if it's the tracked object.
+        if ( pSceneObject == pTrackedObject )
+            continue;
+
         // Ignore if it's a static body.
         if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
 
-        // Calculate the force distance to the controllers position.
-        Vector2 distanceForce = mPosition - pSceneObject->getPosition();
+        // Calculate the force distance to the controllers current position.
+        Vector2 distanceForce = currentPosition - pSceneObject->getPosition();
+
+        // Fetch distance squared.
+        const F32 distanceSqr = distanceForce.LengthSquared();
 
-        // Skip if the position is outside the radius.
-        if ( distanceForce.LengthSquared() > radiusSqr )
+        // Skip if the position is outside the radius or is centered on the controller.
+        if ( distanceSqr > radiusSqr || distanceSqr < FLT_EPSILON )
             continue;
 
         // Non-Linear force?
         if ( mNonLinear )
         {
             // Yes, so use an approximation of the inverse-square law.
-            distanceForce *= (1.0f / distanceForce.LengthSquared()) * forceSqr;
+            distanceForce *= (1.0f / distanceSqr) * forceSqr;
         }
         else
         {
@@ -191,5 +212,5 @@ void PointForceController::renderOverlay( Scene* pScene, const SceneRenderState*
     Parent::renderOverlay( pScene, pSceneRenderState, pBatchRenderer );
 
     // Draw force radius.
-    pScene->mDebugDraw.DrawCircle( mPosition, mRadius, ColorF(1.0f, 1.0f, 0.0f ) );
+    pScene->mDebugDraw.DrawCircle( getCurrentPosition(), mRadius, ColorF(1.0f, 1.0f, 0.0f ) );
 }

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

@@ -50,11 +50,14 @@ private:
     /// Whether to apply the force non-linearly (using the inverse square law) or linearly.
     bool mNonLinear;
 
-	/// Linear drag co-efficient.
-	F32 mLinearDrag;
+    /// Linear drag co-efficient.
+    F32 mLinearDrag;
 
-	/// Linear drag co-efficient.
-	F32 mAngularDrag;
+    /// Linear drag co-efficient.
+    F32 mAngularDrag;
+
+    /// Tracked object.
+    SimObjectPtr<SceneObject> mTrackedObject;
 
 public:
     PointForceController();
@@ -75,6 +78,16 @@ public:
     inline F32 getLinearDrag( void ) const { return mLinearDrag; }
     inline void setAngularDrag( const F32 angularDrag ) { mAngularDrag = angularDrag; }
     inline F32 getAngularDrag( void ) const { return mAngularDrag; }
+    void setTrackedObject( SceneObject* pSceneObject );
+    inline SceneObject* getTrackedObject( void ) { return mTrackedObject; }
+    inline Vector2 getCurrentPosition( void )
+    {
+        // Fetch the tracked object.
+        SceneObject* pSceneObject = mTrackedObject;
+
+        // Return the controller position if no tracked object else the tracked object position plus a tracked object local-space position.
+        return pSceneObject == NULL ? mPosition : b2Mul( pSceneObject->getTransform(), mPosition);
+    }
 
     /// Integration.
     virtual void integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );

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

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

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

@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "2d/core/imageFrameProvider.h"
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProvider::ImageFrameProvider()
+{
+    // Register for animation asset refresh notifications.
+    mAnimationAsset.registerRefreshNotify( this );
+
+    // Allocate assets.
+    ImageFrameProviderCore::allocateAssets( &mImageAsset, &mAnimationAsset );
+}
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProvider::~ImageFrameProvider()
+{
+    // Deallocate assets.
+    ImageFrameProviderCore::deallocateAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProvider::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
+{
+    // Call parent.
+    ImageFrameProviderCore::onAssetRefreshed( pAssetPtrBase );
+}
+

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

@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _IMAGE_FRAME_PROVIDER_H
+#define _IMAGE_FRAME_PROVIDER_H
+
+#ifndef _IMAGE_FRAME_PROVIDER_CORE_H
+#include "2d/core/imageFrameProviderCore.h"
+#endif
+
+///-----------------------------------------------------------------------------
+
+class ImageFrameProvider : public ImageFrameProviderCore
+{
+protected:
+    AssetPtr<ImageAsset>                    mImageAsset;
+    AssetPtr<AnimationAsset>                mAnimationAsset;
+
+public:
+    ImageFrameProvider();
+    virtual ~ImageFrameProvider();
+
+protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+};
+
+
+#endif // _IMAGE_FRAME_PROVIDER_H

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

@@ -0,0 +1,586 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "2d/core/imageFrameProviderCore.h"
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+#ifndef _DGL_H_
+#include "graphics/dgl.h"
+#endif
+
+#ifndef _CONSOLETYPES_H_
+#include "console/consoleTypes.h"
+#endif
+
+#ifndef _STRINGBUFFER_H_
+#include "string/stringBuffer.h"
+#endif
+
+#ifndef _RENDER_PROXY_H_
+#include "2d/core/renderProxy.h"
+#endif
+
+// Debug Profiling.
+#include "debug/profiler.h"
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProviderCore::ImageFrameProviderCore() : mpImageAsset(NULL), mpAnimationAsset(NULL)
+{
+}
+
+//-----------------------------------------------------------------------------
+
+ImageFrameProviderCore::~ImageFrameProviderCore()
+{
+    // Reset the state.
+    resetState();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::allocateAssets( AssetPtr<ImageAsset>* pImageAssetPtr, AssetPtr<AnimationAsset>* pAnimationAssetPtr )
+{
+    // Sanity!
+    AssertFatal( mpImageAsset == NULL && mpAnimationAsset == NULL, "ImageFrameProviderCore: Assets already allocated." );
+    AssertFatal( pImageAssetPtr != NULL, "ImageFrameProviderCore: Image-Asset pointer cannot be NULL." );
+    AssertFatal( pAnimationAssetPtr != NULL, "ImageFrameProviderCore: Animation-Asset pointer cannot be NULL." );
+
+    // Reset the state.
+    resetState();
+
+    // Set asset pointers.
+    mpImageAsset = pImageAssetPtr;
+    mpAnimationAsset = pAnimationAssetPtr;
+
+    // Set static/animation frame provider.
+    mStaticProvider = mpImageAsset->notNull();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::resetState( void )
+{
+    mSelfTick = false;
+
+    mCurrentFrameIndex = 0;
+    mLastFrameIndex = 0;
+    mMaxFrameIndex = 0;
+    mCurrentTime = 0.0f;
+    mPausedTime = 0.0f;
+    mAnimationTimeScale = 1.0f;
+    mTotalIntegrationTime = 0.0f;
+    mFrameIntegrationTime = 0.0f;
+    mAnimationPaused = false;
+    mAnimationFinished = true;
+
+    clearAssets();
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::copyTo( ImageFrameProviderCore* pImageFrameProviderCore ) const
+{
+    // Sanity!
+    AssertFatal(pImageFrameProviderCore != NULL, "ImageFrameProviderCore::copyTo - Copy object cannot be NULL.");
+
+    // Set self ticking.
+    pImageFrameProviderCore->mSelfTick = mSelfTick;
+
+    // Static provider?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so use the image/frame if we have an asset.
+        if ( mpImageAsset->notNull() )
+            pImageFrameProviderCore->setImage( getImage(), getImageFrame() );
+    }
+    else if ( mpAnimationAsset->notNull() )
+    {
+        // No, so use current animation if we have an asset.
+        if ( mpAnimationAsset->notNull() )
+            pImageFrameProviderCore->setAnimation(getAnimation() );
+    }
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::update( const F32 elapsedTime )
+{
+    // Static provider?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so turn-off tick processing.
+        setProcessTicks( false );
+
+        return false;
+    }
+
+    // Finish if the animation has finished.
+    if ( isAnimationFinished() )
+        return false;
+
+    // Finish if animation is paused.
+    if ( isAnimationPaused() )
+        return true;
+
+    // Update the animation.
+    updateAnimation( Tickable::smTickSec );
+
+    // Finish if the animation has NOT finished.
+    if ( !isAnimationFinished() )
+        return false;
+
+    // Turn-off tick processing.
+    setProcessTicks( false );
+
+    // Perform callback.
+    onAnimationEnd();
+
+    // Flag animation as just finished.
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::processTick( void )
+{
+    // Update using tick period.
+    update( Tickable::smTickSec );
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::validRender( void ) const
+{
+    // Are we in static mode?
+    if ( isStaticFrameProvider() )
+    {
+        // Yes, so we must have an image asset and the frame must be in bounds.
+        return mpImageAsset->notNull() && ( getImageFrame() < (*mpImageAsset)->getFrameCount() );
+    }
+
+    // No, so if the animation must be valid.
+    return isAnimationValid();
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::render(
+    const bool flipX,
+    const bool flipY,
+    const Vector2& vertexPos0,
+    const Vector2& vertexPos1,
+    const Vector2& vertexPos2,
+    const Vector2& vertexPos3,
+    BatchRender* pBatchRenderer ) const
+{
+    // Finish if we can't render.
+    if ( !validRender() )
+        return;
+
+    // Fetch texel area.
+    ImageAsset::FrameArea::TexelArea texelArea = getProviderImageFrameArea().mTexelArea;
+
+    // Flip texture coordinates appropriately.
+    texelArea.setFlip( flipX, flipY );
+
+    // Fetch lower/upper texture coordinates.
+    const Vector2& texLower = texelArea.mTexelLower;
+    const Vector2& texUpper = texelArea.mTexelUpper;
+    
+    // Submit batched quad.
+    pBatchRenderer->SubmitQuad(
+        vertexPos0,
+        vertexPos1,
+        vertexPos2,
+        vertexPos3,
+        Vector2( texLower.x, texUpper.y ),
+        Vector2( texUpper.x, texUpper.y ),
+        Vector2( texUpper.x, texLower.y ),
+        Vector2( texLower.x, texLower.y ),
+        getProviderTexture() );
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
+{
+    // Validate frame provider.
+    if ( ( isStaticFrameProvider() && (mpImageAsset->isNull() || mImageFrame >= (*mpImageAsset)->getFrameCount()) ) ||
+        ( !isStaticFrameProvider() && (mpAnimationAsset->isNull() ) ) )
+    {
+        // Invalid so fetch the 'cannot render' proxy.
+        RenderProxy* pNoImageRenderProxy = Sim::findObject<RenderProxy>( CANNOT_RENDER_PROXY_NAME );
+
+        // Check that the render proxy can render.
+        if ( pNoImageRenderProxy != NULL && pNoImageRenderProxy->validRender() )
+        {
+            // Render using render-proxy.
+            pNoImageRenderProxy->renderGui( owner, offset, updateRect );
+        }
+
+        // Update control.
+        owner.setUpdate();
+    }
+    else
+    {
+        // Valid, so calculate source region.
+        const ImageAsset::FrameArea& frameArea = getProviderImageFrameArea();
+        RectI sourceRegion( frameArea.mPixelArea.mPixelOffset, Point2I(frameArea.mPixelArea.mPixelWidth, frameArea.mPixelArea.mPixelHeight) );
+
+        // Calculate destination region.
+        RectI destinationRegion(offset, owner.mBounds.extent);
+
+        // Render image.
+		dglSetBitmapModulation( owner.mProfile->mFillColor );
+        dglDrawBitmapStretchSR( getProviderTexture(), destinationRegion, sourceRegion );
+        dglClearBitmapModulation();
+    }
+
+    // Render child controls.
+    owner.renderChildControls(offset, updateRect);
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setImage( const char* pImageAssetId, const U32 frame )
+{
+    // Finish if invalid image asset.
+    if ( pImageAssetId == NULL )
+        return false;
+
+    // Set asset.
+    mpImageAsset->setAssetId( pImageAssetId );
+
+    // Set the image frame if the image asset was set.
+    if ( mpImageAsset->notNull() )
+        setImageFrame( frame );
+
+    // Set Frame.
+    mImageFrame = frame;
+
+    // Set as static provider.
+    mStaticProvider = true;
+
+    // Turn-off tick processing.
+    setProcessTicks( false );
+
+    // Return Okay.
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setImageFrame( const U32 frame )
+{
+    // Check Existing Image.
+    if ( mpImageAsset->isNull() )
+    {
+        // Warn.
+        Con::warnf("ImageFrameProviderCore::setImageFrame() - Cannot set Frame without existing asset Id.");
+
+        // Return Here.
+        return false;
+    }
+
+    // Check Frame Validity.
+    if ( frame >= (*mpImageAsset)->getFrameCount() )
+    {
+        // Warn.
+        Con::warnf( "ImageFrameProviderCore::setImageFrame() - Invalid Frame #%d for asset Id '%s'.", frame, mpImageAsset->getAssetId() );
+        // Return Here.
+        return false;
+    }
+
+    // Set Frame.
+    mImageFrame = frame;
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+const U32 ImageFrameProviderCore::getCurrentAnimationFrame( void ) const
+{
+    // Sanity!
+    AssertFatal( mpAnimationAsset->notNull(), "Animation controller requested current image frame but no animation asset assigned." );
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Sanity!
+    AssertFatal( mCurrentFrameIndex < validatedFrames.size(), "Animation controller requested the current frame but it is out of bounds of the validated frames." );
+
+    return validatedFrames[mCurrentFrameIndex];
+};
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::isAnimationValid( void ) const
+{
+    // Not valid if no animation asset.
+    if ( mpAnimationAsset->isNull() )
+        return false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Not valid if current frame index is out of bounds of the validated frames.
+    if ( mCurrentFrameIndex >= validatedFrames.size() )
+        return false;
+
+    // Fetch image asset.
+    const AssetPtr<ImageAsset>& imageAsset = (*mpAnimationAsset)->getImage();
+
+    // Not valid if no image asset.
+    if ( imageAsset.isNull() )
+        return false;
+
+    // Fetch current frame.
+    const U32 currentFrame = getCurrentAnimationFrame();
+
+    // Not valid if current frame is out of bounds of the image asset.
+    if ( currentFrame >= imageAsset->getFrameCount() )
+        return false;
+
+    // Valid.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::setAnimation( const char* pAnimationAssetId )
+{
+    // Set as dynamic provider.
+    mStaticProvider = false;
+
+    // Ensure animation is un-paused.
+    mAnimationPaused = false;
+
+    // Reset static asset.
+    mpImageAsset->clear();
+
+    // Fetch animation asset.
+    mpAnimationAsset->setAssetId( pAnimationAssetId );
+
+    // Finish if we didn't get an animation.
+    if ( mpAnimationAsset->isNull() )
+        return false;
+
+    // Play Animation.
+    if ( !playAnimation( *mpAnimationAsset ) )
+        return false;
+
+    // Turn-on tick processing.
+    setProcessTicks( true );
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::playAnimation( const AssetPtr<AnimationAsset>& animationAsset )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AnimationController_PlayAnimation);
+
+    // Stop animation.
+    stopAnimation();
+
+    // Finish if no animation asset.
+    if ( animationAsset.isNull() )
+        return true;
+
+    // Set as dynamic provider.
+    mStaticProvider = false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = animationAsset->getValidatedAnimationFrames();
+
+    // Check we've got some frames.
+    if ( validatedFrames.size() == 0 )
+    {
+        Con::warnf( "ImageFrameProviderCore::playAnimation() - Cannot play AnimationAsset '%s' - Animation has no validated frames!", mpAnimationAsset->getAssetId() );
+        return false;
+    }
+
+    // Set animation asset.
+    mpAnimationAsset->setAssetId( animationAsset.getAssetId() );
+
+    // Set Maximum Frame Index.
+    mMaxFrameIndex = validatedFrames.size()-1;
+
+    // Calculate Total Integration Time.
+    mTotalIntegrationTime = (*mpAnimationAsset)->getAnimationTime();
+
+    // Calculate Frame Integration Time.
+    mFrameIntegrationTime = mTotalIntegrationTime / validatedFrames.size();
+
+    // No, so random Start?
+    if ( (*mpAnimationAsset)->getRandomStart() )
+    {
+        // Yes, so calculate start time.
+        mCurrentTime = CoreMath::mGetRandomF(0.0f, mTotalIntegrationTime*0.999f);
+    }
+    else
+    {
+        // No, so set first frame.
+        mCurrentTime = 0.0f;
+    }
+
+    // Reset animation finished flag.
+    mAnimationFinished = false;
+
+    // Do an initial animation update.
+    updateAnimation(0.0f);
+
+    // Return Okay.
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool ImageFrameProviderCore::updateAnimation( const F32 elapsedTime )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(AnimationController_UpdateAnimation);
+
+    // Finish if animation asset is not valid.
+    if ( mpAnimationAsset->isNull() || (*mpAnimationAsset)->getImage().isNull() )
+        return false;
+
+    // Finish if animation has finished.
+    if ( mAnimationFinished )
+        return false;
+
+    // Fetch validated frames.
+    const Vector<S32>& validatedFrames = (*mpAnimationAsset)->getValidatedAnimationFrames();
+
+    // Finish if there are no validated frames.
+    if ( validatedFrames.size() == 0 )
+        return false;
+
+    // Calculate scaled time.
+    const F32 scaledTime = elapsedTime * mAnimationTimeScale;
+
+    // Update Current Time.
+    mCurrentTime += scaledTime;
+
+    // Check if the animation has finished.
+    if ( !(*mpAnimationAsset)->getAnimationCycle() && mGreaterThanOrEqual(mCurrentTime, mTotalIntegrationTime) )
+    {
+        // Animation has finished.
+        mAnimationFinished = true;
+
+        // Fix Animation at end of frames.
+        mCurrentTime = mTotalIntegrationTime - (mFrameIntegrationTime * 0.5f);
+    }
+
+    // Update Current Mod Time.
+    mCurrentModTime = mFmod( mCurrentTime, mTotalIntegrationTime );
+
+    // Calculate Current Frame.
+    mCurrentFrameIndex = (S32)(mCurrentModTime / mFrameIntegrationTime);
+
+    // Fetch frame.
+    S32 frame = validatedFrames[mCurrentFrameIndex];
+
+    // Fetch image frame count.
+    const S32 imageFrameCount = (*mpAnimationAsset)->getImage()->getFrameCount();
+
+    // Clamp frames.
+    if ( frame < 0 )
+        frame = 0;
+    else if (frame >= imageFrameCount )
+        frame = imageFrameCount-1;
+
+    // Calculate if frame has changed.
+    bool frameChanged = (mCurrentFrameIndex != mLastFrameIndex);
+
+    // Reset Last Frame.
+    mLastFrameIndex = mCurrentFrameIndex;
+
+    // Return Frame-Changed Flag.
+    return frameChanged;
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::setAnimationFrame( const U32 frameIndex )
+{
+    // Do we have a valid animation asset?
+    if ( mpAnimationAsset->isNull() )
+    {
+        // No, so warn.
+        Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Cannot set frame; animation is finished or is invalid!");
+        return;
+    }
+
+    // Validate Frame Index?
+    if ( (S32)frameIndex < 0 || frameIndex > mMaxFrameIndex )
+    {
+        // No, so warn.
+        Con::warnf("ImageFrameProviderCore::setAnimationFrame() - Animation Frame-Index Invalid (frame#%d of %d in %s)", frameIndex, mMaxFrameIndex, mpAnimationAsset->getAssetId() );
+        // Finish here.
+        return;
+    }
+
+    // Calculate current time.
+    mCurrentTime = frameIndex*mFrameIntegrationTime;
+
+    // Do an immediate animation update.
+    updateAnimation(0.0f);
+}
+
+//------------------------------------------------------------------------------
+
+void ImageFrameProviderCore::clearAssets( void )
+{
+    // Clear assets.
+    if ( mpAnimationAsset != NULL )
+        mpAnimationAsset->clear();
+
+    if ( mpImageAsset != NULL )
+        mpImageAsset->clear();
+
+    // Reset remaining state.
+    mImageFrame = 0;
+    mStaticProvider = true;
+    setProcessTicks( false );
+}
+
+//-----------------------------------------------------------------------------
+
+void ImageFrameProviderCore::onAssetRefreshed( AssetPtrBase* pAssetPtrBase )
+{
+    // Don't perform any action if the animation is not already playing.
+    if ( mAnimationFinished )
+        return;
+
+    // Attempt to restart the animation.
+    playAnimation( *mpAnimationAsset );
+}

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

@@ -0,0 +1,153 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _IMAGE_FRAME_PROVIDER_CORE_H
+#define _IMAGE_FRAME_PROVIDER_CORE_H
+
+#ifndef _IMAGE_ASSET_H_
+#include "2d/assets/ImageAsset.h"
+#endif
+
+#ifndef _ANIMATION_ASSET_H_
+#include "2d/assets/AnimationAsset.h"
+#endif
+
+#ifndef _TICKABLE_H_
+#include "platform/Tickable.h"
+#endif
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+#ifndef _BATCH_RENDER_H_
+#include "BatchRender.h"
+#endif
+
+#ifndef _FACTORY_CACHE_H_
+#include "memory/factoryCache.h"
+#endif
+
+#ifndef _GUICONTROL_H_
+#include "gui/guiControl.h"
+#endif
+
+///-----------------------------------------------------------------------------
+
+class ImageFrameProviderCore :
+    public virtual Tickable,
+    public IFactoryObjectReset,
+    protected AssetPtrCallback
+{
+protected:
+    bool                                    mSelfTick;
+
+    bool                                    mStaticProvider;
+
+    U32                                     mImageFrame;
+    AssetPtr<ImageAsset>*                   mpImageAsset;
+    AssetPtr<AnimationAsset>*               mpAnimationAsset;
+
+    S32                                     mLastFrameIndex;
+    S32                                     mCurrentFrameIndex;
+    U32                                     mMaxFrameIndex;
+    F32                                     mCurrentTime;
+    F32                                     mPausedTime;
+    F32                                     mCurrentModTime;
+    F32                                     mAnimationTimeScale;
+    F32                                     mTotalIntegrationTime;
+    F32                                     mFrameIntegrationTime;
+    bool                                    mAnimationPaused;
+    bool                                    mAnimationFinished;
+
+public:
+    ImageFrameProviderCore();
+    virtual ~ImageFrameProviderCore();
+
+    void allocateAssets( AssetPtr<ImageAsset>* pImageAssetPtr, AssetPtr<AnimationAsset>* pAnimationAssetPtr );
+    inline void deallocateAssets( void ) { mpImageAsset = NULL; mpAnimationAsset = NULL; }
+
+    virtual void copyTo( ImageFrameProviderCore* pImageFrameProviderCore ) const;
+
+    /// Integration.
+    virtual bool update( const F32 elapsedTime );
+    virtual void processTick();
+    virtual void interpolateTick( F32 delta ) {};
+    virtual void advanceTime( F32 timeDelta ) {};
+    virtual void setProcessTicks( bool tick  ) { Tickable::setProcessTicks( mSelfTick ? tick : false ); }
+    bool updateAnimation( const F32 elapsedTime );
+
+    virtual bool validRender( void ) const;
+
+    virtual void render(
+        const bool flipX,
+        const bool flipY,
+        const Vector2& vertexPos0,
+        const Vector2& vertexPos1,
+        const Vector2& vertexPos2,
+        const Vector2& vertexPos3,
+        BatchRender* pBatchRenderer ) const;
+
+    void renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const;
+
+    /// Static-Image Frame.
+    inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
+    virtual bool setImage( const char* pImageAssetId, const U32 frame );
+    inline StringTableEntry getImage( void ) const{ return mpImageAsset->getAssetId(); }
+    virtual bool setImageFrame( const U32 frame );
+    inline U32 getImageFrame( void ) const { return mImageFrame; }
+
+    /// Animated-Image Frame.
+    virtual bool setAnimation( const char* pAnimationAssetId );
+    inline StringTableEntry getAnimation( void ) const { return mpAnimationAsset->getAssetId(); }
+    void setAnimationFrame( const U32 frameIndex );
+    void setAnimationTimeScale( const F32 scale ) { mAnimationTimeScale = scale; }
+    inline F32 getAnimationTimeScale( void ) const { return mAnimationTimeScale; }
+    bool playAnimation( const AssetPtr<AnimationAsset>& animationAsset);
+    inline void pauseAnimation( const bool animationPaused ) { mAnimationPaused = animationPaused; }
+    inline void stopAnimation( void ) { mAnimationFinished = true; mAnimationPaused = false; }
+    inline void resetAnimationTime( void ) { mCurrentTime = 0.0f; }
+    inline bool isAnimationPaused( void ) const { return mAnimationPaused; }
+    inline bool isAnimationFinished( void ) const { return mAnimationFinished; };
+    bool isAnimationValid( void ) const;
+
+    /// Frame provision.
+    inline bool isStaticFrameProvider( void ) const { return mStaticProvider; }
+    inline TextureHandle& getProviderTexture( void ) const { return !validRender() ? BadTextureHandle : isStaticFrameProvider() ? (*mpImageAsset)->getImageTexture() : (*mpAnimationAsset)->getImage()->getImageTexture(); };
+    inline const ImageAsset::FrameArea& getProviderImageFrameArea( void ) const  { return !validRender() ? BadFrameArea : isStaticFrameProvider() ? (*mpImageAsset)->getImageFrameArea(mImageFrame) : (*mpAnimationAsset)->getImage()->getImageFrameArea(getCurrentAnimationFrame()); };
+
+    inline const AnimationAsset* getCurrentAnimation( void ) const { return mpAnimationAsset->notNull() ? *mpAnimationAsset : NULL; };
+    inline const StringTableEntry getCurrentAnimationAssetId( void ) const { return mpAnimationAsset->getAssetId(); };
+    const U32 getCurrentAnimationFrame( void ) const;
+    inline const F32 getCurrentAnimationTime( void ) const { return mCurrentTime; };
+
+    void clearAssets( void );
+
+    virtual void resetState( void );
+
+protected:
+    virtual void onAnimationEnd( void ) {}
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+};
+
+
+#endif // _IMAGE_FRAME_PROVIDER_CORE_H

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 157 - 74
engine/source/2d/core/SpriteBatch.cc

@@ -34,6 +34,10 @@
 
 //------------------------------------------------------------------------------
 
+static StringTableEntry spritesNodeName = StringTable->insert( "Sprites" );
+
+//------------------------------------------------------------------------------
+
 SpriteBatch::SpriteBatch() :
     mMasterBatchId( 0 ),
     mSelectedSprite( NULL ),
@@ -52,14 +56,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();
@@ -91,7 +109,7 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
 
         // Perform query.
-        pSpriteBatchQuery->renderQueryArea( localAABB );
+        pSpriteBatchQuery->queryArea( localAABB, false );
 
         // Debug Profiling.
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
@@ -372,6 +390,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 +511,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 +524,7 @@ void SpriteBatch::setSpriteAnimation( const char* pAssetId, const bool autoResto
         return;
 
     // Set animation.
-    mSelectedSprite->setAnimation( pAssetId, autoRestore );
+    mSelectedSprite->setAnimation( pAssetId );
 }
 
 //------------------------------------------------------------------------------
@@ -527,7 +548,7 @@ void SpriteBatch::clearSpriteAsset( void )
         return;
 
     // Clear the asset.
-    mSelectedSprite->clearAsset();
+    mSelectedSprite->clearAssets();
 }
 
 //------------------------------------------------------------------------------
@@ -925,6 +946,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.
@@ -1187,38 +1232,106 @@ void SpriteBatch::destroySpriteBatchQuery( void )
 
     // Finish if sprite clipping 
     delete mpSpriteBatchQuery;
+    mpSpriteBatchQuery = NULL;
 }
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomWrite( TamlCustomNode* pSpritesNode )
+bool SpriteBatch::destroySprite( const U32 batchId )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(SpriteBatch_DestroySprite);
+
+    // Find sprite.
+    typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
+
+    // Finish if sprite not found.
+    if ( spriteItr == mSprites.end() )
+        return false;
+
+    // Find sprite.    
+    SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
+
+    // Sanity!
+    AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch::destroySprite() - Found sprite but it was NULL." );
+
+    // Cache sprite.
+    SpriteBatchItemFactory.cacheObject( pSpriteBatchItem );
+
+    // Remove from sprites.
+    mSprites.erase( batchId );
+
+    return true;
+}
+
+//------------------------------------------------------------------------------
+
+bool SpriteBatch::checkSpriteSelected( void ) const
+{
+    // Finish if a sprite is selected.
+    if ( mSelectedSprite != NULL )
+        return true;
+
+    // No, so warn,
+    Con::warnf( "Cannot perform sprite operation no sprite is selected." );
+
+    return false;
+}
+
+//------------------------------------------------------------------------------
+
+b2AABB SpriteBatch::calculateLocalAABB( const b2AABB& renderAABB )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(SpriteBatch_CalculateLocalAABB);
+
+    // Calculate local OOBB.
+    b2Vec2 localOOBB[4];
+    CoreMath::mAABBtoOOBB( renderAABB, localOOBB );
+    CoreMath::mCalculateInverseOOBB( localOOBB, mBatchTransform, localOOBB );
+
+    // Calculate local AABB.
+    b2AABB localAABB;
+    CoreMath::mOOBBtoAABB( localOOBB, localAABB );
+    
+    return localAABB;
+}
+
+//------------------------------------------------------------------------------
+
+void SpriteBatch::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomWrite);
 
-    // Fetch property names.
-    StringTableEntry spriteItemTypeName = StringTable->insert( "Sprite" );
+    // Finish if no sprites.
+    if ( getSpriteCount() == 0 )
+        return;
+
+    // Add sprites node.
+    TamlCustomNode* pSpritesNode = customNodes.addNode( spritesNodeName );
 
     // Write all sprites.
     for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
-    {
-        // Add sprite node.
-        TamlCustomNode* pNode = pSpritesNode->addNode( spriteItemTypeName );
-        
+    {      
         // Write type with sprite item.
-        spriteItr->value->onTamlCustomWrite( pNode );
+        spriteItr->value->onTamlCustomWrite( pSpritesNode );
     }
 }
 
 //------------------------------------------------------------------------------
 
-void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
+void SpriteBatch::onTamlCustomRead( const TamlCustomNodes& customNodes )
 {
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomRead);
 
-    // Fetch node name.
-    StringTableEntry spriteItemNodeName = StringTable->insert( "Sprite" );
+    // Find sprites custom node.
+    const TamlCustomNode* pSpritesNode = customNodes.findNode( spritesNodeName );
+
+    // Finish if we don't have the node.
+    if ( pSpritesNode == NULL )
+        return;
 
     // Fetch children nodes.
     const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
@@ -1233,7 +1346,7 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
         StringTableEntry nodeName = pNode->getNodeName();
 
         // Is this a known node name?
-        if ( nodeName != spriteItemNodeName )
+        if ( nodeName != spritesItemTypeName )
         {
             // No, so warn.
             Con::warnf( "SpriteBatch - Unknown custom type '%s'.", nodeName );
@@ -1271,62 +1384,32 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
 
 //------------------------------------------------------------------------------
 
-bool SpriteBatch::destroySprite( const U32 batchId )
+void SpriteBatch::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
 {
-    // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatch_DestroySprite);
-
-    // Find sprite.
-    typeSpriteBatchHash::iterator spriteItr = mSprites.find( batchId );
-
-    // Finish if sprite not found.
-    if ( spriteItr == mSprites.end() )
-        return false;
-
-    // Find sprite.    
-    SpriteBatchItem* pSpriteBatchItem = spriteItr->value;
-
     // Sanity!
-    AssertFatal( pSpriteBatchItem != NULL, "SpriteBatch::destroySprite() - Found sprite but it was NULL." );
-
-    // Cache sprite.
-    SpriteBatchItemFactory.cacheObject( pSpriteBatchItem );
-
-    // Remove from sprites.
-    mSprites.erase( batchId );
-
-    return true;
-}
-
-//------------------------------------------------------------------------------
-
-bool SpriteBatch::checkSpriteSelected( void ) const
-{
-    // Finish if a sprite is selected.
-    if ( mSelectedSprite != NULL )
-        return true;
-
-    // No, so warn,
-    Con::warnf( "Cannot perform sprite operation no sprite is selected." );
-
-    return false;
-}
-
-//------------------------------------------------------------------------------
-
-b2AABB SpriteBatch::calculateLocalAABB( const b2AABB& renderAABB )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatch_CalculateLocalAABB);
-
-    // Calculate local OOBB.
-    b2Vec2 localOOBB[4];
-    CoreMath::mAABBtoOOBB( renderAABB, localOOBB );
-    CoreMath::mCalculateInverseOOBB( localOOBB, mBatchTransform, localOOBB );
-
-    // Calculate local AABB.
-    b2AABB localAABB;
-    CoreMath::mOOBBtoAABB( localOOBB, localAABB );
+    AssertFatal( pClassRep != NULL,  "SpriteBatch::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SpriteBatch::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    char buffer[1024];
+
+    // Create sprite batch node element.
+    TiXmlElement* pBatchNodeElement = new TiXmlElement( "xs:element" );
+    dSprintf( buffer, sizeof(buffer), "%s.%s", pClassRep->getClassName(), spritesNodeName );
+    pBatchNodeElement->SetAttribute( "name", buffer );
+    pBatchNodeElement->SetAttribute( "minOccurs", 0 );
+    pBatchNodeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pBatchNodeElement );
+
+    // Create complex type.
+    TiXmlElement* pBatchNodeComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pBatchNodeElement->LinkEndChild( pBatchNodeComplexTypeElement );
     
-    return localAABB;
+    // Create choice element.
+    TiXmlElement* pBatchNodeChoiceElement = new TiXmlElement( "xs:choice" );
+    pBatchNodeChoiceElement->SetAttribute( "minOccurs", 0 );
+    pBatchNodeChoiceElement->SetAttribute( "maxOccurs", "unbounded" );
+    pBatchNodeComplexTypeElement->LinkEndChild( pBatchNodeChoiceElement );
+
+    // Write sprite batch item.
+    SpriteBatchItem::WriteCustomTamlSchema( pClassRep, pBatchNodeChoiceElement );
 }

+ 11 - 4
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,9 +173,14 @@ 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;
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
     SpriteBatchItem* createSprite( void );
     SpriteBatchItem* findSpritePosition( const SpriteBatchItem::LogicalPosition& logicalPosition );
@@ -188,8 +195,8 @@ protected:
     void createSpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );
 
-    void onTamlCustomWrite( TamlCustomNode* pSpritesNode );
-    void onTamlCustomRead( const TamlCustomNode* pSpritesNode );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes  );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 private:
     bool destroySprite( const U32 batchId );

+ 192 - 62
engine/source/2d/core/SpriteBatchItem.cc

@@ -28,73 +28,39 @@
 #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;
+StringTableEntry spritesItemTypeName                = StringTable->insert( "Sprite" );
+
+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 +125,8 @@ void SpriteBatchItem::resetState( void )
 
     mSpriteBatchQueryKey = 0;
 
+    mUserData = NULL;
+
     // Require self ticking.
     mSelfTick = true;
 }
@@ -310,10 +278,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.
@@ -334,14 +303,17 @@ void SpriteBatchItem::updateWorldTransform( const U32 batchTransformId )
 
 //------------------------------------------------------------------------------
 
-void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
+void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pParentNode )
 {
+    // Add sprite node.
+    TamlCustomNode* pSpriteNode = pParentNode->addNode( spritesItemTypeName );
+
     // Write name.
     if ( getName() != StringTable->EmptyString )
         pSpriteNode->addField( spriteNameName, getName() );
 
-    // Write asset.
-    if ( isStaticMode() )
+    // Static frame provider?
+    if ( isStaticFrameProvider() )
     {
         // Fetch image asset Id.
         StringTableEntry assetId = getImage();
@@ -410,7 +382,7 @@ void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
 
     // Write source blend factor.
     if ( mBlendMode && mSrcBlendFactor != GL_SRC_ALPHA )
-        pSpriteNode->addField( spriteBlendModeName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
+        pSpriteNode->addField( spriteSrcBlendFactorName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
         
     // Write destination blend factor.
     if ( mBlendMode && mDstBlendFactor != GL_ONE_MINUS_SRC_ALPHA )
@@ -584,3 +556,161 @@ void SpriteBatchItem::onTamlCustomRead( const TamlCustomNode* pSpriteNode )
     if ( spriteChildren.size() == 1 )
         setDataObject( spriteChildren[0]->getProxyObject<SimObject>(true) );
 }
+
+//------------------------------------------------------------------------------
+
+void SpriteBatchItem::WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SpriteBatchItem::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SpriteBatchItem::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create batch item element.
+    TiXmlElement* pBatchItemElement = new TiXmlElement( "xs:element" );
+    pBatchItemElement->SetAttribute( "name", spritesItemTypeName );
+    pBatchItemElement->SetAttribute( "minOccurs", 0 );
+    pBatchItemElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->LinkEndChild( pBatchItemElement );
+
+    // Create complex type Element.
+    TiXmlElement* pBatchItemComplexTypeElement = new TiXmlElement( "xs:complexType" );
+    pBatchItemElement->LinkEndChild( pBatchItemComplexTypeElement );
+
+    // Create "Name" attribute.
+    TiXmlElement* pBatchItemName = new TiXmlElement( "xs:attribute" );
+    pBatchItemName->SetAttribute( "name", spriteNameName );
+    pBatchItemName->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemName );
+
+    // "Create "Image" attribute.
+    TiXmlElement* pBatchItemImage = new TiXmlElement( "xs:attribute" );
+    pBatchItemImage->SetAttribute( "name", spriteImageName );
+    pBatchItemImage->SetAttribute( "type", "AssetId_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemImage );
+
+    // "Create "Image Frame" attribute.
+    TiXmlElement* pBatchItemImageFrame = new TiXmlElement( "xs:attribute" );
+    pBatchItemImageFrame->SetAttribute( "name", spriteImageFrameName );
+    pBatchItemImageFrame->SetAttribute( "type", "xs:positiveInteger" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemImageFrame );
+
+    // "Create "Animation" attribute.
+    TiXmlElement* pBatchItemAnimation = new TiXmlElement( "xs:attribute" );
+    pBatchItemAnimation->SetAttribute( "name", spriteAnimationName );
+    pBatchItemAnimation->SetAttribute( "type", "AssetId_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAnimation );
+
+    // Create "Visible" attribute.
+    TiXmlElement* pBatchItemVisible = new TiXmlElement( "xs:attribute" );
+    pBatchItemVisible->SetAttribute( "name", spriteVisibleName );
+    pBatchItemVisible->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemVisible );
+
+    // Create "Local Position" attribute.
+    TiXmlElement* pBatchItemPosition = new TiXmlElement( "xs:attribute" );
+    pBatchItemPosition->SetAttribute( "name", spriteLocalPositionName );
+    pBatchItemPosition->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemPosition );
+
+    // Create "Size" attribute.
+    TiXmlElement* pBatchItemSize = new TiXmlElement( "xs:attribute" );
+    pBatchItemSize->SetAttribute( "name", spriteSizeName );
+    pBatchItemSize->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSize );
+
+    // Create "Local Angle" attribute.
+    TiXmlElement* pBatchItemAngle = new TiXmlElement( "xs:attribute" );
+    pBatchItemAngle->SetAttribute( "name", spriteLocalAngleName );
+    pBatchItemAngle->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAngle );
+
+    // Create "Depth" attribute.
+    TiXmlElement* pBatchItemDepth = new TiXmlElement( "xs:attribute" );
+    pBatchItemDepth->SetAttribute( "name", spriteDepthName );
+    pBatchItemDepth->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemDepth );
+
+    // Create "FlipX" attribute.
+    TiXmlElement* pBatchItemFlipX = new TiXmlElement( "xs:attribute" );
+    pBatchItemFlipX->SetAttribute( "name", spriteFlipXName );
+    pBatchItemFlipX->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemFlipX );
+
+    // Create "FlipY" attribute.
+    TiXmlElement* pBatchItemFlipY = new TiXmlElement( "xs:attribute" );
+    pBatchItemFlipY->SetAttribute( "name", spriteFlipYName );
+    pBatchItemFlipY->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemFlipY );
+
+    // Create "Sort Point" attribute.
+    TiXmlElement* pBatchItemSortPoint = new TiXmlElement( "xs:attribute" );
+    pBatchItemSortPoint->SetAttribute( "name", spriteSortPointName );
+    pBatchItemSortPoint->SetAttribute( "type", "Vector2_ConsoleType" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSortPoint );
+
+    // Create "Render Group" attribute.
+    TiXmlElement* pBatchItemRenderGroup = new TiXmlElement( "xs:attribute" );
+    pBatchItemRenderGroup->SetAttribute( "name", spriteRenderGroupName );
+    pBatchItemRenderGroup->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemRenderGroup );
+
+    // Create "Blend Mode" attribute.
+    TiXmlElement* pBatchItemBlendMode = new TiXmlElement( "xs:attribute" );
+    pBatchItemBlendMode->SetAttribute( "name", spriteBlendModeName );
+    pBatchItemBlendMode->SetAttribute( "type", "xs:boolean" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemBlendMode );
+
+    // Create "Source Blend Factor" attribute.
+    TiXmlElement* pBatchItemSrcBlendFactor = new TiXmlElement( "xs:attribute" );
+    pBatchItemSrcBlendFactor->SetAttribute( "name", spriteSrcBlendFactorName );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemSrcBlendFactor );
+    TiXmlElement* pBatchItemSrcBlendFactorType = new TiXmlElement( "xs:simpleType" );
+    pBatchItemSrcBlendFactor->LinkEndChild( pBatchItemSrcBlendFactorType );
+    TiXmlElement* pBatchItemSrcBlendFactorTypeRestriction = new TiXmlElement( "xs:restriction" );
+    pBatchItemSrcBlendFactorTypeRestriction->SetAttribute( "base", "xs:string" );
+    pBatchItemSrcBlendFactorType->LinkEndChild( pBatchItemSrcBlendFactorTypeRestriction );
+    const S32 srcBlendFactorEnumsCount = srcBlendFactorTable.size;
+    for( S32 index = 0; index < srcBlendFactorEnumsCount; ++index )
+    {
+        // Add enumeration element.
+        TiXmlElement* pSrcBlendFactorEnumeration = new TiXmlElement( "xs:enumeration" );
+        pSrcBlendFactorEnumeration->SetAttribute( "value", srcBlendFactorTable.table[index].label );
+        pBatchItemSrcBlendFactorTypeRestriction->LinkEndChild( pSrcBlendFactorEnumeration );
+    }
+
+    // Create "Destination Blend Factor" attribute.
+    TiXmlElement* pBatchItemDstBlendFactor = new TiXmlElement( "xs:attribute" );
+    pBatchItemDstBlendFactor->SetAttribute( "name", spriteDstBlendFactorName );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemDstBlendFactor );
+    TiXmlElement* pBatchItemDstBlendFactorType = new TiXmlElement( "xs:simpleType" );
+    pBatchItemDstBlendFactor->LinkEndChild( pBatchItemDstBlendFactorType );
+    TiXmlElement* pBatchItemDstBlendFactorTypeRestriction = new TiXmlElement( "xs:restriction" );
+    pBatchItemDstBlendFactorTypeRestriction->SetAttribute( "base", "xs:string" );
+    pBatchItemDstBlendFactorType->LinkEndChild( pBatchItemDstBlendFactorTypeRestriction );
+    const S32 dstBlendFactorEnumsCount = dstBlendFactorTable.size;
+    for( S32 index = 0; index < dstBlendFactorEnumsCount; ++index )
+    {
+        // Add enumeration element.
+        TiXmlElement* pDstBlendFactorEnumeration = new TiXmlElement( "xs:enumeration" );
+        pDstBlendFactorEnumeration->SetAttribute( "value", dstBlendFactorTable.table[index].label );
+        pBatchItemDstBlendFactorTypeRestriction->LinkEndChild( pDstBlendFactorEnumeration );
+    }
+
+    // Create "Blend Color" attribute.
+    TiXmlElement* pBatchItemBlendColor = new TiXmlElement( "xs:attribute" );
+    pBatchItemBlendColor->SetAttribute( "name", spriteBlendColorName );
+    pBatchItemBlendColor->SetAttribute( "type", "Color_Enums" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemBlendColor );
+
+    // Create "Alpha Test" attribute.
+    TiXmlElement* pBatchItemAlphaTest = new TiXmlElement( "xs:attribute" );
+    pBatchItemAlphaTest->SetAttribute( "name", spriteAlphaTestName );
+    pBatchItemAlphaTest->SetAttribute( "type", "xs:float" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemAlphaTest );
+
+    // Create "Logical Position" attribute.
+    TiXmlElement* pBatchItemLogicalPosition = new TiXmlElement( "xs:attribute" );
+    pBatchItemLogicalPosition->SetAttribute( "name", spriteLogicalPositionName );
+    pBatchItemLogicalPosition->SetAttribute( "type", "xs:string" );
+    pBatchItemComplexTypeElement->LinkEndChild( pBatchItemLogicalPosition );
+}

+ 19 - 13
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,15 @@ class SceneRenderRequest;
 
 //------------------------------------------------------------------------------  
 
-class SpriteBatchItem : public SpriteProxyBase
+extern StringTableEntry spritesItemTypeName;
+
+//------------------------------------------------------------------------------  
+
+class SpriteBatchItem : public ImageFrameProvider
 {
     friend class SpriteBatch;
 
-    typedef SpriteProxyBase Parent;
+    typedef ImageFrameProvider Parent;
 
 public:
     // Represents a logical position.
@@ -225,6 +221,8 @@ protected:
 
     U32                 mSpriteBatchQueryKey;
 
+    void*               mUserData;
+
 public:
     SpriteBatchItem();
     virtual ~SpriteBatchItem();
@@ -284,14 +282,22 @@ 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; }
 
     virtual void copyTo( SpriteBatchItem* pSpriteBatchItem ) const;
 
+    inline const Vector2* getRenderOOBB( void ) const { return mRenderOOBB; }
+
     void prepareRender( SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
     void render( BatchRender* pBatchRenderer, const SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
     void setBatchParent( SpriteBatch* pSpriteBatch, const U32 batchId );
     inline void setProxyId( const S32 proxyId ) { mProxyId = proxyId; }
@@ -299,7 +305,7 @@ protected:
     void updateLocalTransform( void );
     void updateWorldTransform( const U32 batchTransformId );
 
-    void onTamlCustomWrite( TamlCustomNode* pSpriteNode );
+    void onTamlCustomWrite( TamlCustomNode* pParentNode );
     void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
 };
 

+ 61 - 21
engine/source/2d/core/SpriteBatchQuery.cc

@@ -39,8 +39,8 @@ SpriteBatchQuery::SpriteBatchQuery( SpriteBatch* pSpriteBatch ) :
         mpSpriteBatch(pSpriteBatch),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mComparePoint(0.0f, 0.0f)
 {
     // Set debug associations.
     VECTOR_SET_ASSOCIATION( mQueryResults );
@@ -81,10 +81,10 @@ bool SpriteBatchQuery::update( SpriteBatchItem* pSpriteBatchItem, const b2AABB&
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryArea( const b2AABB& aabb )
+U32 SpriteBatchQuery::queryArea( const b2AABB& aabb, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryArea);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryArea);
 
     mMasterQueryKey++;
 
@@ -92,17 +92,26 @@ U32 SpriteBatchQuery::renderQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
 
     // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
     Query( this, aabb );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 SpriteBatchQuery::queryRay( const Vector2& point1, const Vector2& point2, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryRay);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryRay);
 
     mMasterQueryKey++;
 
@@ -110,23 +119,23 @@ U32 SpriteBatchQuery::renderQueryRay( const Vector2& point1, const Vector2& poin
     mIsRaycastQueryResult = true;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point1;
-    rayInput.p2 = point2;
-
-    rayInput.maxFraction = 1.0f;
-
-    RayCast( this, rayInput );
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
+    RayCast( this, mCompareRay );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
 
-U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
+U32 SpriteBatchQuery::queryPoint( const Vector2& point, const bool targetOOBB )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryPoint);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryPoint);
 
     mMasterQueryKey++;
 
@@ -134,12 +143,13 @@ U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point;
-    rayInput.p2 = b2Vec2( point.x + b2_linearSlop, point.y + b2_linearSlop );
-    rayInput.maxFraction = 1.0f;
-
-    RayCast( this, rayInput );
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = targetOOBB;
+    Query( this, aabb );
+    mCheckOOBB = false;
 
     return getQueryResultsCount();
 }
@@ -180,6 +190,25 @@ bool SpriteBatchQuery::QueryCallback( S32 proxyId )
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return true;
 
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+            // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSpriteBatchItem->getRenderOOBB(), 4);
+
+        if ( mCheckPoint )
+        {
+            if ( !oobb.TestPoint( mCompareTransform, mComparePoint ) )
+                return true;
+        }
+        else
+        {
+            if ( !b2TestOverlap( &mComparePolygonShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+    }
+
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 
@@ -203,6 +232,17 @@ F32 SpriteBatchQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return 1.0f;
 
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSpriteBatchItem->getRenderOOBB(), 4);
+        b2RayCastOutput rayOutput;
+        if ( !oobb.RayCast( &rayOutput, mCompareRay, mCompareTransform, 0 ) )
+            return true;
+    }
+
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 

+ 10 - 6
engine/source/2d/core/SpriteBatchQuery.h

@@ -48,10 +48,10 @@ public:
     void            remove( SpriteBatchItem* pSpriteBatchItem );
     bool            update( SpriteBatchItem* pSpriteBatchItem, const b2AABB& aabb, const b2Vec2& displacement );
 
-    //// Render queries.
-    U32             renderQueryArea( const b2AABB& aabb );
-    U32             renderQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             renderQueryPoint( const Vector2& point );
+    //// Spatial queries.
+    U32             queryArea( const b2AABB& aabb, const bool targetOOBB );
+    U32             queryRay( const Vector2& point1, const Vector2& point2, const bool targetOOBB );
+    U32             queryPoint( const Vector2& point, const bool targetOOBB );
  
     /// Results.
     void            clearQuery( void );
@@ -74,8 +74,12 @@ private:
 
 private:
     SpriteBatch*                mpSpriteBatch;
-    bool                        mCheckFixturePoint;
-    b2Vec2                      mFixturePoint;
+    b2PolygonShape              mComparePolygonShape;
+    b2RayCastInput              mCompareRay;
+    b2Vec2                      mComparePoint;
+    b2Transform                 mCompareTransform;
+    bool                        mCheckOOBB;
+    bool                        mCheckPoint;
     typeSpriteBatchQueryResultVector mQueryResults;
     bool                        mIsRaycastQueryResult;
     typeSceneObjectVector       mAlwaysInScopeSet;

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

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

@@ -0,0 +1,310 @@
+//-----------------------------------------------------------------------------
+// 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 );
+}
+
+//------------------------------------------------------------------------------
+
+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 );
+
+    // Are the spatials dirty?
+    if ( getSpatialDirty() )
+    {
+        // Yes, so update the world transform.
+        setBatchTransform( getRenderTransform() );
+    }
+
+    // Are the render extents dirty?
+    if ( getLocalExtentsDirty() )
+    {
+        // Yes, so set size as local extents.
+        setSize( getLocalExtents() );
+    }
+
+    // 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 );
+
+    // Finish if the spatials are NOT dirty.
+    if ( !getSpatialDirty() )
+        return;
+
+    // Update the batch world transform.
+    setBatchTransform( getRenderTransform() );
+}
+//-----------------------------------------------------------------------------
+
+void WaveComposite::interpolateObject( const F32 timeDelta )
+{
+    // Call parent.
+    Parent::interpolateObject( timeDelta );
+
+    // Update composition time (interpolated).
+    updateComposition( (timeDelta * mPreTickTime) + ((1.0f-timeDelta) * mPostTickTime) );
+
+    // Finish if the spatials are NOT dirty.
+    if ( !getSpatialDirty() )
+        return;
+
+    // Update the batch world transform.
+    setBatchTransform( getRenderTransform() );
+}
+
+//------------------------------------------------------------------------------
+
+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() );
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue )
+{
+    // Prepare render.
+    SpriteBatch::prepareRender( this, pSceneRenderState, pSceneRenderQueue );
+}
+
+//-----------------------------------------------------------------------------
+
+void WaveComposite::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
+{
+    // Render.
+    SpriteBatch::render( pSceneRenderState, pSceneRenderRequest, pBatchRenderer );
+}
+
+//-----------------------------------------------------------------------------
+
+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;
+    }
+}

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

@@ -0,0 +1,98 @@
+//-----------------------------------------------------------------------------
+// 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 SceneObject, public SpriteBatch
+{
+protected:
+    typedef SceneObject 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 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 );
+
+    virtual bool canPrepareRender( void ) const { return true; }
+    virtual bool validRender( void ) const { return mImageAsset.notNull(); }
+    virtual bool shouldRender( void ) const { return true; }
+    virtual void scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue );    
+    virtual void sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer );
+
+    bool setImage( const char* pImageAssetId );
+    inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
+    bool setImageFrame( const U32 frame );
+    inline U32 getImageFrame( void ) const { return mImageFrame; }
+    void setSpriteCount( const U32 spriteCount );
+    inline U32 getSpriteCount( void ) const { return mSpriteCount; }
+    void setSpriteSize( const Vector2& spriteSize );
+    inline const Vector2& getSpriteSize( void ) const { return mSpriteSize; };
+    inline void setAmplitude( const F32 amplitude ) { mAmplitude = amplitude; }
+    inline F32 getAmplitude( void ) const { return mAmplitude; }
+    inline void setFrequency( const F32 frequency ) { mFrequency = frequency; }
+    inline F32 getFrequency( void ) const { return mFrequency; }
+
+    /// Declare Console Object.
+    DECLARE_CONOBJECT( WaveComposite );
+
+protected:
+    void generateComposition( void );
+    void updateComposition( const F32 time );
+
+protected:
+    static bool setImage(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setImage( data ); return false; }
+    static const char* getImage(void* obj, const char* data) { return DYNAMIC_VOID_CAST_TO(WaveComposite, ImageFrameProvider, obj)->getImage(); }
+    static bool writeImage( void* obj, StringTableEntry pFieldName ) { return static_cast<WaveComposite*>(obj)->mImageAsset.notNull(); }
+    static bool setImageFrame(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setImageFrame( dAtoi(data) ); return false; }
+    static bool writeImageFrame( void* obj, StringTableEntry pFieldName ) { return static_cast<WaveComposite*>(obj)->getImageFrame() > 0; }
+    static bool setSpriteCount(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setSpriteCount( dAtoi(data) ); return false; }
+    static bool setSpriteSize(void* obj, const char* data) { static_cast<WaveComposite*>(obj)->setSpriteSize( Vector2(data) ); return false; }
+};
+
+#endif // _WAVE_COMPOSITE_H_

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

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

+ 114 - 39
engine/source/2d/gui/SceneWindow.cc

@@ -40,6 +40,28 @@
 // Debug Profiling.
 #include "debug/profiler.h"
 
+// Input event names.
+static StringTableEntry inputEventEnterName            = StringTable->insert("onTouchEnter");
+static StringTableEntry inputEventLeaveName            = StringTable->insert("onTouchLeave");
+static StringTableEntry inputEventDownName             = StringTable->insert("onTouchDown");
+static StringTableEntry inputEventUpName               = StringTable->insert("onTouchUp");
+static StringTableEntry inputEventMovedName            = StringTable->insert("onTouchMoved");
+static StringTableEntry inputEventDraggedName          = StringTable->insert("onTouchDragged");
+
+static StringTableEntry mouseEventMiddleMouseDownName   = StringTable->insert("onMiddleMouseDown");
+static StringTableEntry mouseEventMiddleMouseUpName     = StringTable->insert("onMiddleMouseUp");
+static StringTableEntry mouseEventMiddleMouseDraggedName= StringTable->insert("onMiddleMouseDragged");
+
+static StringTableEntry mouseEventRightMouseDownName   = StringTable->insert("onRightMouseDown");
+static StringTableEntry mouseEventRightMouseUpName     = StringTable->insert("onRightMouseUp");
+static StringTableEntry mouseEventRightMouseDraggedName= StringTable->insert("onRightMouseDragged");
+
+static StringTableEntry mouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
+static StringTableEntry mouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
+
+static StringTableEntry mouseEventEnterName            = StringTable->insert("onMouseEnter");
+static StringTableEntry mouseEventLeaveName            = StringTable->insert("onMouseLeave");
+
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT(SceneWindow);
@@ -99,23 +121,6 @@ SceneWindow::SceneWindow() :    mpScene(NULL),
     VECTOR_SET_ASSOCIATION( mInputEventEntering );
     VECTOR_SET_ASSOCIATION( mInputEventLeaving );    
 
-    // Touch input event names.
-    mInputEventDownName             = StringTable->insert("onTouchDown");
-    mInputEventUpName               = StringTable->insert("onTouchUp");
-    mInputEventMovedName            = StringTable->insert("onTouchMoved");
-    mInputEventDraggedName          = StringTable->insert("onTouchDragged");
-    mInputEventEnterName            = StringTable->insert("onTouchEnter");
-    mInputEventLeaveName            = StringTable->insert("onTouchLeave");
-
-    // Mouse input event names.
-    mMouseEventRightMouseDownName   = StringTable->insert("onRightMouseDown");
-    mMouseEventRightMouseUpName     = StringTable->insert("onRightMouseUp");
-    mMouseEventRightMouseDraggedName= StringTable->insert("onRightMouseDragged");
-    mMouseEventWheelUpName          = StringTable->insert("onMouseWheelUp");
-    mMouseEventWheelDownName        = StringTable->insert("onMouseWheelDown");
-    mMouseEventEnterName            = StringTable->insert("onMouseEnter");
-    mMouseEventLeaveName            = StringTable->insert("onMouseLeave");
-
     // Turn-on Tick Processing.
     setProcessTicks( true );
 }
@@ -130,9 +135,14 @@ SceneWindow::~SceneWindow()
 
 bool SceneWindow::onAdd()
 {
+    // Call parent.
     if(!Parent::onAdd())
         return false;
 
+    // Register input sets.
+    mInputEventWatching.registerObject();
+    mInputListeners.registerObject();
+
     // Reset the camera position.
     setCameraPosition( Vector2::getZero() );
 
@@ -156,6 +166,10 @@ void SceneWindow::onRemove()
     // Reset Scene.
     resetScene();
 
+    // Unregister input sets.
+    mInputEventWatching.unregisterObject();
+    mInputListeners.unregisterObject();
+
     // Call Parent.
     Parent::onRemove();
 }
@@ -820,6 +834,28 @@ void SceneWindow::setObjectInputEventInvisibleFilter( const bool useInvisible )
 
 //-----------------------------------------------------------------------------
 
+void SceneWindow::addInputListener( SimObject* pSimObject )
+{
+    // Sanity!
+    AssertFatal( pSimObject != NULL, "SceneWindow::addInputEventListener() - Cannot add NULL object as input event listener." );
+
+    // Ignore if the object is already a listener.
+    if ( mInputListeners.find( pSimObject ) != mInputListeners.end() )
+        return;
+
+    // Add as listener.
+    mInputListeners.addObject( pSimObject );
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::removeInputListener( SimObject* pSimObject )
+{
+    mInputListeners.removeObject( pSimObject );
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::setMousePosition( const Vector2& mousePosition )
 {
     // Fetch Canvas.
@@ -967,6 +1003,13 @@ void SceneWindow::sendWindowInputEvent( StringTableEntry name, const GuiEvent& e
 
     // Call Scripts.
     Con::executef(this, 4, name, argBuffer[0], argBuffer[1], argBuffer[2]);
+
+    // Iterate listeners.
+    for( SimSet::iterator listenerItr = mInputListeners.begin(); listenerItr != mInputListeners.end(); ++listenerItr )
+    {
+        // Call scripts on listener.
+        Con::executef( *listenerItr, 4, name, argBuffer[0], argBuffer[1], argBuffer[2] );
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -980,10 +1023,10 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
     if ( !getScene() ) return;
 
     // Only process appropriate input events.
-    if ( !( name == mInputEventDownName ||
-            name == mInputEventUpName ||
-            name == mInputEventMovedName ||
-            name == mInputEventDraggedName ) )
+    if ( !( name == inputEventDownName ||
+            name == inputEventUpName ||
+            name == inputEventMovedName ||
+            name == inputEventDraggedName ) )
         return;
 
     // Convert Event-Position into scene coordinates.
@@ -1089,7 +1132,7 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventLeaving[index];
 
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventLeaveName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventLeaveName, event, worldMousePoint );
 
         // Remove scene object.
         mInputEventWatching.removeObject( pSceneObject );
@@ -1102,10 +1145,10 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventEntering[index];
 
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventEnterName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventEnterName, event, worldMousePoint );
 
         // Process "moved" or "dragged" events.
-        if ( name == mInputEventMovedName || name == mInputEventDraggedName )
+        if ( name == inputEventMovedName || name == inputEventDraggedName )
             pSceneObject->onInputEvent( name, event, worldMousePoint );
 
         // Add scene object.
@@ -1120,6 +1163,22 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
 
 //-----------------------------------------------------------------------------
 
+void SceneWindow::onMouseEnter( const GuiEvent& event )
+{
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventEnterName, event);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::onMouseLeave( const GuiEvent& event )
+{
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventLeaveName, event);
+}
+
+//-----------------------------------------------------------------------------
+
 void SceneWindow::onMouseDown( const GuiEvent& event )
 {
     // Lock Mouse (if necessary).
@@ -1127,7 +1186,7 @@ void SceneWindow::onMouseDown( const GuiEvent& event )
         mouseLock();
 
     // Dispatch input event.
-    dispatchInputEvent( mInputEventDownName, event);
+    dispatchInputEvent( inputEventDownName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1139,7 +1198,7 @@ void SceneWindow::onMouseUp( const GuiEvent& event )
         mouseUnlock();
 
     // Dispatch input event.
-    dispatchInputEvent(mInputEventUpName, event);
+    dispatchInputEvent(inputEventUpName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1147,7 +1206,7 @@ void SceneWindow::onMouseUp( const GuiEvent& event )
 void SceneWindow::onMouseMove( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mInputEventMovedName, event);
+    dispatchInputEvent(inputEventMovedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1155,23 +1214,39 @@ void SceneWindow::onMouseMove( const GuiEvent& event )
 void SceneWindow::onMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mInputEventDraggedName, event);
+    dispatchInputEvent(inputEventDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
 
-void SceneWindow::onMouseEnter( const GuiEvent& event )
+void SceneWindow::onMiddleMouseDown( const GuiEvent& event )
 {
+    // Lock Mouse (if necessary).
+    if(mLockMouse)
+        mouseLock();
+
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventEnterName, event);
+    dispatchInputEvent(mouseEventMiddleMouseDownName, event);
 }
 
 //-----------------------------------------------------------------------------
 
-void SceneWindow::onMouseLeave( const GuiEvent& event )
+void SceneWindow::onMiddleMouseUp( const GuiEvent& event )
+{
+    // Lock Mouse (if necessary).
+    if(mLockMouse)
+        mouseUnlock();
+
+    // Dispatch input event.
+    dispatchInputEvent(mouseEventMiddleMouseUpName, event);
+}
+
+//-----------------------------------------------------------------------------
+
+void SceneWindow::onMiddleMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventLeaveName, event);
+    dispatchInputEvent(mouseEventMiddleMouseDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1183,7 +1258,7 @@ void SceneWindow::onRightMouseDown( const GuiEvent& event )
         mouseLock();
 
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDownName, event);
+    dispatchInputEvent(mouseEventRightMouseDownName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1195,7 +1270,7 @@ void SceneWindow::onRightMouseUp( const GuiEvent& event )
         mouseUnlock();
 
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseUpName, event);
+    dispatchInputEvent(mouseEventRightMouseUpName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1203,7 +1278,7 @@ void SceneWindow::onRightMouseUp( const GuiEvent& event )
 void SceneWindow::onRightMouseDragged( const GuiEvent& event )
 {
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDraggedName, event);
+    dispatchInputEvent(mouseEventRightMouseDraggedName, event);
 }
 
 //-----------------------------------------------------------------------------
@@ -1214,7 +1289,7 @@ bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
    Parent::onMouseWheelUp( event );
 
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelUpName, event);
+   dispatchInputEvent(mouseEventWheelUpName, event);
 
    // Return Success.
    return true;
@@ -1228,7 +1303,7 @@ bool SceneWindow::onMouseWheelDown( const GuiEvent& event )
    Parent::onMouseWheelDown( event );
 
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelDownName, event);
+   dispatchInputEvent(mouseEventWheelDownName, event);
 
    // Return Success.
    return true;
@@ -1689,7 +1764,7 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     glEnable        ( GL_BLEND );
     glBlendFunc     ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
 
-    // Set banner background colour.
+    // Set banner background color.
     const ColorI& fillColor = mProfile->mFillColor;
     const F32 colorScale = 1.0f / 255.0f;
     glColor4f( fillColor.red * colorScale, fillColor.green * colorScale, fillColor.blue * colorScale, fillColor.alpha * colorScale );
@@ -1726,7 +1801,7 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     // Disable Banner Blending.
     glDisable       ( GL_BLEND );
         
-    // Set Debug Text Colour.
+    // Set Debug Text color.
     dglSetBitmapModulation( mProfile->mFontColor );
 
     // ****************************************************************

+ 25 - 29
engine/source/2d/gui/SceneWindow.h

@@ -131,27 +131,11 @@ private:
     U32                 mInputEventGroupMaskFilter;
     U32                 mInputEventLayerMaskFilter;
     bool                mInputEventInvisibleFilter;
-    SimSet              mInputEventWatching;
     typeWorldQueryResultVector mInputEventQuery;
     typeSceneObjectVector mInputEventEntering;
     typeSceneObjectVector mInputEventLeaving;
-
-    // Input event names.
-    StringTableEntry    mInputEventDownName;
-    StringTableEntry    mInputEventUpName;
-    StringTableEntry    mInputEventMovedName;
-    StringTableEntry    mInputEventDraggedName;
-    StringTableEntry    mInputEventEnterName;
-    StringTableEntry    mInputEventLeaveName;
-
-    StringTableEntry    mMouseEventRightMouseDownName;
-    StringTableEntry    mMouseEventRightMouseUpName;
-    StringTableEntry    mMouseEventRightMouseDraggedName;
-    StringTableEntry    mMouseEventWheelUpName;
-    StringTableEntry    mMouseEventWheelDownName;
-    StringTableEntry    mMouseEventEnterName;
-    StringTableEntry    mMouseEventLeaveName;
-
+    SimSet              mInputEventWatching;
+    SimSet              mInputListeners;
 
     /// Render Masks.
     U32                 mRenderLayerMask;
@@ -220,6 +204,9 @@ public:
     inline void clearWatchedInputEvents( void ) { mInputEventWatching.clear(); }
     inline void removeFromInputEventPick(SceneObject* pSceneObject ) { mInputEventWatching.removeObject((SimObject*)pSceneObject); }
 
+    void addInputListener( SimObject* pSimObject );
+    void removeInputListener( SimObject* pSimObject );
+
     /// Coordinate Conversion.
     void windowToScenePoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
     void sceneToWindowPoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
@@ -304,18 +291,27 @@ public:
 
     /// GuiControl
     virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
-    void onMouseDown( const GuiEvent& event );
-    void onMouseUp( const GuiEvent& event );
-    void onMouseMove( const GuiEvent& event );
-    void onMouseDragged( const GuiEvent& event );
-    void onMouseEnter( const GuiEvent& event );
-    void onMouseLeave( const GuiEvent& event );
-    void onRightMouseDown( const GuiEvent& event );
-    void onRightMouseUp( const GuiEvent& event );
-    void onRightMouseDragged( const GuiEvent& event );
-    bool onMouseWheelDown( const GuiEvent &event );
-    bool onMouseWheelUp( const GuiEvent &event );
     virtual void onRender( Point2I offset, const RectI& updateRect );
+
+    virtual void onMouseEnter( const GuiEvent& event );
+    virtual void onMouseLeave( const GuiEvent& event );
+
+    virtual void onMouseDown( const GuiEvent& event );
+    virtual void onMouseUp( const GuiEvent& event );
+    virtual void onMouseMove( const GuiEvent& event );
+    virtual void onMouseDragged( const GuiEvent& event );
+
+    virtual void onMiddleMouseDown(const GuiEvent &event);
+    virtual void onMiddleMouseUp(const GuiEvent &event);
+    virtual void onMiddleMouseDragged(const GuiEvent &event);
+
+    virtual void onRightMouseDown( const GuiEvent& event );
+    virtual void onRightMouseUp( const GuiEvent& event );
+    virtual void onRightMouseDragged( const GuiEvent& event );
+
+    virtual bool onMouseWheelDown( const GuiEvent &event );
+    virtual bool onMouseWheelUp( const GuiEvent &event );
+
     void renderMetricsOverlay( Point2I offset, const RectI& updateRect );
 
     static CameraInterpolationMode getInterpolationModeEnum(const char* label);

+ 46 - 0
engine/source/2d/gui/SceneWindow_ScriptBinding.h

@@ -1146,6 +1146,52 @@ ConsoleMethod(SceneWindow, setObjectInputEventInvisibleFilter, void, 3, 3, "(boo
 
 //-----------------------------------------------------------------------------
 
+ConsoleMethod(SceneWindow, addInputListener, bool, 3, 3,    "(inputListener) Adds an object as an input listener.\n"
+                                                            "@param inputListener The object to add as an input listener.\n"
+                                                            "@return Whether the object was added as an input event listener or not.")
+{
+    // Find the SimObject
+    SimObject* pSimObject = Sim::findObject( argv[2] );
+
+    // Did we find the SimObject?
+    if ( pSimObject == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "SceneWindow::addInputListener() - Could not find the object '%s' to add as an input event listener.", argv[2] );
+        return false;
+    }
+
+    // Add input listener.
+    object->addInputListener( pSimObject );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleMethod(SceneWindow, removeInputListener, bool, 3, 3, "(inputListener) Removes an object from being an input listener.\n"
+                                                            "@param inputListener The object to remove as an input listener.\n"
+                                                            "@return Whether the object was removed as an input event listener or not.")
+{
+    // Find the SimObject
+    SimObject* pSimObject = Sim::findObject( argv[2] );
+
+    // Did we find the SimObject?
+    if ( pSimObject == NULL )
+    {
+        // No, so warn.
+        Con::warnf( "SceneWindow::removeInputListener() - Could not find the object '%s' to remove from being an input event listener.", argv[2] );
+        return false;
+    }
+
+    // Remove input listener.
+    object->removeInputListener( pSimObject );
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
 ConsoleMethod(SceneWindow, setLockMouse, void, 3, 3, "(bool lockSet) Sets the window mouse-lock status."
               "@return No return value.")
 {

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

Fichier diff supprimé car celui-ci est trop grand
+ 373 - 289
engine/source/2d/scene/Scene.cc


+ 44 - 22
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
@@ -193,7 +198,8 @@ public:
         PICK_INVALID,
         ///---
         PICK_ANY,
-        PICK_SIZE,
+        PICK_AABB,
+        PICK_OOBB,
         PICK_COLLISION,
     };
 
@@ -202,6 +208,7 @@ public:
 
 private:
     typedef BehaviorComponent   Parent;
+    typedef SceneObject         Children;
 
     /// World.
     b2World*                    mpWorld;
@@ -219,10 +226,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 +353,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 +368,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 +403,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 +416,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 );
@@ -426,8 +442,12 @@ public:
                                 bool& enableMotor,
                                 F32& motorSpeed,
                                 F32& maxMotorTorque );
+
+	F32                     getRevoluteJointAngle( const U32 jointId );
+	F32						getRevoluteJointSpeed( const U32 jointId );
+
     /// 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 +467,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 +498,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 +518,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 +547,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 +556,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 +590,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 +649,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 ); }

+ 3 - 3
engine/source/2d/scene/SceneRenderState.h

@@ -46,7 +46,7 @@ struct SceneRenderState
         U32 renderGroupMask,
         const Vector2& renderScale,
         DebugStats* pDebugStats,
-        GuiControl* pGuiControl )
+        SimObject* pRenderHost )
     {
         mRenderArea       = renderArea;
         mRenderAABB       = CoreMath::mRectFtoAABB( renderArea );
@@ -56,7 +56,7 @@ struct SceneRenderState
         mRenderLayerMask  = renderLayerMask;
         mRenderGroupMask  = renderGroupMask;
         mpDebugStats      = pDebugStats;
-        mpGuiControl      = pGuiControl;
+        mpRenderHost      = pRenderHost;
     }
 
     RectF           mRenderArea;
@@ -67,7 +67,7 @@ struct SceneRenderState
     U32             mRenderGroupMask;
     Vector2         mRenderScale;
     DebugStats*     mpDebugStats;
-    GuiControl*     mpGuiControl;
+    SimObject*      mpRenderHost;
 
 
 };

Fichier diff supprimé car celui-ci est trop grand
+ 268 - 152
engine/source/2d/scene/Scene_ScriptBinding.h


+ 305 - 57
engine/source/2d/scene/WorldQuery.cc

@@ -39,8 +39,10 @@ WorldQuery::WorldQuery( Scene* pScene ) :
         mpScene(pScene),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mCheckAABB(false),
+        mCheckOOBB(false),
+        mCheckCircle(false)
 {
     // Set debug associations.
     for ( U32 n = 0; n < MAX_LAYERS_SUPPORTED; n++ )
@@ -130,10 +132,10 @@ void WorldQuery::removeAlwaysInScope( SceneObject* pSceneObject )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
+U32 WorldQuery::collisionQueryAABB( const b2AABB& aabb )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryArea);
+    PROFILE_SCOPE(WorldQuery_collisionQueryAABB);
 
     mMasterQueryKey++;
 
@@ -141,7 +143,16 @@ U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
 
     // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckAABB = true;
     mpScene->getWorld()->QueryAABB( this, aabb );
+    mCheckAABB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -151,10 +162,10 @@ U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 WorldQuery::collisionQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryRay);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryRay);
 
     mMasterQueryKey++;
 
@@ -172,10 +183,10 @@ U32 WorldQuery::fixtureQueryRay( const Vector2& point1, const Vector2& point2 )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
+U32 WorldQuery::collisionQueryPoint( const Vector2& point )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryPoint);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryPoint);
 
     mMasterQueryKey++;
 
@@ -186,10 +197,10 @@ U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
     b2AABB aabb;
     aabb.lowerBound = point;
     aabb.upperBound = point;
-    mCheckFixturePoint = true;
-    mFixturePoint = point;
+    mCheckPoint = true;
+    mComparePoint = point;
     mpScene->getWorld()->QueryAABB( this, aabb );
-    mCheckFixturePoint = false;
+    mCheckPoint = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -199,10 +210,38 @@ U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryArea( const b2AABB& aabb )
+U32 WorldQuery::collisionQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryArea);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryCircle);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckCircle = true;
+    mpScene->getWorld()->QueryAABB( this, aabb );
+    mCheckCircle = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::aabbQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_aabbQueryAABB);
 
     mMasterQueryKey++;
 
@@ -220,10 +259,10 @@ U32 WorldQuery::renderQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
+U32 WorldQuery::aabbQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryRay);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
 
     mMasterQueryKey++;
 
@@ -231,13 +270,35 @@ U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
     mIsRaycastQueryResult = true;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point1;
-    rayInput.p2 = point2;
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    RayCast( this, mCompareRay );
 
-    rayInput.maxFraction = 1.0f;
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::aabbQueryPoint( const Vector2& point )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AABBQueryPoint);
 
-    RayCast( this, rayInput );
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    Query( this, aabb );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -247,10 +308,10 @@ U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::renderQueryPoint( const Vector2& point )
+U32 WorldQuery::aabbQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryPoint);
+    PROFILE_SCOPE(WorldQuery_AABBQueryCircle);
 
     mMasterQueryKey++;
 
@@ -258,12 +319,46 @@ U32 WorldQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
 
     // Query.
-    b2RayCastInput rayInput;
-    rayInput.p1 = point;
-    rayInput.p2 = b2Vec2( point.x + b2_linearSlop, point.y + b2_linearSlop );
-    rayInput.maxFraction = 1.0f;
+    b2AABB aabb;
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckCircle = true;
+    Query( this, aabb );
+    mCheckCircle = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
 
-    RayCast( this, rayInput );
+U32 WorldQuery::oobbQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_aabbQueryAABB);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2Vec2 verts[4];
+    verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+    verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+    verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+    verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+    mComparePolygonShape.Set( verts, 4 );
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    mCheckAABB = true;
+    Query( this, aabb );
+    mCheckAABB = false;
+    mCheckOOBB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -273,15 +368,54 @@ U32 WorldQuery::renderQueryPoint( const Vector2& point )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::anyQueryArea( const b2AABB& aabb )
+U32 WorldQuery::oobbQueryRay( const Vector2& point1, const Vector2& point2 )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_AnyQueryAreaAABB);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
+
+    mMasterQueryKey++;
+
+    // Flag as a ray-cast query result.
+    mIsRaycastQueryResult = true;
 
     // Query.
-    renderQueryArea( aabb );
-    mMasterQueryKey--;
-    fixtureQueryArea( aabb );
+    mCompareRay.p1 = point1;
+    mCompareRay.p2 = point2;
+    mCompareRay.maxFraction = 1.0f;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    RayCast( this, mCompareRay );
+    mCheckOOBB = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::oobbQueryPoint( const Vector2& point )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AABBQueryPoint);
+
+    mMasterQueryKey++;
+
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
+    b2AABB aabb;
+    aabb.lowerBound = point;
+    aabb.upperBound = point;
+    mComparePoint = point;
+    mCompareTransform.SetIdentity();
+    mCheckOOBB = true;
+    mCheckPoint = true;
+    Query( this, aabb );
+    mCheckPoint = false;
+    mCheckOOBB = false;
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -291,18 +425,50 @@ U32 WorldQuery::anyQueryArea( const b2AABB& aabb )
 
 //-----------------------------------------------------------------------------
 
-U32 WorldQuery::anyQueryArea( const Vector2& lowerBound, const Vector2& upperBound )
+U32 WorldQuery::oobbQueryCircle( const Vector2& centroid, const F32 radius )
 {
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_AnyQueryAreaBounds);
+    PROFILE_SCOPE(WorldQuery_OOBBQueryCircle);
+
+    mMasterQueryKey++;
 
-    // Calculate AABB.
+    // Flag as not a ray-cast query result.
+    mIsRaycastQueryResult = false;
+
+    // Query.
     b2AABB aabb;
-    aabb.lowerBound.Set( getMin( lowerBound.x, upperBound.x ), getMin( lowerBound.x, upperBound.x ) );
-    aabb.upperBound.Set( getMax( lowerBound.x, upperBound.x ), getMax( lowerBound.x, upperBound.x ) );
+    mCompareTransform.SetIdentity();
+    mCompareCircleShape.m_p = centroid;
+    mCompareCircleShape.m_radius = radius;
+    mCompareCircleShape.ComputeAABB( &aabb, mCompareTransform, 0 );
+    mCheckOOBB = true;
+    mCheckCircle = true;
+    Query( this, aabb );
+    mCheckCircle = false;
+    mCheckOOBB = false;
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::anyQueryAABB( const b2AABB& aabb )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_anyQueryAABBAABB);
 
     // Query.
-    return anyQueryArea( aabb );
+    oobbQueryAABB( aabb );
+    mMasterQueryKey--;
+    collisionQueryAABB( aabb );
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
 }
 
 //-----------------------------------------------------------------------------
@@ -313,9 +479,9 @@ U32 WorldQuery::anyQueryRay( const Vector2& point1, const Vector2& point2 )
     PROFILE_SCOPE(WorldQuery_AnyQueryRay);
 
     // Query.
-    renderQueryRay( point1, point2 );
+    oobbQueryRay( point1, point2 );
     mMasterQueryKey--;
-    fixtureQueryRay( point1, point2 );
+    collisionQueryRay( point1, point2 );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -331,9 +497,27 @@ U32 WorldQuery::anyQueryPoint( const Vector2& point )
     PROFILE_SCOPE(WorldQuery_AnyQueryPoint);
 
     // Query.
-    renderQueryPoint( point );
+    oobbQueryPoint( point );
     mMasterQueryKey--;
-    fixtureQueryPoint( point );
+    collisionQueryPoint( point );
+
+    // Inject always-in-scope.
+    injectAlwaysInScope();
+
+    return getQueryResultsCount();
+}
+
+//-----------------------------------------------------------------------------
+
+U32 WorldQuery::anyQueryCircle( const Vector2& centroid, const F32 radius )
+{
+    // Debug Profiling.
+    PROFILE_SCOPE(WorldQuery_AnyQueryCircle);
+
+    // Query.
+    oobbQueryCircle( centroid, radius );
+    mMasterQueryKey--;
+    collisionQueryCircle( centroid, radius );
 
     // Inject always-in-scope.
     injectAlwaysInScope();
@@ -425,12 +609,19 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
 
-    // Check fixture point.
-    if ( mCheckFixturePoint && !fixture->TestPoint( mFixturePoint ) )
+    // Check collision point.
+    if ( mCheckPoint && !fixture->TestPoint( mComparePoint ) )
         return true;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check collision AABB.
+    if ( mCheckAABB )
+        if ( !b2TestOverlap( &mComparePolygonShape, 0, fixture->GetShape(), 0, mCompareTransform, fixture->GetBody()->GetTransform() ) )
+            return true;
+
+    // Check collision circle.
+    if ( mCheckCircle )
+        if ( !b2TestOverlap( &mCompareCircleShape, 0, fixture->GetShape(), 0, mCompareTransform, fixture->GetBody()->GetTransform() ) )
+            return true;
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -442,6 +633,9 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return true;
@@ -478,9 +672,6 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneGroupMask = pSceneObject->getSceneGroupMask();
@@ -489,7 +680,7 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
     const S32 shapeIndex = pSceneObject->getCollisionShapeIndex( fixture );
 
     // Sanity!
-    AssertFatal( shapeIndex >= 0, "2dWorldQuery::ReportFixture() - Cannot find shape index reported on physics proxy of a fixture." );
+    AssertFatal( shapeIndex >= 0, "WorldQuery::ReportFixture() - Cannot find shape index reported on physics proxy of a fixture." );
 
     // Compare masks and report.
     if ( (mQueryFilter.mSceneLayerMask & sceneLayerMask) != 0 && (mQueryFilter.mSceneGroupMask & sceneGroupMask) != 0 )
@@ -497,6 +688,9 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
         WorldQueryResult queryResult( pSceneObject, point, normal, fraction, (U32)shapeIndex );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return 1.0f;
@@ -533,8 +727,48 @@ bool WorldQuery::QueryCallback( S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSceneObject->getRenderOOBB(), 4);
+
+        // Check point.
+        if ( mCheckPoint )
+        {
+            if ( !oobb.TestPoint( mCompareTransform, mComparePoint ) )
+                return true;
+        }
+        // Check AABB.
+        else if ( mCheckAABB )
+        {
+            if ( !b2TestOverlap( &mComparePolygonShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+        // Check circle.
+        else if ( mCheckCircle )
+        {
+            if ( !b2TestOverlap( &mCompareCircleShape, 0, &oobb, 0, mCompareTransform, mCompareTransform ) )
+                return true;
+        }
+    }
+    // Check circle.
+    else if ( mCheckCircle )
+    {
+        // Fetch the shapes AABB.
+        b2AABB aabb = pSceneObject->getAABB();
+        b2Vec2 verts[4];
+        verts[0].Set( aabb.lowerBound.x, aabb.lowerBound.y );
+        verts[1].Set( aabb.upperBound.x, aabb.lowerBound.y );
+        verts[2].Set( aabb.upperBound.x, aabb.upperBound.y );
+        verts[3].Set( aabb.lowerBound.x, aabb.upperBound.y );
+        b2PolygonShape shapeAABB;
+        shapeAABB.Set( verts, 4);
+        if ( !b2TestOverlap( &mCompareCircleShape, 0, &shapeAABB, 0, mCompareTransform, mCompareTransform ) )
+            return true;
+    }
+
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -546,6 +780,9 @@ bool WorldQuery::QueryCallback( S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return true;
@@ -582,8 +819,16 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
+    // Check OOBB.
+    if ( mCheckOOBB )
+    {
+        // Fetch the shapes render OOBB.
+        b2PolygonShape oobb;
+        oobb.Set( pSceneObject->getRenderOOBB(), 4);
+        b2RayCastOutput rayOutput;
+        if ( !oobb.RayCast( &rayOutput, mCompareRay, mCompareTransform, 0 ) )
+            return true;
+    }
 
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -595,6 +840,9 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
 
     return 1.0f;
@@ -621,9 +869,6 @@ void WorldQuery::injectAlwaysInScope( void )
         if ( pSceneObject->getWorldQueryKey() == mMasterQueryKey )
             continue;
 
-        // Tag with world query key.
-        pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
         // Enabled filter.
         if ( mQueryFilter.mEnabledFilter && !pSceneObject->isEnabled() )
             continue;
@@ -646,6 +891,9 @@ void WorldQuery::injectAlwaysInScope( void )
             WorldQueryResult queryResult( pSceneObject );
             mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
             mQueryResults.push_back( queryResult );
+
+            // Tag with world query key.
+            pSceneObject->setWorldQueryKey( mMasterQueryKey );
         }
     }
 }

+ 30 - 15
engine/source/2d/scene/WorldQuery.h

@@ -56,21 +56,29 @@ public:
     void            addAlwaysInScope( SceneObject* pSceneObject );
     void            removeAlwaysInScope( SceneObject* pSceneObject );
 
-    //// World fixture queries.
-    U32             fixtureQueryArea( const b2AABB& aabb );
-    U32             fixtureQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             fixtureQueryPoint( const Vector2& point );
-
-    //// Render queries.
-    U32             renderQueryArea( const b2AABB& aabb );
-    U32             renderQueryRay( const Vector2& point1, const Vector2& point2 );
-    U32             renderQueryPoint( const Vector2& point );
-
-    /// World fixture & render queries.
-    U32             anyQueryArea( const b2AABB& aabb );
-    U32             anyQueryArea( const Vector2& lowerBound, const Vector2& upperBound );
+    /// World collision-shape queries.
+    U32             collisionQueryAABB( const b2AABB& aabb );
+    U32             collisionQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             collisionQueryPoint( const Vector2& point );
+    U32             collisionQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// AABB queries.
+    U32             aabbQueryAABB( const b2AABB& aabb );
+    U32             aabbQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             aabbQueryPoint( const Vector2& point );
+    U32             aabbQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// OOBB queries.
+    U32             oobbQueryAABB( const b2AABB& aabb );
+    U32             oobbQueryRay( const Vector2& point1, const Vector2& point2 );
+    U32             oobbQueryPoint( const Vector2& point );
+    U32             oobbQueryCircle( const Vector2& centroid, const F32 radius );
+
+    /// Any queries.
+    U32             anyQueryAABB( const b2AABB& aabb );
     U32             anyQueryRay( const Vector2& point1, const Vector2& point2 );
     U32             anyQueryPoint( const Vector2& point );
+    U32             anyQueryCircle( const Vector2& centroid, const F32 radius );
 
     /// Filtering.
     inline void     setQueryFilter( const WorldQueryFilter& queryFilter ) { mQueryFilter = queryFilter; }
@@ -96,8 +104,15 @@ private:
 private:
     Scene*                      mpScene;
     WorldQueryFilter            mQueryFilter;
-    bool                        mCheckFixturePoint;
-    b2Vec2                      mFixturePoint;
+    b2PolygonShape              mComparePolygonShape;
+    b2CircleShape               mCompareCircleShape;
+    b2RayCastInput              mCompareRay;
+    b2Vec2                      mComparePoint;
+    b2Transform                 mCompareTransform;
+    bool                        mCheckPoint;
+    bool                        mCheckAABB;
+    bool                        mCheckOOBB;
+    bool                        mCheckCircle;
     typeWorldQueryResultVector  mLayeredQueryResults[MAX_LAYERS_SUPPORTED];
     typeWorldQueryResultVector  mQueryResults;
     bool                        mIsRaycastQueryResult;

+ 44 - 26
engine/source/2d/sceneobject/CompositeSprite.cc

@@ -81,10 +81,6 @@ const char* CompositeSprite::getBatchLayoutTypeDescription(const CompositeSprite
     return StringTable->EmptyString;
 }
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(CompositeSprite);
-
 //------------------------------------------------------------------------------
 
 CompositeSprite::CompositeSprite() :
@@ -108,8 +104,8 @@ void CompositeSprite::initPersistFields()
     Parent::initPersistFields();
 
     /// Defaults.
-    addProtectedField( "DefaultSpriteStride", TypeVector2, Offset(mDefaultSpriteStride, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
-    addProtectedField( "DefaultSpriteSize", TypeVector2, Offset(mDefaultSpriteSize, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
+    addProtectedField( "DefaultSpriteStride", TypeVector2, Offset(mDefaultSpriteStride, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteStride, "");
+    addProtectedField( "DefaultSpriteSize", TypeVector2, Offset(mDefaultSpriteSize, CompositeSprite), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeDefaultSpriteSize, "");
     addProtectedField( "DefaultSpriteAngle", TypeF32, Offset(mDefaultSpriteSize, CompositeSprite), &setDefaultSpriteAngle, &getDefaultSpriteAngle, &writeDefaultSpriteAngle, "");
     addProtectedField( "BatchLayout", TypeEnum, Offset(mBatchLayoutType, CompositeSprite), &setBatchLayout, &defaultProtectedGetFn, &writeBatchLayout, 1, &batchLayoutTypeTable, "");
     addProtectedField( "BatchCulling", TypeBool, Offset(mBatchCulling, CompositeSprite), &setBatchCulling, &defaultProtectedGetFn, &writeBatchCulling, "");
@@ -119,6 +115,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?
@@ -248,8 +267,8 @@ SpriteBatchItem* CompositeSprite::createSprite( const SpriteBatchItem::LogicalPo
             return createCustomLayout( logicalPosition );
 
         default:
-            // Sanity!
-            AssertFatal( false, "CompositeSprite::createSprite() - Unknown layout type encountered." );
+            // Warn.
+            Con::warnf( "CompositeSprite::createSprite() - Unknown layout type encountered." );
             return SpriteBatch::createSprite( logicalPosition );
     }
 }
@@ -386,18 +405,8 @@ void CompositeSprite::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomWrite( customNodes );
 
-    // Fetch sprite count.
-    const U32 spriteCount = getSpriteCount();
-
-    // Finish if no sprites.
-    if ( spriteCount == 0 )
-        return;
-
-    // Add sprites node.
-    TamlCustomNode* pSpritesNode = customNodes.addNode( StringTable->insert("Sprites") );
-
     // Write node with sprite batch.
-    SpriteBatch::onTamlCustomWrite( pSpritesNode );
+    SpriteBatch::onTamlCustomWrite( customNodes );
 }
 
 //-----------------------------------------------------------------------------
@@ -407,13 +416,22 @@ void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Call parent.
     Parent::onTamlCustomRead( customNodes );
 
-    // Find sprites custom node.
-    const TamlCustomNode* pSpritesNode = customNodes.findNode( StringTable->insert("Sprites") );
+    // Read node with sprite batch.
+    SpriteBatch::onTamlCustomRead( customNodes );
+}
 
-    // Finish if we don't have the node.
-    if ( pSpritesNode == NULL )
-        return;
+//-----------------------------------------------------------------------------
 
-    // Read node with sprite batch.
-    SpriteBatch::onTamlCustomRead( pSpritesNode );
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "CompositeSprite::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "CompositeSprite::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Write sprite batch.
+    SpriteBatch::WriteCustomTamlSchema( pClassRep, pParentElement );
 }
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(CompositeSprite, WriteCustomTamlSchema);

+ 6 - 1
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 );
@@ -89,9 +92,11 @@ protected:
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 protected:
+    static bool         writeDefaultSpriteStride( void* obj, StringTableEntry pFieldName )  { return !STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteStride().isEqual( Vector2::getOne() ); }
+    static bool         writeDefaultSpriteSize( void* obj, StringTableEntry pFieldName )    { return !STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteSize().isEqual( Vector2::getOne() ); }
     static bool         setDefaultSpriteAngle(void* obj, const char* data)                  { STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->setDefaultSpriteAngle(mDegToRad(dAtof(data))); return false; }
     static const char*  getDefaultSpriteAngle(void* obj, const char* data)                  { return Con::getFloatArg( mRadToDeg(STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteAngle()) ); }
-    static bool         writeDefaultSpriteAngle( void* obj, StringTableEntry pFieldName )   { return mNotZero( static_cast<SpriteBatch*>(obj)->getDefaultSpriteAngle() ); }
+    static bool         writeDefaultSpriteAngle( void* obj, StringTableEntry pFieldName )   { return mNotZero( STATIC_VOID_CAST_TO(CompositeSprite, SpriteBatch, obj)->getDefaultSpriteAngle() ); }
     static bool         writeBatchIsolated( void* obj, StringTableEntry pFieldName )        { return static_cast<CompositeSprite*>(obj)->getBatchIsolated(); }
     static bool         writeBatchSortMode( void* obj, StringTableEntry pFieldName )        { return static_cast<CompositeSprite*>(obj)->getBatchSortMode() != SceneRenderQueue::RENDER_SORT_OFF; }
 

+ 20 - 13
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] );
 }
 
 //-----------------------------------------------------------------------------
@@ -772,14 +768,25 @@ ConsoleMethod(CompositeSprite, setSpriteBlendColor, void, 3, 6, "(float red, flo
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(CompositeSprite, getSpriteBlendColor, const char*, 2, 2,  "Gets the sprite blend color\n"
+ConsoleMethod(CompositeSprite, getSpriteBlendColor, const char*, 2, 3,  "(allowColorNames) Gets the sprite blend color\n"
+                                                                        "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
                                                                         "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getSpriteBlendColor();
 
-    // Fetch the field value.
-    return Con::getData( TypeColorF, &blendColor, 0 );
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &blendColor, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return blendColor.scriptThis();
 }
 
 //-----------------------------------------------------------------------------
@@ -908,7 +915,7 @@ ConsoleMethod(CompositeSprite, pickPoint, const char*, 3, 4,    "(x / y ) Picks
     point = b2MulT( renderTransform, point );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryPoint( point );
+    pSpriteBatchQuery->queryPoint( point, true );
 
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
@@ -1032,7 +1039,7 @@ ConsoleMethod(CompositeSprite, pickArea, const char*, 4, 6, "(startx/y, endx/y )
     CoreMath::mRotateAABB( aabb, -renderTransform.q.GetAngle(), aabb );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryArea( aabb );
+    pSpriteBatchQuery->queryArea( aabb, true );
 
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
@@ -1146,7 +1153,7 @@ ConsoleMethod(CompositeSprite, pickRay, const char*, 4, 6,  "(startx/y, endx/y)
     v2 = b2MulT( renderTransform, v2 );
 
     // Perform query.
-    pSpriteBatchQuery->renderQueryRay( v1, v2 );
+    pSpriteBatchQuery->queryRay( v1, v2, true );
 
     // Sanity!
     AssertFatal( pSpriteBatchQuery->getIsRaycastQueryResult(), "Invalid non-ray-cast query result returned." );

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

+ 9 - 13
engine/source/2d/sceneobject/ParticlePlayer.h

@@ -31,28 +31,20 @@
 #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"
 #define PARTICLE_PLAYER_SIZE_SCALE              "$pref::T2D::ParticlePlayerSizeScale"
 #define PARTICLE_PLAYER_FORCE_SCALE             "$pref::T2D::ParticlePlayerForceScale"
+#define PARTICLE_PLAYER_TIME_SCALE              "$pref::T2D::ParticlePlayerTimeScale"
 
 //-----------------------------------------------------------------------------
 
-class ParticlePlayer : public SceneObject, public AssetPtrCallback
+class ParticlePlayer : public SceneObject, protected AssetPtrCallback
 {
 private:
     typedef SceneObject Parent;
 
-
     /// Emitter node.
     class EmitterNode
     {
@@ -134,7 +126,7 @@ private:
     F32                         mEmissionRateScale;
     F32                         mSizeScale;
     F32                         mForceScale;
-
+    F32                         mTimeScale;
 
     bool                        mWaitingForParticles;
     bool                        mWaitingForDelete;
@@ -174,6 +166,9 @@ public:
     inline void setForceScale( const F32 scale ) { mForceScale = scale; }
     inline F32 getForceScale( void  ) const { return mForceScale; }
 
+    inline void setTimeScale( const F32 scale ) { mTimeScale = scale; }
+    inline F32 getTimeScale( void  ) const { return mTimeScale; }
+
     inline const U32 getEmitterCount( void ) const { return (U32)mEmitters.size(); }
 
     void setEmitterPaused( const bool paused, const U32 emitterIndex );
@@ -194,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 );
@@ -207,10 +204,9 @@ protected:
     static bool     writeEmissionRateScale( void* obj, StringTableEntry pFieldName )        { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getEmissionRateScale() ); }
     static bool     writeSizeScale( void* obj, StringTableEntry pFieldName )                { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getSizeScale() ); }
     static bool     writeForceScale( void* obj, StringTableEntry pFieldName )               { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getForceScale() ); }
+    static bool     writeTimeScale( void* obj, StringTableEntry pFieldName )                { return !mIsOne( static_cast<ParticlePlayer*>( obj )->getTimeScale() ); }
 
 private:
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
-
     void initializeParticleAsset( void );
     void destroyParticleAsset( void );
 };

+ 397 - 59
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() ); 
     }
 }
 
@@ -2639,14 +2603,14 @@ void SceneObject::setBlendOptions( void )
         // Set Blend Function.
         glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
 
-        // Set Colour.
+        // Set color.
         glColor4f(mBlendColor.red,mBlendColor.green,mBlendColor.blue,mBlendColor.alpha );
     }
     else
     {
         // Disable Blending.
         glDisable( GL_BLEND );
-        // Reset Colour.
+        // Reset color.
         glColor4f(1,1,1,1);
     }
 
@@ -2673,7 +2637,7 @@ void SceneObject::resetBlendOptions( void )
 
     glDisable( GL_ALPHA_TEST);
 
-    // Reset Colour.
+    // Reset color.
     glColor4f(1,1,1,1);
 }
 
@@ -4132,3 +4096,377 @@ const char* SceneObject::getDstBlendFactorDescription(const GLenum factor)
 
     return StringTable->EmptyString;
 }
+
+//-----------------------------------------------------------------------------
+
+static void WriteCircleCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCircleCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create circle element.
+    TiXmlElement* pCircleElement = new TiXmlElement( "xs:element" );
+    pCircleElement->SetAttribute( "name", circleTypeName );
+    pCircleElement->SetAttribute( "minOccurs", 0 );
+    pCircleElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->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 );
+}
+
+//-----------------------------------------------------------------------------
+
+static void WritePolygonCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WritePolygonCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WritePolygonCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create polygon element.
+    TiXmlElement* pPolygonElement = new TiXmlElement( "xs:element" );
+    pPolygonElement->SetAttribute( "name", polygonTypeName );
+    pPolygonElement->SetAttribute( "minOccurs", 0 );
+    pPolygonElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->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 );
+}
+
+//-----------------------------------------------------------------------------
+
+static void WriteChainCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteChainCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteChainCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create chain element.
+    TiXmlElement* pChainElement = new TiXmlElement( "xs:element" );
+    pChainElement->SetAttribute( "name", chainTypeName );
+    pChainElement->SetAttribute( "minOccurs", 0 );
+    pChainElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->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 );
+}
+
+//-----------------------------------------------------------------------------
+
+static void WriteEdgeCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteEdgeCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    // Create edge element.
+    TiXmlElement* pEdgeElement = new TiXmlElement( "xs:element" );
+    pEdgeElement->SetAttribute( "name", edgeTypeName );
+    pEdgeElement->SetAttribute( "minOccurs", 0 );
+    pEdgeElement->SetAttribute( "maxOccurs", 1 );
+    pParentElement->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 );
+}
+
+//-----------------------------------------------------------------------------
+
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "SceneObject::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "SceneObject::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
+
+    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 );
+
+    // Write collision shapes.
+    WriteCircleCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WritePolygonCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WriteChainCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+    WriteEdgeCustomTamlSchema( pClassRep, pShapesNodeChoiceElement );
+}
+
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT_SCHEMA(SceneObject, WriteCustomTamlSchema);

+ 1 - 3
engine/source/2d/sceneobject/SceneObject.h

@@ -91,8 +91,6 @@ const S32 INVALID_COLLISION_SHAPE_INDEX = -1;
 extern EnumTable bodyTypeTable;
 extern EnumTable srcBlendFactorTable;
 extern EnumTable dstBlendFactorTable;
-extern EnumTable srcBlendFactorTable;
-extern EnumTable dstBlendFactorTable;
 
 //-----------------------------------------------------------------------------
 
@@ -705,7 +703,7 @@ protected:
     static bool             writeUseInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUseInputEvents() == true; }
 
     /// Picking.
-    static bool             writePickingAllowed( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getPickingAllowed() == true; }    
+    static bool             writePickingAllowed( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getPickingAllowed() == false; }    
 
     /// Script callbacks.
     static bool             writeUpdateCallback( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUpdateCallback() == true; }

+ 67 - 14
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)
@@ -3273,14 +3315,25 @@ ConsoleMethod(SceneObject, setBlendColor, void, 3, 6,   "(float red, float green
 
 //-----------------------------------------------------------------------------
 
-ConsoleMethod(SceneObject, getBlendColor, const char*, 2, 2, "Gets the Rendering Blend Colour.\n"
+ConsoleMethod(SceneObject, getBlendColor, const char*, 2, 3,    "(allowColorNames) Gets the Rendering Blend color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
                                                                 "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getBlendColor();
 
-    // Fetch the field value.
-    return Con::getData( TypeColorF, &blendColor, 0 );
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &blendColor, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return blendColor.scriptThis();
 }
 
 //-----------------------------------------------------------------------------

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

+ 14 - 171
engine/source/2d/sceneobject/ShapeVector.cc

@@ -63,11 +63,11 @@ ShapeVector::~ShapeVector()
 void ShapeVector::initPersistFields()
 {
    addProtectedField("PolyList", TypePoint2FVector, Offset(mPolygonBasisList, ShapeVector), &setPolyList, &defaultProtectedGetFn, &writePolyList, "");
-   addProtectedField("LineColor", TypeColorF, Offset(mLineColor, ShapeVector), &setLineColor, &defaultProtectedGetFn, &writeLineColor, "");
-   addProtectedField("FillColor", TypeColorF, Offset(mFillColor, ShapeVector), &setFillColor, &defaultProtectedGetFn, &writeFillColor, "");
-   addProtectedField("FillMode", TypeBool, Offset(mFillMode, ShapeVector), &setFillMode, &defaultProtectedGetFn, &writeFillMode, "");
-   addProtectedField("IsCircle", TypeBool, Offset(mIsCircle, ShapeVector), &setIsCircle, &defaultProtectedGetFn, &writeIsCircle, "");
-   addProtectedField("CircleRadius", TypeF32, Offset(mCircleRadius, ShapeVector), &setCircleRadius, &defaultProtectedGetFn, &writeCircleRadius, "");
+   addField("LineColor", TypeColorF, Offset(mLineColor, ShapeVector), &writeLineColor, "");
+   addField("FillColor", TypeColorF, Offset(mFillColor, ShapeVector), &writeFillColor, "");
+   addField("FillMode", TypeBool, Offset(mFillMode, ShapeVector), &writeFillMode, "");
+   addField("IsCircle", TypeBool, Offset(mIsCircle, ShapeVector), &writeIsCircle, "");
+   addField("CircleRadius", TypeF32, Offset(mCircleRadius, ShapeVector), &writeCircleRadius, "");
 
    Parent::initPersistFields();
 }
@@ -151,7 +151,7 @@ void ShapeVector::sceneRender( const SceneRenderState* pSceneRenderState, const
         renderPolygonShape(vertexCount);
     }
 
-    // Restore Colour.
+    // Restore color.
     glColor4f( 1,1,1,1 );
 
     // Restore Matrix.
@@ -220,7 +220,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 
-        // Set Fill Colour.
+        // Set Fill color.
         glColor4f( (GLfloat)mFillColor.red, (GLfloat)mFillColor.green, (GLfloat)mFillColor.blue, (GLfloat)mFillColor.alpha );
 
         GLfloat vert1[] = {//get first vert and make triangles based off of this one
@@ -253,7 +253,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
  
     }
 
-    // Set Line Colour.
+    // Set Line color.
     glColor4f(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha );
     
         for ( U32 n = 1; n <= vertexCount; n++ )
@@ -276,7 +276,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 
-        // Set Fill Colour.
+        // Set Fill color.
         glColor4fv( (GLfloat*)&mFillColor );
 
         // Draw Object.
@@ -288,7 +288,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         glEnd();
     }
 
-    // Set Line Colour.
+    // Set Line color.
     glColor4fv( (GLfloat*)&mLineColor );
 
     // Draw Object.
@@ -374,10 +374,10 @@ void ShapeVector::setPolyPrimitive( const U32 polyVertexCount )
     else if ( polyVertexCount == 4 )
     {
         // Yes, so set Quad.
-        mPolygonBasisList[0].Set(-1.0f, -1.0f);
-        mPolygonBasisList[1].Set(+1.0f, -1.0f);
-        mPolygonBasisList[2].Set(+1.0f, +1.0f);
-        mPolygonBasisList[3].Set(-1.0f, +1.0f);
+        mPolygonBasisList[0].Set(-0.5f, -0.5f);
+        mPolygonBasisList[1].Set(+0.5f, -0.5f);
+        mPolygonBasisList[2].Set(+0.5f, +0.5f);
+        mPolygonBasisList[3].Set(-0.5f, +0.5f);
     }
     else
     {
@@ -586,163 +586,6 @@ void ShapeVector::generateLocalPoly( void )
 
 //----------------------------------------------------------------------------
 
-void ShapeVector::setLineColorString( const char* lineColour )
-{
-    // Calculate Element Count.
-    const U32 elementCount = Utility::mGetStringElementCount( lineColour );
-
-    // Check we've got enough arguments.
-    if ( elementCount < 3 )
-    {
-        Con::warnf("ShapeVector::setLineColourString() - Invalid Number of Elements! (%s)", lineColour);
-        return;
-    }
-
-    // Calculate Red, Green and Blue.
-    const F32 red   = dAtof(Utility::mGetStringElement( lineColour, 0 ));
-    const F32 green = dAtof(Utility::mGetStringElement( lineColour, 1 ));
-    const F32 blue  = dAtof(Utility::mGetStringElement( lineColour, 2 ));
-
-    // Set Alpha (if specified).
-    F32 alpha;
-    if ( elementCount >= 4 )
-        alpha = dAtof(Utility::mGetStringElement( lineColour, 3 ));
-    else alpha = 1.0f;
-
-    // Set Line Colour.
-    setLineColor( ColorF(red, green, blue, alpha) );
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setLineColor( const ColorF& lineColour )
-{
-    // Set Line Colour.
-    mLineColor = lineColour;
-}
-
-//----------------------------------------------------------------------------
-
-const char* ShapeVector::getLineColor()
-{
-    // Get Return Buffer.
-    char* pReturnBuffer = Con::getReturnBuffer( 64 );
-    dSprintf( pReturnBuffer, 64, "%0.5f %0.5f %0.5f %0.5f", mLineColor.red, mLineColor.green,
-                                                            mLineColor.blue, mLineColor.alpha);
-    return pReturnBuffer;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setLineAlpha( const F32 alpha )
-{
-    // Set Line Alpha.
-    mLineColor.alpha = alpha;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillColorString( const char* fillColour )
-{
-    // Calculate Element Count.
-    const U32 elementCount = Utility::mGetStringElementCount( fillColour );
-
-    // Check we've got enough arguments.
-    if ( elementCount < 3 )
-    {
-        Con::warnf("ShapeVector::setFillColourString() - Invalid Number of Elements! (%s)", fillColour);
-        return;
-    }
-
-    // Calculate Red, Green and Blue.
-    const F32 red   = dAtof(Utility::mGetStringElement( fillColour, 0 ));
-    const F32 green = dAtof(Utility::mGetStringElement( fillColour, 1 ));
-    const F32 blue  = dAtof(Utility::mGetStringElement( fillColour, 2 ));
-
-    // Set Alpha (if specified).
-    F32 alpha;
-    if ( elementCount >= 4 )
-        alpha = dAtof(Utility::mGetStringElement( fillColour, 3 ));
-    else alpha = 1.0f;
-
-    // Set Fill Colour.
-    setFillColor( ColorF(red, green, blue, alpha) );
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillColor( const ColorF& fillColour )
-{
-    // Set Fill Colour.
-    mFillColor = fillColour;
-}
-
-//----------------------------------------------------------------------------
-
-const char* ShapeVector::getFillColor()
-{
-    // Get Return Buffer.
-    char* pReturnBuffer = Con::getReturnBuffer( 64 );
-    dSprintf( pReturnBuffer, 64, "%0.5f %0.5f %0.5f %0.5f", mFillColor.red, mFillColor.green,
-                                                            mFillColor.blue, mFillColor.alpha);
-    return pReturnBuffer;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillAlpha( const F32 alpha )
-{
-    // Set Fill Alpha.
-    mFillColor.alpha = alpha;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setFillMode( const bool fillMode )
-{
-    // Set Fill Mode.
-    mFillMode = fillMode;
-}
-
-//----------------------------------------------------------------------------
-
-bool ShapeVector::getFillMode()
-{
-    return mFillMode;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setIsCircle( const bool isCircle )
-{
-    // Set Fill Mode.
-    mIsCircle = isCircle;
-}
-
-//----------------------------------------------------------------------------
-
-bool ShapeVector::getIsCircle()
-{
-    return mIsCircle;
-}
-
-//----------------------------------------------------------------------------
-
-void ShapeVector::setCircleRadius( const F32 circleRadius )
-{
-    // Set Fill Mode.
-    mCircleRadius = circleRadius;
-}
-
-//----------------------------------------------------------------------------
-
-F32 ShapeVector::getCircleRadius()
-{
-    return mCircleRadius;
-}
-
-//----------------------------------------------------------------------------
-
 Vector2 ShapeVector::getBoxFromPoints()
 {
     Vector2 box(1.0f, 1.0f);

+ 16 - 30
engine/source/2d/sceneobject/ShapeVector.h

@@ -55,28 +55,24 @@ public:
     void setPolyScale( const Vector2& scale );
     void setPolyPrimitive( const U32 polyVertexCount );
     void setPolyCustom( const U32 polyVertexCount, const char* pCustomPolygon );
-
-    /// Rendering Attributes.
-    void setLineColorString( const char* lineColour );
-    void setLineColor( const ColorF& lineColour );
-    void setLineAlpha( const F32 alpha );
-    void setFillColorString( const char* fillColour );
-    void setFillColor( const ColorF& fillColour );
-    void setFillAlpha( const F32 alpha );
-    void setFillMode( const bool fillMode );
-    void setIsCircle( const bool isCircle );
-    void setCircleRadius( F32 radius );
-
-    /// Retrieval.
     U32 getPolyVertexCount( void ) { return U32(mPolygonBasisList.size()); };
+    inline const Vector2* getPolyBasis( void ) const { return &(mPolygonBasisList[0]); };
     const char* getPoly( void );
     const char* getWorldPoly( void );
-    inline const Vector2* getPolyBasis( void ) const         { return &(mPolygonBasisList[0]); };
-    bool getFillMode( void );
-    const char* getLineColor( void );
-    const char* getFillColor( void );
-    bool getIsCircle( void );
-    F32 getCircleRadius ( void );
+
+    inline void setLineColor( const ColorF& linecolor ) { mLineColor = linecolor; }
+    inline const ColorF& getLineColor( void ) const { return mLineColor; }
+    inline void setLineAlpha( const F32 alpha ) { mLineColor.alpha = alpha; }
+    inline void setFillColor( const ColorF& fillcolor ) { mFillColor = fillcolor; }
+    inline const ColorF& getFillColor( void ) const { return mFillColor; }
+    inline void setFillAlpha( const F32 alpha ) { mFillColor.alpha = alpha; }
+    inline void setFillMode( const bool fillMode ) { mFillMode = fillMode; }
+    inline bool getFillMode( void ) const { return mFillMode; }
+    inline void setIsCircle( const bool isCircle ) { mIsCircle = isCircle; }
+    inline bool getIsCircle( void ) const { return mIsCircle; }
+    inline void setCircleRadius( const F32 circleRadius ) { mCircleRadius = circleRadius; }
+    inline F32 getCircleRadius ( void ) const { return mCircleRadius; }
+
     Vector2 getBoxFromPoints( void );
 
     /// Internal Crunchers.
@@ -112,25 +108,15 @@ public:
 protected:
     static bool setPolyList(void* obj, const char* data)
     {
-       //Vector2 poly[b2_maxPolygonVertices];
-       U32 count = Utility::mGetStringElementCount(data) >> 1;
-       //for (U32 i = 0; i < count; i++)
-       //   poly[i] = Utility::mGetStringElementVector(data, i * 2);
-
+       const U32 count = Utility::mGetStringElementCount(data) >> 1;
        static_cast<ShapeVector*>(obj)->setPolyCustom(count, data);
        return false;
     }
     static bool writePolyList( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mPolygonBasisList.size() > 0; }
-
-    static bool setLineColor(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setLineColorString(data); return false; }
     static bool writeLineColor( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mLineColor != ColorF(1.0f,1.0f,1.0f,1.0f); }
-    static bool setFillColor(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setFillColorString(data); return false; }
     static bool writeFillColor( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mFillColor != ColorF(0.5f,0.5f,0.5f,1.0f); }
-    static bool setFillMode(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setFillMode(dAtob(data)); return false; }
     static bool writeFillMode( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mFillMode == true; }
-    static bool setIsCircle(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setIsCircle(dAtob(data)); return false; }
     static bool writeIsCircle( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mIsCircle == true; }
-    static bool setCircleRadius(void* obj, const char* data) { static_cast<ShapeVector*>(obj)->setCircleRadius(dAtof(data)); return false; }
     static bool writeCircleRadius( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mIsCircle != 1; }
 };
 

+ 166 - 33
engine/source/2d/sceneobject/ShapeVector_ScriptBinding.h

@@ -93,30 +93,97 @@ ConsoleMethod(ShapeVector, getWorldPoly, const char*, 2, 2, "() Gets Polygon poi
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, setLineColour, void, 3, 3, "(R / G / B / [A]) Sets the Rendering Line Color (identical to setLineColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
+ConsoleMethod(ShapeVector, setLineColor, void, 3, 6,    "(float red, float green, float blue, [float alpha = 1.0]) or ( stockColorName ) - Sets the line color."
+                                                        "@param red The red value.\n"
+                                                        "@param green The green value.\n"
+                                                        "@param blue The blue value.\n"
+                                                        "@param alpha The alpha value.\n"
+                                                        "@return No return Value.")
 {
-    // Set Line Color.
-    object->setLineColorString( argv[2] );
-}
+    // The colors.
+    F32 red;
+    F32 green;
+    F32 blue;
+    F32 alpha = 1.0f;
+
+    // Space separated.
+    if (argc == 3 )
+    {
+        // Grab the element count.
+        const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+        // Has a single argument been specified?
+        if ( elementCount == 1 )
+        {
+            // Set color.
+            Con::setData( TypeColorF, &const_cast<ColorF&>(object->getBlendColor()), 0, 1, &(argv[2]) );
+            return;
+        }
+
+        // ("R G B [A]")
+        if ((elementCount == 3) || (elementCount == 4))
+        {
+            // Extract the color.
+            red   = dAtof(Utility::mGetStringElement(argv[2], 0));
+            green = dAtof(Utility::mGetStringElement(argv[2], 1));
+            blue  = dAtof(Utility::mGetStringElement(argv[2], 2));
+
+            // Grab the alpha if it's there.
+            if (elementCount > 3)
+                alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
+        }
+
+        // Invalid.
+        else
+        {
+            Con::warnf("ShapeVector::setLineColor() - Invalid Number of parameters!");
+            return;
+        }
+    }
 
-//----------------------------------------------------------------------------
+    // (R, G, B)
+    else if (argc >= 5)
+    {
+        red   = dAtof(argv[2]);
+        green = dAtof(argv[3]);
+        blue  = dAtof(argv[4]);
 
-ConsoleMethod(ShapeVector, setLineColor, void, 3, 3, "(R / G / B / [A]) - Sets the Rendering Line Color(identical to setLineColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
-{
-    // Set Line Color.
-    object->setLineColorString( argv[2] );
+        // Grab the alpha if it's there.
+        if (argc > 5)
+            alpha = dAtof(argv[5]);
+    }
+
+    // Invalid.
+    else
+    {
+        Con::warnf("ShapeVector::setLineColor() - Invalid Number of parameters!");
+        return;
+    }
+
+    object->setLineColor( ColorF(red, green, blue, alpha) );
 }
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, getLineColor, const char*, 2, 2, "() Gets the Rendering Line Color.\n"
-              "@return Returns the fill color as a string formatted with \"Red Green Blue Alpha\"")
+ConsoleMethod(ShapeVector, getLineColor, const char*, 2, 3,     "(allowColorNames) Gets the fill color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
+                                                                "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    return object->getLineColor();
+    // Get line color.
+    ColorF color = object->getLineColor();
+
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &color, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return color.scriptThis();
 }
 
 //----------------------------------------------------------------------------
@@ -131,31 +198,97 @@ ConsoleMethod(ShapeVector, setLineAlpha, void, 3, 3, "(alpha) Sets the Rendering
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, setFillColour, void, 3, 3, "(R / G / B / [A]) Sets the Rendering Fill Color (identical to setFillColor).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value."
-              )
+ConsoleMethod(ShapeVector, setFillColor, void, 3, 3,    "(float red, float green, float blue, [float alpha = 1.0]) or ( stockColorName ) - Sets the fill color."
+                                                        "@param red The red value.\n"
+                                                        "@param green The green value.\n"
+                                                        "@param blue The blue value.\n"
+                                                        "@param alpha The alpha value.\n"
+                                                        "@return No return Value.")
 {
-    // Set Fill Color.
-    object->setLineColorString( argv[2] );
-}
+    // The colors.
+    F32 red;
+    F32 green;
+    F32 blue;
+    F32 alpha = 1.0f;
+
+    // Space separated.
+    if (argc == 3 )
+    {
+        // Grab the element count.
+        const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+        // Has a single argument been specified?
+        if ( elementCount == 1 )
+        {
+            // Set color.
+            Con::setData( TypeColorF, &const_cast<ColorF&>(object->getBlendColor()), 0, 1, &(argv[2]) );
+            return;
+        }
+
+        // ("R G B [A]")
+        if ((elementCount == 3) || (elementCount == 4))
+        {
+            // Extract the color.
+            red   = dAtof(Utility::mGetStringElement(argv[2], 0));
+            green = dAtof(Utility::mGetStringElement(argv[2], 1));
+            blue  = dAtof(Utility::mGetStringElement(argv[2], 2));
+
+            // Grab the alpha if it's there.
+            if (elementCount > 3)
+                alpha = dAtof(Utility::mGetStringElement(argv[2], 3));
+        }
+
+        // Invalid.
+        else
+        {
+            Con::warnf("ShapeVector::setFillColor() - Invalid Number of parameters!");
+            return;
+        }
+    }
 
-//----------------------------------------------------------------------------
+    // (R, G, B)
+    else if (argc >= 5)
+    {
+        red   = dAtof(argv[2]);
+        green = dAtof(argv[3]);
+        blue  = dAtof(argv[4]);
 
-ConsoleMethod(ShapeVector, setFillColor, void, 3, 3, "(R / G / B / [A]) - Sets the Rendering Fill Color (identical to setFillColour).\n"
-              "@param R/G/B/[A] Color values (0.0f - 1.0f) formatted as (\"Red Green Blue [Alpha]\"). Alpha is optional.\n"
-              "@return No return value.")
-{
-    // Set Fill Color.
-    object->setFillColorString( argv[2] );
+        // Grab the alpha if it's there.
+        if (argc > 5)
+            alpha = dAtof(argv[5]);
+    }
+
+    // Invalid.
+    else
+    {
+        Con::warnf("ShapeVector::setFillColor() - Invalid Number of parameters!");
+        return;
+    }
+
+    object->setFillColor( ColorF(red, green, blue, alpha) );
 }
 
 //----------------------------------------------------------------------------
 
-ConsoleMethod(ShapeVector, getFillColor, const char*, 2, 2, "() Gets the Rendering Fill Color.\n"
-              "@return Returns the fill color as a string formatted with \"Red Green Blue Alpha\"")
+ConsoleMethod(ShapeVector, getFillColor, const char*, 2, 3,     "(allowColorNames) Gets the fill color.\n"
+                                                                "@param allowColorNames Whether to allow stock color names to be returned or not.  Optional: Defaults to false.\n"
+                                                                "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
-    return object->getFillColor();
+    // Get line color.
+    ColorF color = object->getFillColor();
+
+    // Fetch allow color names flag.
+    const bool allowColorNames = (argc > 2) ? dAtob(argv[2] ) : false;
+
+    // Are color names allowed?
+    if ( allowColorNames )
+    {
+        // Yes, so fetch the field value.
+        return Con::getData( TypeColorF, &color, 0 );
+    }
+
+    // No, so fetch the raw color values.
+    return color.scriptThis();
 }
 
 //----------------------------------------------------------------------------

+ 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],

+ 0 - 1
engine/source/2d/sceneobject/Sprite.h

@@ -60,7 +60,6 @@ public:
 protected:
     static bool writeFlipX( void* obj, StringTableEntry pFieldName )        { return static_cast<Sprite*>(obj)->getFlipX() == true; }
     static bool writeFlipY( void* obj, StringTableEntry pFieldName )        { return static_cast<Sprite*>(obj)->getFlipY() == true; }
-
 };
 
 #endif // _SPRITE_H_

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 353 - 358
engine/source/component/behaviors/behaviorComponent.cpp

@@ -35,17 +35,18 @@
 #include "persistence/taml/tamlCustom.h"
 #endif
 
+#ifndef _TAML_H_
+#include "persistence/Taml/taml.h"
+#endif
+
 // Script bindings.
 #include "behaviorComponent_ScriptBinding.h"
 
 //-----------------------------------------------------------------------------
 
-#define BEHAVIOR_FIELDNAME              "Behavior"
-#define BEHAVIOR_CONNECTION_FIELDNAME   "BehaviorConnection"
-
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT( BehaviorComponent );
+#define BEHAVIOR_ID_FIELD_NAME                  "Id"
+#define BEHAVIOR_NODE_NAME                      "Behaviors"
+#define BEHAVIOR_CONNECTION_TYPE_NAME           "Connection"
 
 //-----------------------------------------------------------------------------
 
@@ -886,6 +887,183 @@ const BehaviorComponent::typePortConnectionVector* BehaviorComponent::getBehavio
 
 //-----------------------------------------------------------------------------
 
+void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
+{
+    // Export selected only?
+    if( ( flags & SelectedOnly ) && !isSelected() )
+    {
+        return;
+    }
+
+    if( mBehaviors.size() == 0 )
+    {
+        Parent::write( stream, tabStop, flags );
+        return;
+    }
+
+    // The work we want to perform here is in the Taml callback.
+    onTamlPreWrite();
+
+    // Write object.
+    Parent::write( stream, tabStop, flags );
+
+    // The work we want to perform here is in the Taml callback.
+    onTamlPostWrite();
+}
+
+//-----------------------------------------------------------------------------
+
+bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
+{
+
+   // CodeReview [6/25/2007 justind]
+   // If we're deleting the BehaviorComponent, don't forward the call to the
+   // behaviors, the parent onRemove will handle freeing them
+   // This should really be handled better, and is in the Parent implementation
+   // but behaviors are a special case because they always want to be called BEFORE
+   // the parent to act.
+   if( dStricmp( fname, "delete" ) == 0 )
+      return Parent::handlesConsoleMethod( fname, routingId );
+
+   for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
+   {
+      SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
+      if( pComponent != NULL && pComponent->isMethod( fname ) )
+      {
+         *routingId = -2; // -2 denotes method on component
+         return true;
+      }
+   }
+
+   // Let parent handle it
+   return Parent::handlesConsoleMethod( fname, routingId );
+}
+
+//-----------------------------------------------------------------------------
+
+// Needed to be able to directly call execute on a Namespace::Entry
+extern ExprEvalState gEvalState;
+
+const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
+{   
+    if( mBehaviors.empty() )   
+        return Parent::callOnBehaviors( argc, argv );
+      
+    // Copy the arguments to avoid weird clobbery situations.
+    FrameTemp<char *> argPtrs (argc);
+   
+    U32 strdupWatermark = FrameAllocator::getWaterMark();
+    for( U32 i = 0; i < argc; i++ )
+    {
+        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
+        dStrcpy( argPtrs[i], argv[i] );
+    }
+
+    // Walk backwards through the list just as with components
+    const char* result = "";
+    bool handled = false;
+    for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
+    {
+        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
+        AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
+        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
+
+        // Use the BehaviorInstance's namespace
+        Namespace *pNamespace = pBehavior->getNamespace();
+        if(!pNamespace)
+            continue;
+
+        // Lookup the Callback Namespace entry and then splice callback
+        const char *cbName = StringTable->insert(argv[0]);
+        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
+        if( pNSEntry )
+        {
+            // Set %this to our BehaviorInstance's Object ID
+            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
+
+            // Change the Current Console object, execute, restore Object
+            SimObject *save = gEvalState.thisObject;
+            gEvalState.thisObject = pBehavior;
+
+            result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
+
+            gEvalState.thisObject = save;
+            handled = true;
+            break;
+        }
+    }
+
+    // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
+    // to deal with it.  If the parent cannot handle the message it will return an error string.
+    if (!handled)
+    {
+        result = Parent::callOnBehaviors( argc, argv );
+    }
+
+    // Clean up.
+    FrameAllocator::setWaterMark( strdupWatermark );
+
+    return result;
+}
+
+//-----------------------------------------------------------------------------
+
+const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true  */ )
+{   
+    if( mBehaviors.empty() )   
+        return Parent::_callMethod( argc, argv, callThis );
+     
+    // Copy the arguments to avoid weird clobbery situations.
+    FrameTemp<char *> argPtrs (argc);
+   
+    U32 strdupWatermark = FrameAllocator::getWaterMark();
+    for( U32 i = 0; i < argc; i++ )
+    {
+        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
+        dStrcpy( argPtrs[i], argv[i] );
+    }
+
+    for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
+    {
+        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
+        AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
+        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
+
+        // Use the BehaviorInstance's namespace
+        Namespace *pNamespace = pBehavior->getNamespace();
+        if(!pNamespace)
+            continue;
+
+        // Lookup the Callback Namespace entry and then splice callback
+        const char *cbName = StringTable->insert(argv[0]);
+        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
+        if( pNSEntry )
+        {
+            // Set %this to our BehaviorInstance's Object ID
+            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
+
+            // Change the Current Console object, execute, restore Object
+            SimObject *save = gEvalState.thisObject;
+            gEvalState.thisObject = pBehavior;
+
+            pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
+
+            gEvalState.thisObject = save;
+        }
+    }
+
+    // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
+    // it needs to be able to contain other components and behave properly
+    const char* fnRet = Parent::_callMethod( argc, argv, callThis );
+
+    // Clean up.
+    FrameAllocator::setWaterMark( strdupWatermark );
+
+    return fnRet;
+}
+
+//-----------------------------------------------------------------------------
+
 void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
     // Call parent.
@@ -952,10 +1130,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 +1150,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,408 +1191,228 @@ 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() );
-
-                // Skip it.
-                continue;
-            }
+                // Fetch field nodes.
+                const TamlCustomFieldVector& connectionFieldNodes = pBehaviorNode->getFields();
 
-            // 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;
-
-                    /// Skip it.
-                    continue;
+                    // Assign output/input appropriately.
+                    pOutputInstance = pBehaviorInstance1;
+                    pInputInstance = pBehaviorInstance2;
+                    outputName = behaviorFieldName1;
+                    inputName = behaviorFieldName2;
                 }
-
-                // 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 )
+                // Is the output on behavior instance #2?
+                else if ( pBehaviorInstance2->getTemplate()->hasBehaviorOutput( behaviorFieldName2 ) )
                 {
-                    // Yes, so update field type.
-                    fieldType = TypeAssetId;
-                }
-
-                // Set field.
-                pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
-            }
-
-            // 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 );
-        }
-
-        // Set master as next behavior id.
-        mMasterBehaviorId = (U32)maximumBehaviorId+1;
-    }
-
-    // Find behavior connections custom node.
-    const TamlCustomNode* pCustomConnectionNode = customNodes.findNode( BEHAVIOR_CONNECTION_NODE_NAME );
-
-    // 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 );
-
-        // Fetch children connection nodes.
-        const TamlCustomNodeVector& connectionNodes = pCustomConnectionNode->getChildren();
-
-        // Iterate property alias.
-        for( TamlCustomNodeVector::const_iterator connectionNodeItr = connectionNodes.begin(); connectionNodeItr != connectionNodes.end(); ++connectionNodeItr )
-        {
-            // Fetch connection node.
-            TamlCustomNode* pConnectionNode = *connectionNodeItr;
-
-            // Skip if the alias isn't a connection.
-            if ( pConnectionNode->getNodeName() != connectionNodeName )
-                continue;
-
-            // Fetch field nodes.
-            const TamlCustomFieldVector& connectionFieldNodes = pConnectionNode->getFields();
-
-            // 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 property field #1.
-            TamlCustomField* pPropertyField1 = *connectionFieldNodes.begin();
-            TamlCustomField* pPropertyField2 = *(connectionFieldNodes.begin()+1);
-           
-            // Fetch behavior instances #1.
-            BehaviorInstance* pBehaviorInstance1 = getBehaviorByInstanceId( dAtoi( pPropertyField1->getFieldValue() ) );
-
-            // 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 behavior instances #2.
-            BehaviorInstance* pBehaviorInstance2 = getBehaviorByInstanceId( dAtoi( pPropertyField2->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;
-            }
-
-            // Fetch behavior fields.
-            StringTableEntry behaviorFieldName1 = pPropertyField1->getFieldName();
-            StringTableEntry behaviorFieldName2 = pPropertyField2->getFieldName();
-
-            BehaviorInstance* pOutputInstance;
-            BehaviorInstance* pInputInstance;
-            StringTableEntry outputName;
-            StringTableEntry inputName;
+                    // 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;
+                    }
 
-            // 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 ) )
+                    // Assign output/input appropriately.
+                    pOutputInstance = pBehaviorInstance2;
+                    pInputInstance = pBehaviorInstance1;
+                    outputName = behaviorFieldName2;
+                    inputName = behaviorFieldName1;
+                }
+                else
                 {
-                    // No, so warn.
-                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
+                    // Warn.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Invalid output/input on behavior connection '%s=%s' & '%s=%s''.",
+                        behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
                         behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
                     continue;
                 }
 
-                // 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 ) )
+                // Can we connect?
+                if ( !connect( pOutputInstance, pInputInstance, outputName, inputName ) )
                 {
                     // No, so warn.
-                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Could not find a behavior input '%s' on behavior '%s'.",
-                        behaviorFieldName1, pBehaviorInstance1->getTemplateName() );
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Failed to connect behaviors '%s=%s' & '%s=%s''.",
+                        behaviorFieldName1, pBehaviorInstance1->getTemplateName(),
+                        behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
                     continue;
                 }
-
-                // 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 template.
+                BehaviorTemplate* pTemplate = dynamic_cast<BehaviorTemplate *>( Sim::findObject( pBehaviorNode->getNodeName() ) );
 
-            // 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;
-            }
-        }
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void BehaviorComponent::write( Stream &stream, U32 tabStop, U32 flags /* = 0 */ )
-{
-    // Export selected only?
-    if( ( flags & SelectedOnly ) && !isSelected() )
-    {
-        return;
-    }
+                // Find template?
+                if( pTemplate == NULL )
+                {
+                    // No, so warn appropriately.
+                    Con::warnf( "BehaviorComponent::onTamlCustomRead() - Missing Behavior '%s'", pBehaviorNode->getNodeName() );
 
-    if( mBehaviors.size() == 0 )
-    {
-        Parent::write( stream, tabStop, flags );
-        return;
-    }
+                    if( isMethod( "onBehaviorMissing" ) )
+                        Con::executef( this, 2, "onBehaviorMissing", pBehaviorNode->getNodeName() );
 
-    // The work we want to perform here is in the Taml callback.
-    onTamlPreWrite();
+                    // Skip it.
+                    continue;
+                }
 
-    // Write object.
-    Parent::write( stream, tabStop, flags );
+                // Create an instance of the template.
+                BehaviorInstance* pBehaviorInstance = pTemplate->createInstance();
 
-    // The work we want to perform here is in the Taml callback.
-    onTamlPostWrite();
-}
+                // 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() );
 
-bool BehaviorComponent::handlesConsoleMethod( const char *fname, S32 *routingId )
-{
+                    // Skip it.
+                    continue;
+                }
 
-   // CodeReview [6/25/2007 justind]
-   // If we're deleting the BehaviorComponent, don't forward the call to the
-   // behaviors, the parent onRemove will handle freeing them
-   // This should really be handled better, and is in the Parent implementation
-   // but behaviors are a special case because they always want to be called BEFORE
-   // the parent to act.
-   if( dStricmp( fname, "delete" ) == 0 )
-      return Parent::handlesConsoleMethod( fname, routingId );
+                S32 behaviorId = 0;
 
-   for( SimSet::iterator nItr = mBehaviors.begin(); nItr != mBehaviors.end(); nItr++ )
-   {
-      SimObject *pComponent = dynamic_cast<SimObject *>(*nItr);
-      if( pComponent != NULL && pComponent->isMethod( fname ) )
-      {
-         *routingId = -2; // -2 denotes method on component
-         return true;
-      }
-   }
+                // Fetch field nodes.
+                const TamlCustomFieldVector& fields = pBehaviorNode->getFields();
 
-   // Let parent handle it
-   return Parent::handlesConsoleMethod( fname, routingId );
-}
+                // Iterate fields.
+                for ( TamlCustomFieldVector::const_iterator nodeFieldItr = fields.begin(); nodeFieldItr != fields.end(); ++nodeFieldItr )
+                {
+                    // Fetch field.
+                    TamlCustomField* pField = *nodeFieldItr;
 
-//-----------------------------------------------------------------------------
+                    // Fetch field name.
+                    const char* pFieldName = pField->getFieldName();
 
-// Needed to be able to directly call execute on a Namespace::Entry
-extern ExprEvalState gEvalState;
+                    // Fetch field value.
+                    const char* pFieldValue = pField->getFieldValue();
 
-const char *BehaviorComponent::callOnBehaviors( U32 argc, const char *argv[] )
-{   
-    if( mBehaviors.empty() )   
-        return Parent::callOnBehaviors( argc, argv );
-      
-    // Copy the arguments to avoid weird clobbery situations.
-    FrameTemp<char *> argPtrs (argc);
-   
-    U32 strdupWatermark = FrameAllocator::getWaterMark();
-    for( U32 i = 0; i < argc; i++ )
-    {
-        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
-        dStrcpy( argPtrs[i], argv[i] );
-    }
+                    // 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;
+                    }
 
-    // Walk backwards through the list just as with components
-    const char* result = "";
-    bool handled = false;
-    for( SimSet::iterator i = (mBehaviors.end()-1); i >= mBehaviors.begin(); i-- )
-    {
-        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
-        AssertFatal( pBehavior, "BehaviorComponent::callOnBehaviors - Bad behavior instance in list." );
-        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
+                    // Fetch behavior field.
+                    BehaviorTemplate::BehaviorField* pBehaviorField = pTemplate->getBehaviorField( pFieldName );
 
-        // Use the BehaviorInstance's namespace
-        Namespace *pNamespace = pBehavior->getNamespace();
-        if(!pNamespace)
-            continue;
+                    // Set default field type.
+                    S32 fieldType = -1;
 
-        // Lookup the Callback Namespace entry and then splice callback
-        const char *cbName = StringTable->insert(argv[0]);
-        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
-        if( pNSEntry )
-        {
-            // Set %this to our BehaviorInstance's Object ID
-            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
+                    // Is this an asset field type?
+                    if ( pBehaviorField != NULL && pBehaviorField->mType == behaviorTemplateAssetFieldType )
+                    {
+                        // Yes, so update field type.
+                        fieldType = TypeAssetId;
+                    }
 
-            // Change the Current Console object, execute, restore Object
-            SimObject *save = gEvalState.thisObject;
-            gEvalState.thisObject = pBehavior;
+                    // Set field.
+                    pBehaviorInstance->setPrefixedDynamicDataField( pField->getFieldName(), NULL, pField->getFieldValue(), fieldType );
+                }
 
-            result = pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
+                // Add behavior.
+                addBehavior( pBehaviorInstance );
 
-            gEvalState.thisObject = save;
-            handled = true;
-            break;
+                // Override the automatically allocated behavior Id when adding the behavior.
+                // NOTE: This must be done after adding the behavior.
+                pBehaviorInstance->setBehaviorId( behaviorId );
+            }
         }
-    }
 
-    // If this wasn't handled by a behavior above then pass along to the parent DynamicConsoleMethodComponent
-    // to deal with it.  If the parent cannot handle the message it will return an error string.
-    if (!handled)
-    {
-        result = Parent::callOnBehaviors( argc, argv );
+        // Set master as next behavior id.
+        mMasterBehaviorId = (U32)maximumBehaviorId+1;
     }
-
-    // Clean up.
-    FrameAllocator::setWaterMark( strdupWatermark );
-
-    return result;
 }
 
 //-----------------------------------------------------------------------------
 
-const char *BehaviorComponent::_callMethod( U32 argc, const char *argv[], bool callThis /* = true  */ )
-{   
-    if( mBehaviors.empty() )   
-        return Parent::_callMethod( argc, argv, callThis );
-     
-    // Copy the arguments to avoid weird clobbery situations.
-    FrameTemp<char *> argPtrs (argc);
-   
-    U32 strdupWatermark = FrameAllocator::getWaterMark();
-    for( U32 i = 0; i < argc; i++ )
-    {
-        argPtrs[i] = reinterpret_cast<char *>( FrameAllocator::alloc( dStrlen( argv[i] ) + 1 ) );
-        dStrcpy( argPtrs[i], argv[i] );
-    }
-
-    for( SimSet::iterator i = mBehaviors.begin(); i != mBehaviors.end(); i++ )
-    {
-        BehaviorInstance *pBehavior = dynamic_cast<BehaviorInstance *>( *i );
-        AssertFatal( pBehavior, "BehaviorComponent::_callMethod - Bad behavior instance in list." );
-        AssertFatal( pBehavior->getId() > 0, "Invalid id for behavior component" );
-
-        // Use the BehaviorInstance's namespace
-        Namespace *pNamespace = pBehavior->getNamespace();
-        if(!pNamespace)
-            continue;
-
-        // Lookup the Callback Namespace entry and then splice callback
-        const char *cbName = StringTable->insert(argv[0]);
-        Namespace::Entry *pNSEntry = pNamespace->lookup(cbName);
-        if( pNSEntry )
-        {
-            // Set %this to our BehaviorInstance's Object ID
-            argPtrs[1] = const_cast<char *>( pBehavior->getIdString() );
-
-            // Change the Current Console object, execute, restore Object
-            SimObject *save = gEvalState.thisObject;
-            gEvalState.thisObject = pBehavior;
-
-            pNSEntry->execute(argc, const_cast<const char **>( ~argPtrs ), &gEvalState);
-
-            gEvalState.thisObject = save;
-        }
-    }
+static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement )
+{
+    // Sanity!
+    AssertFatal( pClassRep != NULL,  "BehaviorComponent::WriteCustomTamlSchema() - ClassRep cannot be NULL." );
+    AssertFatal( pParentElement != NULL,  "BehaviorComponent::WriteCustomTamlSchema() - Parent Element cannot be NULL." );
 
-    // Pass this up to the parent since a BehaviorComponent is still a DynamicConsoleMethodComponent
-    // it needs to be able to contain other components and behave properly
-    const char* fnRet = Parent::_callMethod( argc, argv, callThis );
+    // Write an unrestricted custom Taml schema.
+    Taml::WriteUnrestrictedCustomTamlSchema( BEHAVIOR_NODE_NAME, pClassRep, pParentElement );
+}
 
-    // Clean up.
-    FrameAllocator::setWaterMark( strdupWatermark );
+//-----------------------------------------------------------------------------
 
-    return fnRet;
-}
+IMPLEMENT_CONOBJECT_SCHEMA( BehaviorComponent, WriteCustomTamlSchema );

+ 0 - 7
engine/source/component/behaviors/behaviorComponent.h

@@ -33,13 +33,6 @@
 
 //-----------------------------------------------------------------------------
 
-#define BEHAVIOR_ID_FIELD_NAME                  "Id"
-#define BEHAVIOR_NODE_NAME                      "Behaviors"
-#define BEHAVIOR_CONNECTION_NODE_NAME           "BehaviorConnections"
-#define BEHAVIOR_CONNECTION_TYPE_NAME           "Connection"
-
-//-----------------------------------------------------------------------------
-
 class BehaviorComponent : public DynamicConsoleMethodComponent
 {
     friend class BehaviorInterface;

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

+ 30 - 42
engine/source/graphics/color.cc

@@ -48,35 +48,6 @@ static typeColorIToNameHash    mColorIToName;
 
 //-----------------------------------------------------------------------------
 
-class StockColorItem
-{
-private:
-    StockColorItem() {}
-
-public:
-    StockColorItem( const char* pName, const U8 red, const U8 green, const U8 blue, const U8 alpha = 255 )
-    {
-        // Sanity!
-        AssertFatal( pName != NULL, "Stock color name cannot be NULL." );
-
-        // Set stock color.
-        // NOTE:-   We'll use the char pointer here.  We can yet use the string-table unfortunately.
-        mColorName = pName;
-        mColorI.set( red, green, blue, alpha );
-        mColorF = mColorI;
-    }
-
-    inline const char*      getColorName( void ) const { return mColorName; }
-    inline const ColorF&    getColorF( void ) const { return mColorF; }
-    inline const ColorI&    getColorI( void ) const { return mColorI; }
-
-    const char*         mColorName;
-    ColorF              mColorF;
-    ColorI              mColorI;
-};
-
-//-----------------------------------------------------------------------------
-
 StockColorItem StockColorTable[] =
 {
     StockColorItem( "InvisibleBlack", 0, 0, 0, 0 ),
@@ -368,6 +339,32 @@ StringTableEntry StockColor::name( const ColorI& color )
 
 //-----------------------------------------------------------------------------
 
+S32 StockColor::getCount( void )
+{
+    return sizeof(StockColorTable) / sizeof(StockColorItem);
+}
+
+//-----------------------------------------------------------------------------
+
+const StockColorItem* StockColor::getColorItem( const S32 index )
+{
+    // Fetch stock color count.
+    const S32 stockColorCount = StockColor::getCount();
+
+    // Is the stock color index in range?
+    if ( index < 0 || index >= stockColorCount )
+    {
+        // No, so warn.
+        Con::warnf("StockColor::getName() - Specified color index '%d' is out of range.  Range is 0 to %d.", index, stockColorCount-1 );
+        return NULL;
+    }
+
+    // Return color name.
+    return &(StockColorTable[index]);
+}
+
+//-----------------------------------------------------------------------------
+
 ColorF::ColorF( const char* pStockColorName )
 {
     // Set stock color.
@@ -582,7 +579,7 @@ ConsoleSetType( TypeColorI )
 ConsoleFunction( getStockColorCount, S32, 1, 1, "() - Gets a count of available stock colors.\n"
                                                 "@return A count of available stock colors." )
 {
-    return sizeof(StockColorTable) / sizeof(StockColorItem);
+    return StockColor::getCount();
 }
 
 //-----------------------------------------------------------------------------
@@ -594,19 +591,10 @@ ConsoleFunction( getStockColorName, const char*, 2, 2,  "(stockColorIndex) - Get
     // Fetch stock color index.
     const S32 stockColorIndex = dAtoi(argv[1]);
 
-    // Fetch stock color count.
-    const S32 stockColorCount = sizeof(StockColorTable) / sizeof(StockColorItem);
+    // Fetch the color item.
+    const StockColorItem* pColorItem = StockColor::getColorItem( stockColorIndex );
 
-    // Is the stock color index in range?
-    if ( stockColorIndex < 0 || stockColorIndex >= stockColorCount )
-    {
-        // No, so warn.
-        Con::warnf("getStockColorName() - Specified color index '%d' is out of range.  Range is 0 to %d.", stockColorIndex, stockColorCount-1 );
-        return StringTable->EmptyString;
-    }
-
-    // Return color name.
-    return StockColorTable[stockColorIndex].getColorName();
+    return pColorItem == NULL ? NULL : pColorItem->getColorName();
 }
 
 //-----------------------------------------------------------------------------

+ 40 - 0
engine/source/graphics/color.h

@@ -36,6 +36,7 @@
 DefineConsoleType( TypeColorI )
 DefineConsoleType( TypeColorF )
 
+
 //-----------------------------------------------------------------------------
 
 class ColorI;
@@ -110,6 +111,9 @@ class ColorF
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (alpha >= 0.0f && alpha <= 1.0f); }
    void clamp();
+
+   inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%f %f %f %f", red, green, blue, alpha ); return StringTable->insert(buffer); }
+   inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%.5f %.5f %.5f %.5f", red, green, blue, alpha ); return pBuffer; }
 };
 
 //-----------------------------------------------------------------------------
@@ -174,6 +178,39 @@ class ColorI
 
    U16 get565()  const;
    U16 get4444() const;
+
+   inline StringTableEntry stringThis(void) const   { char buffer[64]; dSprintf(buffer, 64, "%d %d %d %d", red, green, blue, alpha ); return StringTable->insert(buffer); }
+   inline const char* scriptThis(void) const        { char* pBuffer = Con::getReturnBuffer(64); dSprintf(pBuffer, 32, "%d %d %d %d", red, green, blue, alpha ); return pBuffer; }
+};
+
+
+//-----------------------------------------------------------------------------
+
+class StockColorItem
+{
+private:
+    StockColorItem() {}
+
+public:
+    StockColorItem( const char* pName, const U8 red, const U8 green, const U8 blue, const U8 alpha = 255 )
+    {
+        // Sanity!
+        AssertFatal( pName != NULL, "Stock color name cannot be NULL." );
+
+        // Set stock color.
+        // NOTE:-   We'll use the char pointer here.  We can yet use the string-table unfortunately.
+        mColorName = pName;
+        mColorI.set( red, green, blue, alpha );
+        mColorF = mColorI;
+    }
+
+    inline const char*      getColorName( void ) const { return mColorName; }
+    inline const ColorF&    getColorF( void ) const { return mColorF; }
+    inline const ColorI&    getColorI( void ) const { return mColorI; }
+
+    const char*         mColorName;
+    ColorF              mColorF;
+    ColorI              mColorI;
 };
 
 //-----------------------------------------------------------------------------
@@ -187,6 +224,9 @@ public:
     static StringTableEntry name( const ColorF& color );
     static StringTableEntry name( const ColorI& color );
 
+    static S32 getCount( void );
+    static const StockColorItem* getColorItem( const S32 index );
+
     static void create( void );
     static void destroy( void );
 };

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

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff