ソースを参照

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

MichPerry-GG 12 年 前
コミット
3cdb5b5f55
100 ファイル変更6180 行追加4339 行削除
  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>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc" />
     <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\ImageAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
@@ -246,15 +245,17 @@
     <ClCompile Include="..\..\source\2d\controllers\PointForceController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\PointForceController.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\CoreMath.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\ParticleSystem.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.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\Utility.cc" />
     <ClCompile Include="..\..\source\2d\core\Vector2.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\guiImageButtonCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
@@ -281,7 +282,6 @@
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
@@ -611,7 +611,6 @@
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
@@ -633,6 +632,8 @@
     <ClInclude Include="..\..\source\2d\controllers\PointForceController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\controllers\PointForceController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\CoreMath.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\ParticleSystem.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy_ScriptBinding.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\SpriteBatchItem.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.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\Utility.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />
@@ -702,7 +704,6 @@
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\declaredAssets.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">
     <Filter Include="2d\controllers\core">
       <UniqueIdentifier>{6aeaed85-4546-4496-8415-72a392e830ba}</UniqueIdentifier>
       <UniqueIdentifier>{6aeaed85-4546-4496-8415-72a392e830ba}</UniqueIdentifier>
     </Filter>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -711,9 +717,6 @@
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc">
-      <Filter>assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\assets\assetBase.cc">
     <ClCompile Include="..\..\source\assets\assetBase.cc">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClCompile>
     </ClCompile>
@@ -1122,9 +1125,6 @@
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc">
-      <Filter>2d\assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClCompile>
     </ClCompile>
@@ -1161,9 +1161,6 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc">
-      <Filter>2d\core</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </ClCompile>
@@ -1299,6 +1296,15 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -1910,9 +1916,6 @@
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
       <Filter>module</Filter>
       <Filter>module</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h">
-      <Filter>assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\assets\assetBase.h">
     <ClInclude Include="..\..\source\assets\assetBase.h">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClInclude>
     </ClInclude>
@@ -2351,9 +2354,6 @@
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClInclude>
     </ClInclude>
@@ -2426,9 +2426,6 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h">
-      <Filter>2d\core</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\core\Utility.h">
     <ClInclude Include="..\..\source\2d\core\Utility.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </ClInclude>
@@ -2667,6 +2664,18 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </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>
   <ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">

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

@@ -240,7 +240,6 @@
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc" />
     <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\ImageAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
@@ -253,15 +252,17 @@
     <ClCompile Include="..\..\source\2d\controllers\BuoyancyController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\BuoyancyController.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\BatchRender.cc" />
     <ClCompile Include="..\..\source\2d\core\CoreMath.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\ParticleSystem.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\RenderProxy.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBase.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatch.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc" />
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.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\Utility.cc" />
     <ClCompile Include="..\..\source\2d\core\Vector2.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\guiImageButtonCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSceneObjectCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
     <ClCompile Include="..\..\source\2d\gui\guiSpriteCtrl.cc" />
@@ -288,7 +289,6 @@
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetFieldTypes.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetManager.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
     <ClCompile Include="..\..\source\assets\assetQuery.cc" />
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\declaredAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
     <ClCompile Include="..\..\source\assets\referencedAssets.cc" />
@@ -618,7 +618,6 @@
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ImageAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset.h" />
@@ -640,6 +639,8 @@
     <ClInclude Include="..\..\source\2d\controllers\BuoyancyController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\controllers\BuoyancyController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\BatchRender.h" />
     <ClInclude Include="..\..\source\2d\core\CoreMath.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\ParticleSystem.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy.h" />
     <ClInclude Include="..\..\source\2d\core\RenderProxy_ScriptBinding.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\SpriteBatchItem.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQuery.h" />
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.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\Utility.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2.h" />
     <ClInclude Include="..\..\source\2d\core\Vector2_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiImageButtonCtrl_ScriptBindings.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />
     <ClInclude Include="..\..\source\2d\gui\guiSceneObjectCtrl.h" />
@@ -708,7 +710,6 @@
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetPtr.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery.h" />
     <ClInclude Include="..\..\source\assets\assetQuery_ScriptBinding.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.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\assetTagsManifest_ScriptBinding.h" />
     <ClInclude Include="..\..\source\assets\declaredAssets.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">
     <Filter Include="2d\controllers\core">
       <UniqueIdentifier>{e11e344e-6418-4ed0-980a-77d66cd64d65}</UniqueIdentifier>
       <UniqueIdentifier>{e11e344e-6418-4ed0-980a-77d66cd64d65}</UniqueIdentifier>
     </Filter>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -711,9 +717,6 @@
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
     <ClCompile Include="..\..\source\assets\assetTagsManifest.cc">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\assets\assetSnapshot.cc">
-      <Filter>assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\assets\assetBase.cc">
     <ClCompile Include="..\..\source\assets\assetBase.cc">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClCompile>
     </ClCompile>
@@ -1122,9 +1125,6 @@
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
     <ClCompile Include="..\..\source\2d\assets\AnimationAsset.cc">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\assets\AnimationController.cc">
-      <Filter>2d\assets</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
     <ClCompile Include="..\..\source\2d\assets\ImageAsset.cc">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClCompile>
     </ClCompile>
@@ -1161,9 +1161,6 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
     <ClCompile Include="..\..\source\2d\core\SpriteBatchItem.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\core\SpriteProxyBase.cc">
-      <Filter>2d\core</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
     <ClCompile Include="..\..\source\2d\core\Utility.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </ClCompile>
@@ -1299,6 +1296,15 @@
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
     <ClCompile Include="..\..\source\2d\core\SpriteBatchQuery.cc">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClCompile>
     </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>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -1910,9 +1916,6 @@
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
     <ClInclude Include="..\..\source\module\moduleCallbacks.h">
       <Filter>module</Filter>
       <Filter>module</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\assets\assetSnapshot.h">
-      <Filter>assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\assets\assetBase.h">
     <ClInclude Include="..\..\source\assets\assetBase.h">
       <Filter>assets</Filter>
       <Filter>assets</Filter>
     </ClInclude>
     </ClInclude>
@@ -2351,9 +2354,6 @@
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
     <ClInclude Include="..\..\source\2d\assets\AnimationAsset_ScriptBinding.h">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\AnimationController.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
     <ClInclude Include="..\..\source\2d\assets\ImageAsset.h">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClInclude>
     </ClInclude>
@@ -2423,9 +2423,6 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
     <ClInclude Include="..\..\source\2d\core\SpriteBatchItem.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\core\SpriteProxyBase.h">
-      <Filter>2d\core</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\2d\core\Utility.h">
     <ClInclude Include="..\..\source\2d\core\Utility.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </ClInclude>
@@ -2664,6 +2661,18 @@
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
     <ClInclude Include="..\..\source\2d\core\SpriteBatchQueryResult.h">
       <Filter>2d\core</Filter>
       <Filter>2d\core</Filter>
     </ClInclude>
     </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>
   <ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
     <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 */; };
 		2A033011165D1D4100E9CD70 /* platformFileIoTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A033010165D1D4100E9CD70 /* platformFileIoTests.cc */; };
 		2A25739016A48DAC00363C6F /* ParticlePlayer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A25738E16A48DAC00363C6F /* ParticlePlayer.cc */; };
 		2A25739016A48DAC00363C6F /* ParticlePlayer.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A25738E16A48DAC00363C6F /* ParticlePlayer.cc */; };
 		2A6F78CE16A4528C005C76D9 /* ParticleAssetEmitter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2A6F78CC16A4528C005C76D9 /* ParticleAssetEmitter.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 */; };
 		2AA6865F16D69943003CEF0A /* SceneObjectList.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6865A16D69943003CEF0A /* SceneObjectList.cc */; };
 		2AA6866016D69943003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6865D16D69943003CEF0A /* SceneObjectSet.cc */; };
 		2AA6866016D69943003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6865D16D69943003CEF0A /* SceneObjectSet.cc */; };
 		2AB14A0516D7CDC300EABBF2 /* PointForceController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB14A0316D7CDC200EABBF2 /* PointForceController.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 */; };
 		2ACFC0A8166CE1AB00FE7370 /* platformMemoryTests.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ACFC0A7166CE1AB00FE7370 /* platformMemoryTests.cc */; };
 		2ADCAC1516A41E5500E07619 /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ADCAC1116A41E5500E07619 /* ParticleAsset.cc */; };
 		2ADCAC1516A41E5500E07619 /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ADCAC1116A41E5500E07619 /* ParticleAsset.cc */; };
 		2ADCAC1716A41E5500E07619 /* ParticleAssetField.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ADCAC1316A41E5500E07619 /* ParticleAssetField.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 */; };
 		2AE2F55D16D6B08800B6A058 /* BuoyancyController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2F55B16D6B08800B6A058 /* BuoyancyController.cc */; };
 		2AE5B54216A6D860006908D5 /* ParticleAssetFieldCollection.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5B54016A6D860006908D5 /* ParticleAssetFieldCollection.cc */; };
 		2AE5B54216A6D860006908D5 /* ParticleAssetFieldCollection.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE5B54016A6D860006908D5 /* ParticleAssetFieldCollection.cc */; };
 		2AE851D21681E56E00193F17 /* color.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE851D11681E56E00193F17 /* color.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 */; };
 		86C281CD16A4307E00F030F4 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 86C281CB16A4307E00F030F4 /* MainMenu.xib */; };
 		86D76F78165683240046D71F /* osxOutlineGL.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86D76F76165683240046D71F /* osxOutlineGL.cc */; };
 		86D76F78165683240046D71F /* osxOutlineGL.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86D76F76165683240046D71F /* osxOutlineGL.cc */; };
 		86D76F791656868D0046D71F /* AnimationAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E7716518D4600D96ADF /* AnimationAsset.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 */; };
 		86D76F7B1656868D0046D71F /* ImageAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E7C16518D4600D96ADF /* ImageAsset.cc */; };
 		86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8116518D4600D96ADF /* BatchRender.cc */; };
 		86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8116518D4600D96ADF /* BatchRender.cc */; };
 		86D76F7D1656868D0046D71F /* CoreMath.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8316518D4600D96ADF /* CoreMath.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 */; };
 		86D76F7F1656868D0046D71F /* SpriteBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8816518D4600D96ADF /* SpriteBase.cc */; };
 		86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8B16518D4600D96ADF /* SpriteBatch.cc */; };
 		86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8B16518D4600D96ADF /* SpriteBatch.cc */; };
 		86D76F811656868D0046D71F /* SpriteBatchItem.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E8D16518D4600D96ADF /* SpriteBatchItem.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 */; };
 		86D76F831656868D0046D71F /* Utility.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9116518D4600D96ADF /* Utility.cc */; };
 		86D76F841656868D0046D71F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9316518D4600D96ADF /* Vector2.cc */; };
 		86D76F841656868D0046D71F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9316518D4600D96ADF /* Vector2.cc */; };
 		86D76F851656868D0046D71F /* guiImageButtonCtrl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7E9716518D4600D96ADF /* guiImageButtonCtrl.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 */; };
 		86D76F9C165686D80046D71F /* assetFieldTypes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EEC16518D4600D96ADF /* assetFieldTypes.cc */; };
 		86D76F9D165686D80046D71F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EEE16518D4600D96ADF /* assetManager.cc */; };
 		86D76F9D165686D80046D71F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EEE16518D4600D96ADF /* assetManager.cc */; };
 		86D76F9F165686D80046D71F /* assetQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EF416518D4600D96ADF /* assetQuery.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 */; };
 		86D76FA1165686D80046D71F /* assetTagsManifest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */; };
 		86D76FA2165686D80046D71F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7F0116518D4600D96ADF /* audio.cc */; };
 		86D76FA2165686D80046D71F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7F0116518D4600D96ADF /* audio.cc */; };
 		86D76FA3165686D80046D71F /* AudioAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 86BC7F0316518D4600D96ADF /* AudioAsset.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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		86BC7EFB16518D4600D96ADF /* assetTagsManifest_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest_ScriptBinding.h; sourceTree = "<group>"; };
@@ -1407,6 +1408,24 @@
 			name = controllers;
 			name = controllers;
 			sourceTree = "<group>";
 			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 */ = {
 		865A20BD1651589F00527C44 /* Resources */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -1804,6 +1823,7 @@
 		86BC7E7516518D4600D96ADF /* 2d */ = {
 		86BC7E7516518D4600D96ADF /* 2d */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				2AE2938016EF4BFA0015E200 /* experimental */,
 				2AB4F1CF16D55B7300C9A27B /* controllers */,
 				2AB4F1CF16D55B7300C9A27B /* controllers */,
 				86BC7E7616518D4600D96ADF /* assets */,
 				86BC7E7616518D4600D96ADF /* assets */,
 				86BC7E8016518D4600D96ADF /* core */,
 				86BC7E8016518D4600D96ADF /* core */,
@@ -1831,8 +1851,6 @@
 				86BC7E7716518D4600D96ADF /* AnimationAsset.cc */,
 				86BC7E7716518D4600D96ADF /* AnimationAsset.cc */,
 				86BC7E7816518D4600D96ADF /* AnimationAsset.h */,
 				86BC7E7816518D4600D96ADF /* AnimationAsset.h */,
 				86BC7E7916518D4600D96ADF /* AnimationAsset_ScriptBinding.h */,
 				86BC7E7916518D4600D96ADF /* AnimationAsset_ScriptBinding.h */,
-				86BC7E7A16518D4600D96ADF /* AnimationController.cc */,
-				86BC7E7B16518D4600D96ADF /* AnimationController.h */,
 				86BC7E7C16518D4600D96ADF /* ImageAsset.cc */,
 				86BC7E7C16518D4600D96ADF /* ImageAsset.cc */,
 				86BC7E7D16518D4600D96ADF /* ImageAsset.h */,
 				86BC7E7D16518D4600D96ADF /* ImageAsset.h */,
 				86BC7E7E16518D4600D96ADF /* ImageAsset_ScriptBinding.h */,
 				86BC7E7E16518D4600D96ADF /* ImageAsset_ScriptBinding.h */,
@@ -1843,6 +1861,10 @@
 		86BC7E8016518D4600D96ADF /* core */ = {
 		86BC7E8016518D4600D96ADF /* core */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				2AA3655516F3552200E7A900 /* ImageFrameProvider.cc */,
+				2AA3655616F3552200E7A900 /* ImageFrameProvider.h */,
+				2AA3655716F3552200E7A900 /* ImageFrameProviderCore.cc */,
+				2AA3655816F3552200E7A900 /* ImageFrameProviderCore.h */,
 				2ACF5A2516E52D4B00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2516E52D4B00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2616E52D4B00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2616E52D4B00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2716E52D4B00F838D9 /* SpriteBatchQueryResult.h */,
 				2ACF5A2716E52D4B00F838D9 /* SpriteBatchQueryResult.h */,
@@ -1862,8 +1884,6 @@
 				86BC7E8C16518D4600D96ADF /* SpriteBatch.h */,
 				86BC7E8C16518D4600D96ADF /* SpriteBatch.h */,
 				86BC7E8D16518D4600D96ADF /* SpriteBatchItem.cc */,
 				86BC7E8D16518D4600D96ADF /* SpriteBatchItem.cc */,
 				86BC7E8E16518D4600D96ADF /* SpriteBatchItem.h */,
 				86BC7E8E16518D4600D96ADF /* SpriteBatchItem.h */,
-				86BC7E8F16518D4600D96ADF /* SpriteProxyBase.cc */,
-				86BC7E9016518D4600D96ADF /* SpriteProxyBase.h */,
 				86BC7E9116518D4600D96ADF /* Utility.cc */,
 				86BC7E9116518D4600D96ADF /* Utility.cc */,
 				86BC7E9216518D4600D96ADF /* Utility.h */,
 				86BC7E9216518D4600D96ADF /* Utility.h */,
 				86BC7E9316518D4600D96ADF /* Vector2.cc */,
 				86BC7E9316518D4600D96ADF /* Vector2.cc */,
@@ -1990,8 +2010,6 @@
 				86BC7EF416518D4600D96ADF /* assetQuery.cc */,
 				86BC7EF416518D4600D96ADF /* assetQuery.cc */,
 				86BC7EF516518D4600D96ADF /* assetQuery.h */,
 				86BC7EF516518D4600D96ADF /* assetQuery.h */,
 				86BC7EF616518D4600D96ADF /* assetQuery_ScriptBinding.h */,
 				86BC7EF616518D4600D96ADF /* assetQuery_ScriptBinding.h */,
-				86BC7EF716518D4600D96ADF /* assetSnapshot.cc */,
-				86BC7EF816518D4600D96ADF /* assetSnapshot.h */,
 				86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */,
 				86BC7EF916518D4600D96ADF /* assetTagsManifest.cc */,
 				86BC7EFA16518D4600D96ADF /* assetTagsManifest.h */,
 				86BC7EFA16518D4600D96ADF /* assetTagsManifest.h */,
 				86BC7EFB16518D4600D96ADF /* assetTagsManifest_ScriptBinding.h */,
 				86BC7EFB16518D4600D96ADF /* assetTagsManifest_ScriptBinding.h */,
@@ -3078,7 +3096,6 @@
 				86D76F9C165686D80046D71F /* assetFieldTypes.cc in Sources */,
 				86D76F9C165686D80046D71F /* assetFieldTypes.cc in Sources */,
 				86D76F9D165686D80046D71F /* assetManager.cc in Sources */,
 				86D76F9D165686D80046D71F /* assetManager.cc in Sources */,
 				86D76F9F165686D80046D71F /* assetQuery.cc in Sources */,
 				86D76F9F165686D80046D71F /* assetQuery.cc in Sources */,
-				86D76FA0165686D80046D71F /* assetSnapshot.cc in Sources */,
 				86D76FA1165686D80046D71F /* assetTagsManifest.cc in Sources */,
 				86D76FA1165686D80046D71F /* assetTagsManifest.cc in Sources */,
 				86D76FA2165686D80046D71F /* audio.cc in Sources */,
 				86D76FA2165686D80046D71F /* audio.cc in Sources */,
 				86D76FA3165686D80046D71F /* AudioAsset.cc in Sources */,
 				86D76FA3165686D80046D71F /* AudioAsset.cc in Sources */,
@@ -3101,7 +3118,6 @@
 				86D76F98165686B00046D71F /* Sprite.cc in Sources */,
 				86D76F98165686B00046D71F /* Sprite.cc in Sources */,
 				86D76F99165686B00046D71F /* Trigger.cc in Sources */,
 				86D76F99165686B00046D71F /* Trigger.cc in Sources */,
 				86D76F791656868D0046D71F /* AnimationAsset.cc in Sources */,
 				86D76F791656868D0046D71F /* AnimationAsset.cc in Sources */,
-				86D76F7A1656868D0046D71F /* AnimationController.cc in Sources */,
 				86D76F7B1656868D0046D71F /* ImageAsset.cc in Sources */,
 				86D76F7B1656868D0046D71F /* ImageAsset.cc in Sources */,
 				86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */,
 				86D76F7C1656868D0046D71F /* BatchRender.cc in Sources */,
 				86D76F7D1656868D0046D71F /* CoreMath.cc in Sources */,
 				86D76F7D1656868D0046D71F /* CoreMath.cc in Sources */,
@@ -3109,7 +3125,6 @@
 				86D76F7F1656868D0046D71F /* SpriteBase.cc in Sources */,
 				86D76F7F1656868D0046D71F /* SpriteBase.cc in Sources */,
 				86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */,
 				86D76F801656868D0046D71F /* SpriteBatch.cc in Sources */,
 				86D76F811656868D0046D71F /* SpriteBatchItem.cc in Sources */,
 				86D76F811656868D0046D71F /* SpriteBatchItem.cc in Sources */,
-				86D76F821656868D0046D71F /* SpriteProxyBase.cc in Sources */,
 				86D76F831656868D0046D71F /* Utility.cc in Sources */,
 				86D76F831656868D0046D71F /* Utility.cc in Sources */,
 				86D76F841656868D0046D71F /* Vector2.cc in Sources */,
 				86D76F841656868D0046D71F /* Vector2.cc in Sources */,
 				86D76F851656868D0046D71F /* guiImageButtonCtrl.cc in Sources */,
 				86D76F851656868D0046D71F /* guiImageButtonCtrl.cc in Sources */,
@@ -3278,6 +3293,9 @@
 				2AB4C19F16DE9F0600B02479 /* PickingSceneController.cc in Sources */,
 				2AB4C19F16DE9F0600B02479 /* PickingSceneController.cc in Sources */,
 				2AB4C1A316DE9F1100B02479 /* AmbientForceController.cc in Sources */,
 				2AB4C1A316DE9F1100B02479 /* AmbientForceController.cc in Sources */,
 				2ACF5A2816E52D4B00F838D9 /* SpriteBatchQuery.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;
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		};

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

@@ -7,6 +7,8 @@
 	objects = {
 	objects = {
 
 
 /* Begin PBXBuildFile section */
 /* 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 */; };
 		2AA6866A16D69968003CEF0A /* SceneObjectList.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6866516D69968003CEF0A /* SceneObjectList.cc */; };
 		2AA6866B16D69968003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6866816D69968003CEF0A /* SceneObjectSet.cc */; };
 		2AA6866B16D69968003CEF0A /* SceneObjectSet.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AA6866816D69968003CEF0A /* SceneObjectSet.cc */; };
 		2AB14A0916D7CDCE00EABBF2 /* PointForceController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB14A0716D7CDCE00EABBF2 /* PointForceController.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 */; };
 		2AB97A2116B66BE50080F940 /* tamlCustom.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AB97A1F16B66BE50080F940 /* tamlCustom.cc */; };
 		2AC4404E16B0144500FC4091 /* ImageFont.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AC4404C16B0144500FC4091 /* ImageFont.cc */; };
 		2AC4404E16B0144500FC4091 /* ImageFont.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AC4404C16B0144500FC4091 /* ImageFont.cc */; };
 		2ACF5A2C16E52D6A00F838D9 /* SpriteBatchQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2ACF5A2916E52D6A00F838D9 /* SpriteBatchQuery.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 */; };
 		2AE2F55916D6B07200B6A058 /* BuoyancyController.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AE2F55716D6B07200B6A058 /* BuoyancyController.cc */; };
 		2AED7D9316B70102003482CF /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AED7D9216B70102003482CF /* CoreText.framework */; };
 		2AED7D9316B70102003482CF /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2AED7D9216B70102003482CF /* CoreText.framework */; };
 		2AF1C54B16B439D900C1CF3A /* declaredAssets.cc in Sources */ = {isa = PBXBuildFile; fileRef = 2AF1C54716B439D900C1CF3A /* declaredAssets.cc */; };
 		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 */; };
 		867BACF516AEC8BB0033868F /* popupMenu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 867BACCC16AEC8BB0033868F /* popupMenu.mm */; };
 		867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 867BACD016AEC8BB0033868F /* SoundEngine.mm */; };
 		867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 867BACD016AEC8BB0033868F /* SoundEngine.mm */; };
 		867BAFDF16AEC9050033868F /* AnimationAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BACFA16AEC9050033868F /* AnimationAsset.cc */; };
 		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 */; };
 		867BAFE116AEC9050033868F /* ImageAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BACFF16AEC9050033868F /* ImageAsset.cc */; };
 		867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD0216AEC9050033868F /* ParticleAsset.cc */; };
 		867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD0216AEC9050033868F /* ParticleAsset.cc */; };
 		867BAFE316AEC9050033868F /* ParticleAssetEmitter.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD0516AEC9050033868F /* ParticleAssetEmitter.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 */; };
 		867BAFEA16AEC9050033868F /* SpriteBase.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1616AEC9050033868F /* SpriteBase.cc */; };
 		867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1916AEC9050033868F /* SpriteBatch.cc */; };
 		867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1916AEC9050033868F /* SpriteBatch.cc */; };
 		867BAFEC16AEC9050033868F /* SpriteBatchItem.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1B16AEC9050033868F /* SpriteBatchItem.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 */; };
 		867BAFEE16AEC9050033868F /* Utility.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD1F16AEC9050033868F /* Utility.cc */; };
 		867BAFEF16AEC9050033868F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD2116AEC9050033868F /* Vector2.cc */; };
 		867BAFEF16AEC9050033868F /* Vector2.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD2116AEC9050033868F /* Vector2.cc */; };
 		867BAFF016AEC9050033868F /* guiImageButtonCtrl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD2516AEC9050033868F /* guiImageButtonCtrl.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 */; };
 		867BB00816AEC9050033868F /* assetFieldTypes.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7516AEC9050033868F /* assetFieldTypes.cc */; };
 		867BB00916AEC9050033868F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7716AEC9050033868F /* assetManager.cc */; };
 		867BB00916AEC9050033868F /* assetManager.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7716AEC9050033868F /* assetManager.cc */; };
 		867BB00B16AEC9050033868F /* assetQuery.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD7D16AEC9050033868F /* assetQuery.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 */; };
 		867BB00D16AEC9050033868F /* assetTagsManifest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8216AEC9050033868F /* assetTagsManifest.cc */; };
 		867BB00E16AEC9050033868F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8A16AEC9050033868F /* audio.cc */; };
 		867BB00E16AEC9050033868F /* audio.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8A16AEC9050033868F /* audio.cc */; };
 		867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8C16AEC9050033868F /* AudioAsset.cc */; };
 		867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */ = {isa = PBXBuildFile; fileRef = 867BAD8C16AEC9050033868F /* AudioAsset.cc */; };
@@ -481,6 +481,10 @@
 /* End PBXBuildFile section */
 /* End PBXBuildFile section */
 
 
 /* Begin PBXFileReference 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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		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>"; };
 		867BAD8416AEC9050033868F /* assetTagsManifest_ScriptBinding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assetTagsManifest_ScriptBinding.h; sourceTree = "<group>"; };
@@ -1477,6 +1478,24 @@
 			name = controllers;
 			name = controllers;
 			sourceTree = "<group>";
 			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 */ = {
 		867BAC9116AEC8BB0033868F /* platformiOS */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
@@ -1556,6 +1575,7 @@
 		867BACF816AEC9050033868F /* 2d */ = {
 		867BACF816AEC9050033868F /* 2d */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				2AE2938616EF4C310015E200 /* experimental */,
 				2AB4F1D416D55B9F00C9A27B /* controllers */,
 				2AB4F1D416D55B9F00C9A27B /* controllers */,
 				867BACF916AEC9050033868F /* assets */,
 				867BACF916AEC9050033868F /* assets */,
 				867BAD0C16AEC9050033868F /* core */,
 				867BAD0C16AEC9050033868F /* core */,
@@ -1573,8 +1593,6 @@
 				867BACFA16AEC9050033868F /* AnimationAsset.cc */,
 				867BACFA16AEC9050033868F /* AnimationAsset.cc */,
 				867BACFB16AEC9050033868F /* AnimationAsset.h */,
 				867BACFB16AEC9050033868F /* AnimationAsset.h */,
 				867BACFC16AEC9050033868F /* AnimationAsset_ScriptBinding.h */,
 				867BACFC16AEC9050033868F /* AnimationAsset_ScriptBinding.h */,
-				867BACFD16AEC9050033868F /* AnimationController.cc */,
-				867BACFE16AEC9050033868F /* AnimationController.h */,
 				867BACFF16AEC9050033868F /* ImageAsset.cc */,
 				867BACFF16AEC9050033868F /* ImageAsset.cc */,
 				867BAD0016AEC9050033868F /* ImageAsset.h */,
 				867BAD0016AEC9050033868F /* ImageAsset.h */,
 				867BAD0116AEC9050033868F /* ImageAsset_ScriptBinding.h */,
 				867BAD0116AEC9050033868F /* ImageAsset_ScriptBinding.h */,
@@ -1595,6 +1613,10 @@
 		867BAD0C16AEC9050033868F /* core */ = {
 		867BAD0C16AEC9050033868F /* core */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				2AA3655B16F3553E00E7A900 /* ImageFrameProvider.cc */,
+				2AA3655C16F3553E00E7A900 /* ImageFrameProvider.h */,
+				2AA3655D16F3553E00E7A900 /* ImageFrameProviderCore.cc */,
+				2AA3655E16F3553E00E7A900 /* ImageFrameProviderCore.h */,
 				2ACF5A2916E52D6A00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2916E52D6A00F838D9 /* SpriteBatchQuery.cc */,
 				2ACF5A2A16E52D6A00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2A16E52D6A00F838D9 /* SpriteBatchQuery.h */,
 				2ACF5A2B16E52D6A00F838D9 /* SpriteBatchQueryResult.h */,
 				2ACF5A2B16E52D6A00F838D9 /* SpriteBatchQueryResult.h */,
@@ -1614,8 +1636,6 @@
 				867BAD1A16AEC9050033868F /* SpriteBatch.h */,
 				867BAD1A16AEC9050033868F /* SpriteBatch.h */,
 				867BAD1B16AEC9050033868F /* SpriteBatchItem.cc */,
 				867BAD1B16AEC9050033868F /* SpriteBatchItem.cc */,
 				867BAD1C16AEC9050033868F /* SpriteBatchItem.h */,
 				867BAD1C16AEC9050033868F /* SpriteBatchItem.h */,
-				867BAD1D16AEC9050033868F /* SpriteProxyBase.cc */,
-				867BAD1E16AEC9050033868F /* SpriteProxyBase.h */,
 				867BAD1F16AEC9050033868F /* Utility.cc */,
 				867BAD1F16AEC9050033868F /* Utility.cc */,
 				867BAD2016AEC9050033868F /* Utility.h */,
 				867BAD2016AEC9050033868F /* Utility.h */,
 				867BAD2116AEC9050033868F /* Vector2.cc */,
 				867BAD2116AEC9050033868F /* Vector2.cc */,
@@ -1742,8 +1762,6 @@
 				867BAD7D16AEC9050033868F /* assetQuery.cc */,
 				867BAD7D16AEC9050033868F /* assetQuery.cc */,
 				867BAD7E16AEC9050033868F /* assetQuery.h */,
 				867BAD7E16AEC9050033868F /* assetQuery.h */,
 				867BAD7F16AEC9050033868F /* assetQuery_ScriptBinding.h */,
 				867BAD7F16AEC9050033868F /* assetQuery_ScriptBinding.h */,
-				867BAD8016AEC9050033868F /* assetSnapshot.cc */,
-				867BAD8116AEC9050033868F /* assetSnapshot.h */,
 				867BAD8216AEC9050033868F /* assetTagsManifest.cc */,
 				867BAD8216AEC9050033868F /* assetTagsManifest.cc */,
 				867BAD8316AEC9050033868F /* assetTagsManifest.h */,
 				867BAD8316AEC9050033868F /* assetTagsManifest.h */,
 				867BAD8416AEC9050033868F /* assetTagsManifest_ScriptBinding.h */,
 				867BAD8416AEC9050033868F /* assetTagsManifest_ScriptBinding.h */,
@@ -3011,7 +3029,6 @@
 				867BACF516AEC8BB0033868F /* popupMenu.mm in Sources */,
 				867BACF516AEC8BB0033868F /* popupMenu.mm in Sources */,
 				867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */,
 				867BACF616AEC8BB0033868F /* SoundEngine.mm in Sources */,
 				867BAFDF16AEC9050033868F /* AnimationAsset.cc in Sources */,
 				867BAFDF16AEC9050033868F /* AnimationAsset.cc in Sources */,
-				867BAFE016AEC9050033868F /* AnimationController.cc in Sources */,
 				867BAFE116AEC9050033868F /* ImageAsset.cc in Sources */,
 				867BAFE116AEC9050033868F /* ImageAsset.cc in Sources */,
 				867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */,
 				867BAFE216AEC9050033868F /* ParticleAsset.cc in Sources */,
 				867BAFE316AEC9050033868F /* ParticleAssetEmitter.cc in Sources */,
 				867BAFE316AEC9050033868F /* ParticleAssetEmitter.cc in Sources */,
@@ -3024,7 +3041,6 @@
 				867BAFEA16AEC9050033868F /* SpriteBase.cc in Sources */,
 				867BAFEA16AEC9050033868F /* SpriteBase.cc in Sources */,
 				867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */,
 				867BAFEB16AEC9050033868F /* SpriteBatch.cc in Sources */,
 				867BAFEC16AEC9050033868F /* SpriteBatchItem.cc in Sources */,
 				867BAFEC16AEC9050033868F /* SpriteBatchItem.cc in Sources */,
-				867BAFED16AEC9050033868F /* SpriteProxyBase.cc in Sources */,
 				867BAFEE16AEC9050033868F /* Utility.cc in Sources */,
 				867BAFEE16AEC9050033868F /* Utility.cc in Sources */,
 				867BAFEF16AEC9050033868F /* Vector2.cc in Sources */,
 				867BAFEF16AEC9050033868F /* Vector2.cc in Sources */,
 				867BAFF016AEC9050033868F /* guiImageButtonCtrl.cc in Sources */,
 				867BAFF016AEC9050033868F /* guiImageButtonCtrl.cc in Sources */,
@@ -3050,7 +3066,6 @@
 				867BB00816AEC9050033868F /* assetFieldTypes.cc in Sources */,
 				867BB00816AEC9050033868F /* assetFieldTypes.cc in Sources */,
 				867BB00916AEC9050033868F /* assetManager.cc in Sources */,
 				867BB00916AEC9050033868F /* assetManager.cc in Sources */,
 				867BB00B16AEC9050033868F /* assetQuery.cc in Sources */,
 				867BB00B16AEC9050033868F /* assetQuery.cc in Sources */,
-				867BB00C16AEC9050033868F /* assetSnapshot.cc in Sources */,
 				867BB00D16AEC9050033868F /* assetTagsManifest.cc in Sources */,
 				867BB00D16AEC9050033868F /* assetTagsManifest.cc in Sources */,
 				867BB00E16AEC9050033868F /* audio.cc in Sources */,
 				867BB00E16AEC9050033868F /* audio.cc in Sources */,
 				867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */,
 				867BB00F16AEC9050033868F /* AudioAsset.cc in Sources */,
@@ -3414,6 +3429,9 @@
 				2AB4C1B016DE9F6700B02479 /* GroupedSceneController.cc in Sources */,
 				2AB4C1B016DE9F6700B02479 /* GroupedSceneController.cc in Sources */,
 				2AB4C1B116DE9F6700B02479 /* PickingSceneController.cc in Sources */,
 				2AB4C1B116DE9F6700B02479 /* PickingSceneController.cc in Sources */,
 				2ACF5A2C16E52D6A00F838D9 /* SpriteBatchQuery.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;
 			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 )
 void AnimationAsset::setImage( const char* pAssetId )
 {
 {
     // Ignore no change.
     // Ignore no change.

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

@@ -58,9 +58,10 @@ public:
     static void initPersistFields();
     static void initPersistFields();
     virtual bool onAdd();
     virtual bool onAdd();
     virtual void onRemove();
     virtual void onRemove();
+    virtual void copyTo(SimObject* object);
 
 
     void            setImage( const char* pAssetId );
     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 );
     void            setAnimationFrames( const char* pAnimationFrames );
     inline const Vector<S32>& getSpecifiedAnimationFrames( void ) const { return mAnimationFrames; }
     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 )
 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.
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mFrames );
     VECTOR_SET_ASSOCIATION( mExplicitFrames );
     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 )
 void ImageAsset::setForce16Bit( const bool force16Bit )
 {
 {
     // Ignore no change,
     // 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 )
 void ImageAsset::calculateImage( void )
 {
 {
     // Debug Profiling.
     // Debug Profiling.
@@ -1278,3 +1174,205 @@ bool ImageAsset::setFilterMode( void* obj, const char* data )
     static_cast<ImageAsset*>(obj)->setFilterMode(getFilterModeEnum(data));
     static_cast<ImageAsset*>(obj)->setFilterMode(getFilterModeEnum(data));
     return false;
     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();
     static void initPersistFields();
     virtual bool onAdd();
     virtual bool onAdd();
     virtual void onRemove();
     virtual void onRemove();
+    virtual void copyTo(SimObject* object);
 
 
     void                    setImageFile( const char* pImageFile );
     void                    setImageFile( const char* pImageFile );
     inline StringTableEntry getImageFile( void ) const                      { return mImageFile; };
     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; }
     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_
 #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." );
     Con::warnf( "(TypeParticleAssetPtr) - Cannot set multiple args to a single asset." );
 }
 }
 
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(ParticleAsset);
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 ParticleAsset::ParticleAsset() :
 ParticleAsset::ParticleAsset() :
@@ -493,3 +489,20 @@ void ParticleAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Read the fields.
     // Read the fields.
     mParticleFields.onTamlCustomRead( customNodes );
     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:
 private:
     typedef AssetBase  Parent;
     typedef AssetBase  Parent;
+    typedef ParticleAssetEmitter Children;
     typedef Vector<ParticleAssetEmitter*> typeEmitterVector;
     typedef Vector<ParticleAssetEmitter*> typeEmitterVector;
 
 
 public:
 public:

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

@@ -128,10 +128,6 @@ const char* ParticleAssetEmitter::getOrientationTypeDescription( const ParticleO
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-IMPLEMENT_CONOBJECT(ParticleAssetEmitter);
-
-//------------------------------------------------------------------------------
-
 ParticleAssetEmitter::ParticleAssetEmitter() :
 ParticleAssetEmitter::ParticleAssetEmitter() :
                             mEmitterName( StringTable->EmptyString ),
                             mEmitterName( StringTable->EmptyString ),
                             mOwner( NULL ),
                             mOwner( NULL ),
@@ -295,7 +291,7 @@ void ParticleAssetEmitter::copyTo(SimObject* object)
    pParticleAssetEmitter->setAlphaTest( getAlphaTest() );
    pParticleAssetEmitter->setAlphaTest( getAlphaTest() );
 
 
    pParticleAssetEmitter->setRandomImageFrame( getRandomImageFrame() );
    pParticleAssetEmitter->setRandomImageFrame( getRandomImageFrame() );
-   if ( pParticleAssetEmitter->isStaticMode() )
+   if ( pParticleAssetEmitter->isStaticFrameProvider() )
    {
    {
        pParticleAssetEmitter->setImage( getImage() );
        pParticleAssetEmitter->setImage( getImage() );
        pParticleAssetEmitter->setImageFrame( getImageFrame() );
        pParticleAssetEmitter->setImageFrame( getImageFrame() );
@@ -509,3 +505,20 @@ void ParticleAssetEmitter::onTamlCustomRead( const TamlCustomNodes& customNodes
     mParticleFields.onTamlCustomRead( 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"
 #include "2d/assets/particleAssetFieldCollection.h"
 #endif
 #endif
 
 
-#ifndef _PARTICLE_ASSET_FIELD_H_
-#include "2d/assets/particleAssetField.h"
-#endif
-
 #ifndef _IMAGE_ASSET_H_
 #ifndef _IMAGE_ASSET_H_
 #include "2d/assets/ImageAsset.h"
 #include "2d/assets/ImageAsset.h"
 #endif
 #endif
 
 
-#ifndef _ANIMATION_CONTROLLER_H_
-#include "2d/assets/AnimationController.h"
+#ifndef _ANIMATION_ASSET_H_
+#include "2d/assets/AnimationAsset.h"
 #endif
 #endif
 
 
 #ifndef _SCENE_OBJECT_H_
 #ifndef _SCENE_OBJECT_H_
@@ -49,7 +45,7 @@ class ParticleAsset;
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-class ParticleAssetEmitter : public SimObject, public AssetPtrCallback
+class ParticleAssetEmitter : public SimObject, protected AssetPtrCallback
 {
 {
     friend ParticleAsset;
     friend ParticleAsset;
 
 
@@ -185,7 +181,7 @@ public:
     inline void setOldestInFront( const bool oldestInFront ) { mOldestInFront = oldestInFront; refreshAsset();  }
     inline void setOldestInFront( const bool oldestInFront ) { mOldestInFront = oldestInFront; refreshAsset();  }
     inline bool getOldestInFront( void ) const { return mOldestInFront; }
     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 );
     bool setImage( const char* pAssetId, const U32 frame = 0 );
     inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
     inline StringTableEntry getImage( void ) const { return mImageAsset.getAssetId(); }
     bool setImageFrame( const U32 frame );
     bool setImageFrame( const U32 frame );
@@ -194,8 +190,8 @@ public:
     inline bool getRandomImageFrame( void ) const { return mRandomImageFrame; }
     inline bool getRandomImageFrame( void ) const { return mRandomImageFrame; }
     bool setAnimation( const char* animationName );
     bool setAnimation( const char* animationName );
     inline StringTableEntry getAnimation( void ) const { return mAnimationAsset.getAssetId(); }
     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 void setBlendMode( bool blendMode ) { mBlendMode = blendMode; refreshAsset(); }
     inline bool getBlendMode( void ) const { return mBlendMode; };
     inline bool getBlendMode( void ) const { return mBlendMode; };
@@ -257,9 +253,9 @@ public:
 private:
 private:
     void setOwner( ParticleAsset* pParticleAsset );
     void setOwner( ParticleAsset* pParticleAsset );
     inline void refreshAsset( void );
     inline void refreshAsset( void );
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
 
 
 protected:
 protected:
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
     void onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomRead( const 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 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 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     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     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 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 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     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; }
     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 );
 ParticleAssetField::DataKey ParticleAssetField::BadDataKey( -1.0f, 0.0f );
 
 
@@ -70,25 +68,6 @@ ParticleAssetField::ParticleAssetField() :
 {
 {
     // Set Vector Associations.
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mDataKeys );
     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.
     // Set the data keys.
     mDataKeys = 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 onTamlCustomWrite( TamlCustomNode* pCustomNode  );
     void onTamlCustomRead( const 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() :
 ParticleAssetFieldCollection::ParticleAssetFieldCollection() :
                                     mpSelectedField( NULL )
                                     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 onTamlCustomWrite( TamlCustomNodes& customNodes );
     void onTamlCustomRead( const TamlCustomNodes& customNodes );
     void onTamlCustomRead( const TamlCustomNodes& customNodes );
+
+    void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement ) const;
 };
 };
 
 
 #endif // ParticleAssetFieldCollection
 #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 );
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
 
 
     // Query for candidate objects.
     // Query for candidate objects.
-    pWorldQuery->anyQueryArea( mFluidArea ); 
+    pWorldQuery->anyQueryAABB( mFluidArea ); 
 
 
     // Fetch results.
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
@@ -123,7 +123,7 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             continue;
             continue;
 
 
         // Ignore if it's a static body.
         // Ignore if it's a static body.
-        if ( pSceneObject->getBodyType() == b2BodyType::b2_staticBody )
+        if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
             continue;
 
 
         // Fetch the shape count.
         // Fetch the shape count.
@@ -136,10 +136,10 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
         // Fetch the body transform.
         // Fetch the body transform.
         const b2Transform& bodyTransform = pSceneObject->getBody()->GetTransform();;
         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.
         // Yes, so iterate them.
         for( U32 i = 0; i < shapeCount; ++i )
         for( U32 i = 0; i < shapeCount; ++i )
@@ -150,9 +150,9 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             // Fetch the shape.
             // Fetch the shape.
             const b2Shape* pShape = fixtureDef.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.
             // Calculate the area for the shape type.
             if ( pShape->GetType() == b2Shape::e_circle )
             if ( pShape->GetType() == b2Shape::e_circle )
@@ -174,36 +174,36 @@ void BuoyancyController::integrate( Scene* pScene, const F32 totalTime, const F3
             }
             }
 
 
             // Calculate area.
             // 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.
             // 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.
         // Skip not in water.
-		if( area < b2_epsilon )
-			continue;
+        if( area < b2_epsilon )
+            continue;
 
 
         // Calculate area/mass centers.
         // 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);
         pSceneObject->applyForce(buoyancyForce, massCenter);
 
 
-		// Linear drag
+        // Linear drag
         const Vector2 dragForce = (pSceneObject->getLinearVelocityFromWorldPoint(areaCenter) - mFlowVelocity) * (-mLinearDrag * area);
         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 );
         pSceneObject->applyTorque( -pSceneObject->getInertia() / pSceneObject->getMass() * area * pSceneObject->getAngularVelocity()*mAngularDrag );
     }
     }
 }
 }
@@ -225,30 +225,30 @@ F32 BuoyancyController::ComputeCircleSubmergedArea( const b2Transform& bodyTrans
 
 
     // Submerged?
     // Submerged?
     if (l < - radius + FLT_MIN)
     if (l < - radius + FLT_MIN)
-	{
+    {
         // No, so return zero area submerged.
         // 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!
         // 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 r2 = radius * radius;
     const F32 l2 = l * l;
     const F32 l2 = l * l;
     const F32 area = r2 *( mAsin(l / radius) + b2_pi / 2.0f) + l * mSqrt( r2 - l2 );
     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;
     const F32 com = -2.0f / 3.0f * mPow(r2 - l2, 1.5f) / area;
-	
+    
     // Calculate center.
     // 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.
     /// The fluid area.
     b2AABB mFluidArea;
     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:
 protected:
     F32 ComputeCircleSubmergedArea( const b2Transform& bodyTransform, const b2CircleShape* pShape, Vector2& center );
     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 )
 void PointForceController::integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
 {
 {
     // Finish if the attractor would have no effect.
     // Finish if the attractor would have no effect.
@@ -95,13 +103,16 @@ void PointForceController::integrate( Scene* pScene, const F32 totalTime, const
     // Prepare query filter.
     // Prepare query filter.
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
     WorldQuery* pWorldQuery = prepareQueryFilter( pScene );
 
 
+    // Fetch the current position.
+    const Vector2 currentPosition = getCurrentPosition();
+
     // Calculate the AABB of the attractor.
     // Calculate the AABB of the attractor.
     b2AABB aabb;
     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.
     // Query for candidate objects.
-    pWorldQuery->anyQueryArea( aabb ); 
+    pWorldQuery->anyQueryAABB( aabb ); 
 
 
     // Fetch results.
     // Fetch results.
     typeWorldQueryResultVector& queryResults = pWorldQuery->getQueryResults();
     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 linearDrag = mClampF( mLinearDrag, 0.0f, 1.0f ) * elapsedTime;
     const F32 angularDrag = mClampF( mAngularDrag, 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.
     // Iterate the results.
     for ( U32 n = 0; n < resultCount; n++ )
     for ( U32 n = 0; n < resultCount; n++ )
     {
     {
         // Fetch the scene object.
         // Fetch the scene object.
         SceneObject* pSceneObject = queryResults[n].mpSceneObject;
         SceneObject* pSceneObject = queryResults[n].mpSceneObject;
 
 
+        // Ignore if it's the tracked object.
+        if ( pSceneObject == pTrackedObject )
+            continue;
+
         // Ignore if it's a static body.
         // Ignore if it's a static body.
         if ( pSceneObject->getBodyType() == b2_staticBody )
         if ( pSceneObject->getBodyType() == b2_staticBody )
             continue;
             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;
             continue;
 
 
         // Non-Linear force?
         // Non-Linear force?
         if ( mNonLinear )
         if ( mNonLinear )
         {
         {
             // Yes, so use an approximation of the inverse-square law.
             // Yes, so use an approximation of the inverse-square law.
-            distanceForce *= (1.0f / distanceForce.LengthSquared()) * forceSqr;
+            distanceForce *= (1.0f / distanceSqr) * forceSqr;
         }
         }
         else
         else
         {
         {
@@ -191,5 +212,5 @@ void PointForceController::renderOverlay( Scene* pScene, const SceneRenderState*
     Parent::renderOverlay( pScene, pSceneRenderState, pBatchRenderer );
     Parent::renderOverlay( pScene, pSceneRenderState, pBatchRenderer );
 
 
     // Draw force radius.
     // 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.
     /// Whether to apply the force non-linearly (using the inverse square law) or linearly.
     bool mNonLinear;
     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:
 public:
     PointForceController();
     PointForceController();
@@ -75,6 +78,16 @@ public:
     inline F32 getLinearDrag( void ) const { return mLinearDrag; }
     inline F32 getLinearDrag( void ) const { return mLinearDrag; }
     inline void setAngularDrag( const F32 angularDrag ) { mAngularDrag = angularDrag; }
     inline void setAngularDrag( const F32 angularDrag ) { mAngularDrag = angularDrag; }
     inline F32 getAngularDrag( void ) const { return mAngularDrag; }
     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.
     /// Integration.
     virtual void integrate( Scene* pScene, const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
     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();
     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_
 #ifndef _PARTICLE_SYSTEM_H_
 #define _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
 #endif
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -49,9 +49,8 @@ public:
         Vector2                 mVelocity;
         Vector2                 mVelocity;
         F32                     mOrientationAngle;
         F32                     mOrientationAngle;
         Vector2                 mRenderOOBB[4];
         Vector2                 mRenderOOBB[4];
-        U32                     mImageFrame;
         b2Transform             mTransform;
         b2Transform             mTransform;
-        AnimationController     mAnimationController;
+        ImageFrameProviderCore  mFrameProvider;
 
 
         /// Render Properties.
         /// Render Properties.
         Vector2                 mRenderSize;
         Vector2                 mRenderSize;
@@ -73,9 +72,11 @@ public:
         Vector2                 mPostTickPosition;
         Vector2                 mPostTickPosition;
         Vector2                 mRenderTickPosition;
         Vector2                 mRenderTickPosition;
 
 
+        ParticleNode() { constructInPlace<ImageFrameProviderCore>(&mFrameProvider); resetState(); }
+
         virtual void resetState( void )
         virtual void resetState( void )
         {
         {
-            mAnimationController.resetState();
+            mFrameProvider.resetState();
         }
         }
     };
     };
 
 

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

@@ -32,10 +32,6 @@
 #include "graphics/dgl.h"
 #include "graphics/dgl.h"
 #endif
 #endif
 
 
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
 // Script bindings.
 // Script bindings.
 #include "RenderProxy_ScriptBinding.h"
 #include "RenderProxy_ScriptBinding.h"
 
 
@@ -81,6 +77,6 @@ void RenderProxy::copyTo(SimObject* object)
     // Sanity!
     // Sanity!
     AssertFatal(pRenderProxy != NULL, "RenderProxy::copyTo() - Object is not the correct type.");
     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_
 #ifndef _RENDER_PROXY_H_
 #define _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
 #endif
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-class RenderProxy : public SimObject, public SpriteProxyBase
+class RenderProxy : public SimObject, public ImageFrameProvider
 {
 {
     typedef SimObject               Parent;
     typedef SimObject               Parent;
 
 
@@ -53,14 +45,14 @@ public:
     DECLARE_CONOBJECT( RenderProxy );
     DECLARE_CONOBJECT( RenderProxy );
 
 
 protected:
 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_
 #endif // _RENDER_PROXY_H_

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

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 // 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 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;
     const U32 frame = argc >= 4 ? dAtoi(argv[3]) : 0;
 
 
     // Set Image.
     // 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")
                                                         "@return (string imageAssetId) The image being displayed")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "RenderProxy::getImage() - Method invalid, not in static mode." );
         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.
     // 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.")
                                                         "@return Returns true on success.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "RenderProxy::setImageFrame() - Method invalid, not in static mode." );
         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.
     // 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")
                                                         "@return (int frame) The frame currently being displayed")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "RenderProxy::getImageFrame() - Method invalid, not in static mode." );
         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 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.")
                                                         "@return Returns true on success.")
 {    
 {    
-    // Fetch Auto-Restore Flag.
-    const bool autoRestore = (argc >= 4) ? dAtob(argv[3]) : false;
-
     // Play Animation.
     // 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")
                                                         "@param enable If true, pause the animation. If false, continue animating\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "RenderProxy::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
         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.")
                                                         "@return No return value.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "RenderProxy::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
         return;
     }
     }
 
 
-    object->getAnimationController()->stopAnimation();
+    object->stopAnimation();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -148,7 +144,7 @@ ConsoleMethod(RenderProxy, setAnimationFrame, void, 3, 3, "(int frame) - Sets th
                                                                 "@return No return value.")
                                                                 "@return No return value.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::setAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
         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
     // 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")
                                                             "@return (int frame) The current animation frame")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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.")
                                                             "@return (string AnimationAssetId) The current animation asset Id.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimation() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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")
                                                         "@return (float time) The current animation time")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::getAnimationTime() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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")
                                                                 "@return (bool finished) Whether or not the animation is finished")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::getIsAnimationFinished() - Method invalid, not in dynamic (animated) mode." );
         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 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")
                                                                 "@param timeScale Value which will scale the frame animation speed. 1 by default.\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "RenderProxy::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         return;
         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")
                                                                 "@return (float) Returns the animation time scale for this render-proxy.\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "RenderProxy::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "RenderProxy::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         return 1.0f;
         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_
 #ifndef _SPRITE_BASE_H_
-#include "SpriteBase.h"
+#include "2d/core/SpriteBase.h"
 #endif
 #endif
 
 
 #ifndef _DGL_H_
 #ifndef _DGL_H_
 #include "graphics/dgl.h"
 #include "graphics/dgl.h"
 #endif
 #endif
 
 
-#ifndef _STRINGBUFFER_H_
-#include "string/stringBuffer.h"
-#endif
-
 // Script bindings.
 // 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.
     // Call Parent.
     Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
     Parent::integrateObject( totalTime, elapsedTime, pDebugStats );
 
 
-    // Update render proxy base.
-    SpriteProxyBase::update( elapsedTime );
+    // Update image frame provider.
+    ImageFrameProvider::update( elapsedTime );
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 bool SpriteBase::validRender( void ) const
 bool SpriteBase::validRender( void ) const
 {
 {
-    return SpriteProxyBase::validRender();
+    return ImageFrameProvider::validRender();
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -94,8 +90,8 @@ void SpriteBase::copyTo(SimObject* object)
     // Sanity!
     // Sanity!
     AssertFatal(pSpriteBase != NULL, "SpriteBase::copyTo() - Object is not the correct type.");
     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"
 #include "2d/sceneobject/SceneObject.h"
 #endif
 #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
 #endif
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-class SpriteBase : public SceneObject, public SpriteProxyBase
+class SpriteBase : public SceneObject, public ImageFrameProvider
 {
 {
     typedef SceneObject Parent;
     typedef SceneObject Parent;
 
 
@@ -65,14 +57,14 @@ protected:
     virtual void onAnimationEnd( void );
     virtual void onAnimationEnd( void );
 
 
 protected:
 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_
 #endif // _SPRITE_BASE_H_

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

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 // 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 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;
     U32 frame = argc >= 4 ? dAtoi(argv[3]) : 0;
 
 
     // Set image.
     // 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")
                                                         "@return (string imageAssetId) The image being displayed")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "SpriteBase::getImage() - Method invalid, not in static mode." );
         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.
     // 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.")
                                                         "@return Returns true on success.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "SpriteBase::setImageFrame() - Method invalid, not in static mode." );
         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.
     // 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.")
                                                     "@return The current image frame.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "SpriteBase::getImageFrame() - Method invalid, not in static mode." );
         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.
     // 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.
     // 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")
                                                              "@param enable If true, pause the animation. If false, continue animating\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "SpriteBase::pauseAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
         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.")
                                                         "@return No return value.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "SpriteBase::stopAnimation() - Method invalid, not in dynamic (animated) mode." );
         return;
         return;
     }
     }
 
 
-    object->getAnimationController()->stopAnimation();
+    object->stopAnimation();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -146,7 +142,7 @@ ConsoleMethod(SpriteBase, setAnimationFrame, void, 3, 3, "(int frame) - Sets the
                                                                 "@return No return value.")
                                                                 "@return No return value.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::setAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
         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
     // 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")
                                                                "@return (int frame) The current animation frame")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimationFrame() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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.")
                                                         "@return (string AnimationAssetId) The current animation asset Id.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimation() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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")
                                                     "@return (float time) The current animation time")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::getAnimationTime() - Method invalid, not in dynamic (animated) mode." );
         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.
     // 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")
                                                             "@return (bool finished) Whether or not the animation is finished")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::getIsAnimationFinished() - Method invalid, not in dynamic (animated) mode." );
         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 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")
                                                             "@param timeScale Value which will scale the frame animation speed. 1 by default.\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "SpriteBase::setAnimationTimeScale() - Method invalid, not in dynamic (animated) mode." );
         return;
         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")
                                                             "@return (float) Returns the animation time scale for this sprite.\n")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "SpriteBase::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         Con::warnf( "SpriteBase::getSpeedFactor() - Method invalid, not in dynamic (animated) mode." );
         return 1.0f;
         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() :
 SpriteBatch::SpriteBatch() :
     mMasterBatchId( 0 ),
     mMasterBatchId( 0 ),
     mSelectedSprite( NULL ),
     mSelectedSprite( NULL ),
@@ -52,14 +56,28 @@ SpriteBatch::SpriteBatch() :
     // Reset local extents.
     // Reset local extents.
     mLocalExtents.SetZero();
     mLocalExtents.SetZero();
     mLocalExtentsDirty = true;
     mLocalExtentsDirty = true;
-
-    // Create the sprite batch query if sprite clipping is on.
-    createSpriteBatchQuery();
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 SpriteBatch::~SpriteBatch()
 SpriteBatch::~SpriteBatch()
+{
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpriteBatch::onAdd()
+{
+    // Create the sprite batch query if required.
+    if ( mBatchCulling )
+        createSpriteBatchQuery();
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpriteBatch::onRemove()
 {
 {
     // Clear the sprites.
     // Clear the sprites.
     clearSprites();
     clearSprites();
@@ -91,7 +109,7 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
 
 
         // Perform query.
         // Perform query.
-        pSpriteBatchQuery->renderQueryArea( localAABB );
+        pSpriteBatchQuery->queryArea( localAABB, false );
 
 
         // Debug Profiling.
         // Debug Profiling.
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
@@ -372,6 +390,9 @@ void SpriteBatch::setBatchCulling( const bool batchCulling )
     if ( mBatchCulling == batchCulling )
     if ( mBatchCulling == batchCulling )
         return;
         return;
 
 
+    // Set batch culling.
+    mBatchCulling = batchCulling;
+
     // Create/destroy sprite batch query appropriately.
     // Create/destroy sprite batch query appropriately.
     if ( mBatchCulling )
     if ( mBatchCulling )
         createSpriteBatchQuery();
         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.
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_SetSpriteAnimation);
     PROFILE_SCOPE(SpriteBatch_SetSpriteAnimation);
@@ -503,7 +524,7 @@ void SpriteBatch::setSpriteAnimation( const char* pAssetId, const bool autoResto
         return;
         return;
 
 
     // Set animation.
     // Set animation.
-    mSelectedSprite->setAnimation( pAssetId, autoRestore );
+    mSelectedSprite->setAnimation( pAssetId );
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -527,7 +548,7 @@ void SpriteBatch::clearSpriteAsset( void )
         return;
         return;
 
 
     // Clear the asset.
     // 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 )
 void SpriteBatch::setSpriteName( const char* pName )
 {
 {
     // Finish if a sprite is not selected.
     // Finish if a sprite is not selected.
@@ -1187,38 +1232,106 @@ void SpriteBatch::destroySpriteBatchQuery( void )
 
 
     // Finish if sprite clipping 
     // Finish if sprite clipping 
     delete mpSpriteBatchQuery;
     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.
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomWrite);
     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.
     // Write all sprites.
     for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
     for( typeSpriteBatchHash::iterator spriteItr = mSprites.begin(); spriteItr != mSprites.end(); ++spriteItr )
-    {
-        // Add sprite node.
-        TamlCustomNode* pNode = pSpritesNode->addNode( spriteItemTypeName );
-        
+    {      
         // Write type with sprite item.
         // 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.
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_TamlCustomRead);
     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.
     // Fetch children nodes.
     const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
     const TamlCustomNodeVector& spriteNodes = pSpritesNode->getChildren();
@@ -1233,7 +1346,7 @@ void SpriteBatch::onTamlCustomRead( const TamlCustomNode* pSpritesNode )
         StringTableEntry nodeName = pNode->getNodeName();
         StringTableEntry nodeName = pNode->getNodeName();
 
 
         // Is this a known node name?
         // Is this a known node name?
-        if ( nodeName != spriteItemNodeName )
+        if ( nodeName != spritesItemTypeName )
         {
         {
             // No, so warn.
             // No, so warn.
             Con::warnf( "SpriteBatch - Unknown custom type '%s'.", nodeName );
             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!
     // 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();
     SpriteBatch();
     virtual ~SpriteBatch();
     virtual ~SpriteBatch();
 
 
+    virtual bool onAdd();
+    virtual void onRemove();
+
     void prepareRender( SceneRenderObject* pSceneRenderObject, const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue );
     void prepareRender( SceneRenderObject* pSceneRenderObject, const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue );
     void render( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer );
     void render( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer );
 
 
@@ -89,7 +92,6 @@ public:
     void moveQueryProxy( SpriteBatchItem* pSpriteBatchItem, const b2AABB& localAABB );    
     void moveQueryProxy( SpriteBatchItem* pSpriteBatchItem, const b2AABB& localAABB );    
     SpriteBatchQuery* getSpriteBatchQuery( const bool clearQuery = false );
     SpriteBatchQuery* getSpriteBatchQuery( const bool clearQuery = false );
 
 
-
     virtual void copyTo( SpriteBatch* pSpriteBatch ) const;
     virtual void copyTo( SpriteBatch* pSpriteBatch ) const;
 
 
     inline U32 getSpriteCount( void ) { return (U32)mSprites.size(); }
     inline U32 getSpriteCount( void ) { return (U32)mSprites.size(); }
@@ -123,7 +125,7 @@ public:
     StringTableEntry getSpriteImage( void ) const;
     StringTableEntry getSpriteImage( void ) const;
     void setSpriteImageFrame( const U32 imageFrame );
     void setSpriteImageFrame( const U32 imageFrame );
     U32 getSpriteImageFrame( void ) const;
     U32 getSpriteImageFrame( void ) const;
-    void setSpriteAnimation( const char* pAssetId, const bool autoRestore = false );
+    void setSpriteAnimation( const char* pAssetId );
     StringTableEntry getSpriteAnimation( void ) const;
     StringTableEntry getSpriteAnimation( void ) const;
     void clearSpriteAsset( void );
     void clearSpriteAsset( void );
 
 
@@ -171,9 +173,14 @@ public:
     void setSpriteDataObject( SimObject* pDataObject );
     void setSpriteDataObject( SimObject* pDataObject );
     SimObject* getSpriteDataObject( void ) const;
     SimObject* getSpriteDataObject( void ) const;
 
 
+    void setUserData( void* pUserData );
+    void* getUserData( void ) const;
+
     void setSpriteName( const char* pName );
     void setSpriteName( const char* pName );
     StringTableEntry getSpriteName( void ) const;
     StringTableEntry getSpriteName( void ) const;
 
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
 protected:
     SpriteBatchItem* createSprite( void );
     SpriteBatchItem* createSprite( void );
     SpriteBatchItem* findSpritePosition( const SpriteBatchItem::LogicalPosition& logicalPosition );
     SpriteBatchItem* findSpritePosition( const SpriteBatchItem::LogicalPosition& logicalPosition );
@@ -188,8 +195,8 @@ protected:
     void createSpriteBatchQuery( void );
     void createSpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );
 
 
-    void onTamlCustomWrite( TamlCustomNode* pSpritesNode );
-    void onTamlCustomRead( const TamlCustomNode* pSpritesNode );
+    void onTamlCustomWrite( TamlCustomNodes& customNodes  );
+    void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 
 private:
 private:
     bool destroySprite( const U32 batchId );
     bool destroySprite( const U32 batchId );

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

@@ -28,73 +28,39 @@
 #include "2d/core/SpriteBatch.h"
 #include "2d/core/SpriteBatch.h"
 #endif
 #endif
 
 
-#ifndef _SCENE_RENDER_REQUEST_H_
-#include "2d/scene/SceneRenderRequest.h"
-#endif
-
 #ifndef _SCENE_OBJECT_H_
 #ifndef _SCENE_OBJECT_H_
 #include "2d/sceneobject/SceneObject.h"
 #include "2d/sceneobject/SceneObject.h"
 #endif
 #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 )
 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();
     resetState();
 }
 }
 
 
@@ -159,6 +125,8 @@ void SpriteBatchItem::resetState( void )
 
 
     mSpriteBatchQueryKey = 0;
     mSpriteBatchQueryKey = 0;
 
 
+    mUserData = NULL;
+
     // Require self ticking.
     // Require self ticking.
     mSelfTick = true;
     mSelfTick = true;
 }
 }
@@ -310,10 +278,11 @@ void SpriteBatchItem::updateWorldTransform( const U32 batchTransformId )
 
 
     // Update the local transform if needed.
     // Update the local transform if needed.
     if ( mLocalTransformDirty )
     if ( mLocalTransformDirty )
+    {
         updateLocalTransform();
         updateLocalTransform();
-
+    }
     // Finish if the batch transform is up-to-date.
     // Finish if the batch transform is up-to-date.
-    if ( batchTransformId == mLastBatchTransformId )
+    else if ( batchTransformId == mLastBatchTransformId )
         return;
         return;
 
 
     // Fetch world transform.
     // 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.
     // Write name.
     if ( getName() != StringTable->EmptyString )
     if ( getName() != StringTable->EmptyString )
         pSpriteNode->addField( spriteNameName, getName() );
         pSpriteNode->addField( spriteNameName, getName() );
 
 
-    // Write asset.
-    if ( isStaticMode() )
+    // Static frame provider?
+    if ( isStaticFrameProvider() )
     {
     {
         // Fetch image asset Id.
         // Fetch image asset Id.
         StringTableEntry assetId = getImage();
         StringTableEntry assetId = getImage();
@@ -410,7 +382,7 @@ void SpriteBatchItem::onTamlCustomWrite( TamlCustomNode* pSpriteNode )
 
 
     // Write source blend factor.
     // Write source blend factor.
     if ( mBlendMode && mSrcBlendFactor != GL_SRC_ALPHA )
     if ( mBlendMode && mSrcBlendFactor != GL_SRC_ALPHA )
-        pSpriteNode->addField( spriteBlendModeName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
+        pSpriteNode->addField( spriteSrcBlendFactorName, SceneObject::getSrcBlendFactorDescription(mSrcBlendFactor) );
         
         
     // Write destination blend factor.
     // Write destination blend factor.
     if ( mBlendMode && mDstBlendFactor != GL_ONE_MINUS_SRC_ALPHA )
     if ( mBlendMode && mDstBlendFactor != GL_ONE_MINUS_SRC_ALPHA )
@@ -584,3 +556,161 @@ void SpriteBatchItem::onTamlCustomRead( const TamlCustomNode* pSpriteNode )
     if ( spriteChildren.size() == 1 )
     if ( spriteChildren.size() == 1 )
         setDataObject( spriteChildren[0]->getProxyObject<SimObject>(true) );
         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_
 #ifndef _SPRITE_BATCH_ITEM_H_
 #define _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
 #endif
 
 
 //------------------------------------------------------------------------------  
 //------------------------------------------------------------------------------  
@@ -42,11 +34,15 @@ class SceneRenderRequest;
 
 
 //------------------------------------------------------------------------------  
 //------------------------------------------------------------------------------  
 
 
-class SpriteBatchItem : public SpriteProxyBase
+extern StringTableEntry spritesItemTypeName;
+
+//------------------------------------------------------------------------------  
+
+class SpriteBatchItem : public ImageFrameProvider
 {
 {
     friend class SpriteBatch;
     friend class SpriteBatch;
 
 
-    typedef SpriteProxyBase Parent;
+    typedef ImageFrameProvider Parent;
 
 
 public:
 public:
     // Represents a logical position.
     // Represents a logical position.
@@ -225,6 +221,8 @@ protected:
 
 
     U32                 mSpriteBatchQueryKey;
     U32                 mSpriteBatchQueryKey;
 
 
+    void*               mUserData;
+
 public:
 public:
     SpriteBatchItem();
     SpriteBatchItem();
     virtual ~SpriteBatchItem();
     virtual ~SpriteBatchItem();
@@ -284,14 +282,22 @@ public:
     inline void setDataObject( SimObject* pDataObject ) { mDataObject = pDataObject; }
     inline void setDataObject( SimObject* pDataObject ) { mDataObject = pDataObject; }
     inline SimObject* getDataObject( void ) const { return mDataObject; }
     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 void setSpriteBatchQueryKey( const U32 key ) { mSpriteBatchQueryKey = key; }
     inline U32  getSpriteBatchQueryKey( void ) const { return mSpriteBatchQueryKey; }
     inline U32  getSpriteBatchQueryKey( void ) const { return mSpriteBatchQueryKey; }
 
 
     virtual void copyTo( SpriteBatchItem* pSpriteBatchItem ) const;
     virtual void copyTo( SpriteBatchItem* pSpriteBatchItem ) const;
 
 
+    inline const Vector2* getRenderOOBB( void ) const { return mRenderOOBB; }
+
     void prepareRender( SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
     void prepareRender( SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
     void render( BatchRender* pBatchRenderer, const SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
     void render( BatchRender* pBatchRenderer, const SceneRenderRequest* pSceneRenderRequest, const U32 batchTransformId );
 
 
+    static void WriteCustomTamlSchema( const AbstractClassRep* pClassRep, TiXmlElement* pParentElement );
+
 protected:
 protected:
     void setBatchParent( SpriteBatch* pSpriteBatch, const U32 batchId );
     void setBatchParent( SpriteBatch* pSpriteBatch, const U32 batchId );
     inline void setProxyId( const S32 proxyId ) { mProxyId = proxyId; }
     inline void setProxyId( const S32 proxyId ) { mProxyId = proxyId; }
@@ -299,7 +305,7 @@ protected:
     void updateLocalTransform( void );
     void updateLocalTransform( void );
     void updateWorldTransform( const U32 batchTransformId );
     void updateWorldTransform( const U32 batchTransformId );
 
 
-    void onTamlCustomWrite( TamlCustomNode* pSpriteNode );
+    void onTamlCustomWrite( TamlCustomNode* pParentNode );
     void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
     void onTamlCustomRead( const TamlCustomNode* pSpriteNode );
 };
 };
 
 

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

@@ -39,8 +39,8 @@ SpriteBatchQuery::SpriteBatchQuery( SpriteBatch* pSpriteBatch ) :
         mpSpriteBatch(pSpriteBatch),
         mpSpriteBatch(pSpriteBatch),
         mIsRaycastQueryResult(false),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mComparePoint(0.0f, 0.0f)
 {
 {
     // Set debug associations.
     // Set debug associations.
     VECTOR_SET_ASSOCIATION( mQueryResults );
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryArea);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryArea);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -92,17 +92,26 @@ U32 SpriteBatchQuery::renderQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
     mIsRaycastQueryResult = false;
 
 
     // Query.
     // 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 );
     Query( this, aabb );
+    mCheckOOBB = false;
 
 
     return getQueryResultsCount();
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryRay);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryRay);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -110,23 +119,23 @@ U32 SpriteBatchQuery::renderQueryRay( const Vector2& point1, const Vector2& poin
     mIsRaycastQueryResult = true;
     mIsRaycastQueryResult = true;
 
 
     // Query.
     // 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();
     return getQueryResultsCount();
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
+U32 SpriteBatchQuery::queryPoint( const Vector2& point, const bool targetOOBB )
 {
 {
     // Debug Profiling.
     // Debug Profiling.
-    PROFILE_SCOPE(SpriteBatchQuery_RenderQueryPoint);
+    PROFILE_SCOPE(SpriteBatchQuery_QueryPoint);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -134,12 +143,13 @@ U32 SpriteBatchQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
     mIsRaycastQueryResult = false;
 
 
     // Query.
     // 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();
     return getQueryResultsCount();
 }
 }
@@ -180,6 +190,25 @@ bool SpriteBatchQuery::QueryCallback( S32 proxyId )
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return true;
         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.
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 
 
@@ -203,6 +232,17 @@ F32 SpriteBatchQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
     if ( pSpriteBatchItem->getSpriteBatchQueryKey() == mMasterQueryKey )
         return 1.0f;
         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.
     // Tag with world query key.
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
     pSpriteBatchItem->setSpriteBatchQueryKey( mMasterQueryKey );
 
 

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

@@ -48,10 +48,10 @@ public:
     void            remove( SpriteBatchItem* pSpriteBatchItem );
     void            remove( SpriteBatchItem* pSpriteBatchItem );
     bool            update( SpriteBatchItem* pSpriteBatchItem, const b2AABB& aabb, const b2Vec2& displacement );
     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.
     /// Results.
     void            clearQuery( void );
     void            clearQuery( void );
@@ -74,8 +74,12 @@ private:
 
 
 private:
 private:
     SpriteBatch*                mpSpriteBatch;
     SpriteBatch*                mpSpriteBatch;
-    bool                        mCheckFixturePoint;
-    b2Vec2                      mFixturePoint;
+    b2PolygonShape              mComparePolygonShape;
+    b2RayCastInput              mCompareRay;
+    b2Vec2                      mComparePoint;
+    b2Transform                 mCompareTransform;
+    bool                        mCheckOOBB;
+    bool                        mCheckPoint;
     typeSpriteBatchQueryResultVector mQueryResults;
     typeSpriteBatchQueryResultVector mQueryResults;
     bool                        mIsRaycastQueryResult;
     bool                        mIsRaycastQueryResult;
     typeSceneObjectVector       mAlwaysInScopeSet;
     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.
 // Debug Profiling.
 #include "debug/profiler.h"
 #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);
 IMPLEMENT_CONOBJECT(SceneWindow);
@@ -99,23 +121,6 @@ SceneWindow::SceneWindow() :    mpScene(NULL),
     VECTOR_SET_ASSOCIATION( mInputEventEntering );
     VECTOR_SET_ASSOCIATION( mInputEventEntering );
     VECTOR_SET_ASSOCIATION( mInputEventLeaving );    
     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.
     // Turn-on Tick Processing.
     setProcessTicks( true );
     setProcessTicks( true );
 }
 }
@@ -130,9 +135,14 @@ SceneWindow::~SceneWindow()
 
 
 bool SceneWindow::onAdd()
 bool SceneWindow::onAdd()
 {
 {
+    // Call parent.
     if(!Parent::onAdd())
     if(!Parent::onAdd())
         return false;
         return false;
 
 
+    // Register input sets.
+    mInputEventWatching.registerObject();
+    mInputListeners.registerObject();
+
     // Reset the camera position.
     // Reset the camera position.
     setCameraPosition( Vector2::getZero() );
     setCameraPosition( Vector2::getZero() );
 
 
@@ -156,6 +166,10 @@ void SceneWindow::onRemove()
     // Reset Scene.
     // Reset Scene.
     resetScene();
     resetScene();
 
 
+    // Unregister input sets.
+    mInputEventWatching.unregisterObject();
+    mInputListeners.unregisterObject();
+
     // Call Parent.
     // Call Parent.
     Parent::onRemove();
     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 )
 void SceneWindow::setMousePosition( const Vector2& mousePosition )
 {
 {
     // Fetch Canvas.
     // Fetch Canvas.
@@ -967,6 +1003,13 @@ void SceneWindow::sendWindowInputEvent( StringTableEntry name, const GuiEvent& e
 
 
     // Call Scripts.
     // Call Scripts.
     Con::executef(this, 4, name, argBuffer[0], argBuffer[1], argBuffer[2]);
     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;
     if ( !getScene() ) return;
 
 
     // Only process appropriate input events.
     // Only process appropriate input events.
-    if ( !( name == mInputEventDownName ||
-            name == mInputEventUpName ||
-            name == mInputEventMovedName ||
-            name == mInputEventDraggedName ) )
+    if ( !( name == inputEventDownName ||
+            name == inputEventUpName ||
+            name == inputEventMovedName ||
+            name == inputEventDraggedName ) )
         return;
         return;
 
 
     // Convert Event-Position into scene coordinates.
     // Convert Event-Position into scene coordinates.
@@ -1089,7 +1132,7 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventLeaving[index];
         SceneObject* pSceneObject = mInputEventLeaving[index];
 
 
         // Emit event.
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventLeaveName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventLeaveName, event, worldMousePoint );
 
 
         // Remove scene object.
         // Remove scene object.
         mInputEventWatching.removeObject( pSceneObject );
         mInputEventWatching.removeObject( pSceneObject );
@@ -1102,10 +1145,10 @@ void SceneWindow::sendObjectInputEvent( StringTableEntry name, const GuiEvent& e
         SceneObject* pSceneObject = mInputEventEntering[index];
         SceneObject* pSceneObject = mInputEventEntering[index];
 
 
         // Emit event.
         // Emit event.
-        pSceneObject->onInputEvent( mInputEventEnterName, event, worldMousePoint );
+        pSceneObject->onInputEvent( inputEventEnterName, event, worldMousePoint );
 
 
         // Process "moved" or "dragged" events.
         // Process "moved" or "dragged" events.
-        if ( name == mInputEventMovedName || name == mInputEventDraggedName )
+        if ( name == inputEventMovedName || name == inputEventDraggedName )
             pSceneObject->onInputEvent( name, event, worldMousePoint );
             pSceneObject->onInputEvent( name, event, worldMousePoint );
 
 
         // Add scene object.
         // 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 )
 void SceneWindow::onMouseDown( const GuiEvent& event )
 {
 {
     // Lock Mouse (if necessary).
     // Lock Mouse (if necessary).
@@ -1127,7 +1186,7 @@ void SceneWindow::onMouseDown( const GuiEvent& event )
         mouseLock();
         mouseLock();
 
 
     // Dispatch input event.
     // Dispatch input event.
-    dispatchInputEvent( mInputEventDownName, event);
+    dispatchInputEvent( inputEventDownName, event);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1139,7 +1198,7 @@ void SceneWindow::onMouseUp( const GuiEvent& event )
         mouseUnlock();
         mouseUnlock();
 
 
     // Dispatch input event.
     // 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 )
 void SceneWindow::onMouseMove( const GuiEvent& event )
 {
 {
     // Dispatch input 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 )
 void SceneWindow::onMouseDragged( const GuiEvent& event )
 {
 {
     // Dispatch input 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.
     // 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.
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventLeaveName, event);
+    dispatchInputEvent(mouseEventMiddleMouseDraggedName, event);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1183,7 +1258,7 @@ void SceneWindow::onRightMouseDown( const GuiEvent& event )
         mouseLock();
         mouseLock();
 
 
     // Dispatch input event.
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDownName, event);
+    dispatchInputEvent(mouseEventRightMouseDownName, event);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1195,7 +1270,7 @@ void SceneWindow::onRightMouseUp( const GuiEvent& event )
         mouseUnlock();
         mouseUnlock();
 
 
     // Dispatch input event.
     // 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 )
 void SceneWindow::onRightMouseDragged( const GuiEvent& event )
 {
 {
     // Dispatch input event.
     // Dispatch input event.
-    dispatchInputEvent(mMouseEventRightMouseDraggedName, event);
+    dispatchInputEvent(mouseEventRightMouseDraggedName, event);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -1214,7 +1289,7 @@ bool SceneWindow::onMouseWheelUp( const GuiEvent& event )
    Parent::onMouseWheelUp( event );
    Parent::onMouseWheelUp( event );
 
 
    // Dispatch input event.
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelUpName, event);
+   dispatchInputEvent(mouseEventWheelUpName, event);
 
 
    // Return Success.
    // Return Success.
    return true;
    return true;
@@ -1228,7 +1303,7 @@ bool SceneWindow::onMouseWheelDown( const GuiEvent& event )
    Parent::onMouseWheelDown( event );
    Parent::onMouseWheelDown( event );
 
 
    // Dispatch input event.
    // Dispatch input event.
-   dispatchInputEvent(mMouseEventWheelDownName, event);
+   dispatchInputEvent(mouseEventWheelDownName, event);
 
 
    // Return Success.
    // Return Success.
    return true;
    return true;
@@ -1689,7 +1764,7 @@ void SceneWindow::renderMetricsOverlay( Point2I offset, const RectI& updateRect
     glEnable        ( GL_BLEND );
     glEnable        ( GL_BLEND );
     glBlendFunc     ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
     glBlendFunc     ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
 
 
-    // Set banner background colour.
+    // Set banner background color.
     const ColorI& fillColor = mProfile->mFillColor;
     const ColorI& fillColor = mProfile->mFillColor;
     const F32 colorScale = 1.0f / 255.0f;
     const F32 colorScale = 1.0f / 255.0f;
     glColor4f( fillColor.red * colorScale, fillColor.green * colorScale, fillColor.blue * colorScale, fillColor.alpha * colorScale );
     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.
     // Disable Banner Blending.
     glDisable       ( GL_BLEND );
     glDisable       ( GL_BLEND );
         
         
-    // Set Debug Text Colour.
+    // Set Debug Text color.
     dglSetBitmapModulation( mProfile->mFontColor );
     dglSetBitmapModulation( mProfile->mFontColor );
 
 
     // ****************************************************************
     // ****************************************************************

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

@@ -131,27 +131,11 @@ private:
     U32                 mInputEventGroupMaskFilter;
     U32                 mInputEventGroupMaskFilter;
     U32                 mInputEventLayerMaskFilter;
     U32                 mInputEventLayerMaskFilter;
     bool                mInputEventInvisibleFilter;
     bool                mInputEventInvisibleFilter;
-    SimSet              mInputEventWatching;
     typeWorldQueryResultVector mInputEventQuery;
     typeWorldQueryResultVector mInputEventQuery;
     typeSceneObjectVector mInputEventEntering;
     typeSceneObjectVector mInputEventEntering;
     typeSceneObjectVector mInputEventLeaving;
     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.
     /// Render Masks.
     U32                 mRenderLayerMask;
     U32                 mRenderLayerMask;
@@ -220,6 +204,9 @@ public:
     inline void clearWatchedInputEvents( void ) { mInputEventWatching.clear(); }
     inline void clearWatchedInputEvents( void ) { mInputEventWatching.clear(); }
     inline void removeFromInputEventPick(SceneObject* pSceneObject ) { mInputEventWatching.removeObject((SimObject*)pSceneObject); }
     inline void removeFromInputEventPick(SceneObject* pSceneObject ) { mInputEventWatching.removeObject((SimObject*)pSceneObject); }
 
 
+    void addInputListener( SimObject* pSimObject );
+    void removeInputListener( SimObject* pSimObject );
+
     /// Coordinate Conversion.
     /// Coordinate Conversion.
     void windowToScenePoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
     void windowToScenePoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
     void sceneToWindowPoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
     void sceneToWindowPoint( const Vector2& srcPoint, Vector2& dstPoint ) const;
@@ -304,18 +291,27 @@ public:
 
 
     /// GuiControl
     /// GuiControl
     virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
     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 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 );
     void renderMetricsOverlay( Point2I offset, const RectI& updateRect );
 
 
     static CameraInterpolationMode getInterpolationModeEnum(const char* label);
     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."
 ConsoleMethod(SceneWindow, setLockMouse, void, 3, 3, "(bool lockSet) Sets the window mouse-lock status."
               "@return No return value.")
               "@return No return value.")
 {
 {

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

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

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

@@ -23,17 +23,13 @@
 #ifndef _GUISPRITECTRL_H_
 #ifndef _GUISPRITECTRL_H_
 #define _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
 #endif
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-class GuiSpriteCtrl : public GuiControl, public SpriteProxyBase
+class GuiSpriteCtrl : public GuiControl, public ImageFrameProvider
 {
 {
 private:
 private:
     typedef GuiControl Parent;
     typedef GuiControl Parent;
@@ -63,13 +59,13 @@ protected:
 
 
 protected:
 protected:
     static bool setImage(void* obj, const char* data) { static_cast<GuiSpriteCtrl*>(obj)->setImage( data ); return false; }
     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 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 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_
 #endif //_GUISPRITECTRL_H_

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

@@ -20,10 +20,10 @@
 // IN THE SOFTWARE.
 // 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 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.")
                                                             "@return (string imageAssetId) The image being displayed.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "GuiSpriteCtrl::getImage() - Method invalid, not in static mode." );
         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.
     // 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.")
                                                         "@return (int frame) The frame currently being displayed.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( !object->isStaticMode() )
+    if ( !object->isStaticFrameProvider() )
     {
     {
         // No, so warn.
         // No, so warn.
         Con::warnf( "GuiSpriteCtrl::getFrame() - Method invalid, not in static mode." );
         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.")
                                                                 "@return (string ianimationAssetId) The animation being displayed.")
 {
 {
     // Are we in static mode?
     // Are we in static mode?
-    if ( object->isStaticMode() )
+    if ( object->isStaticFrameProvider() )
     {
     {
         // Yes, so warn.
         // Yes, so warn.
         Con::warnf( "GuiSpriteCtrl::getAnimation() - Method invalid, in static mode." );
         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.
     // 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 )
     if ( pSceneObjectA->mCollisionSuppress || pSceneObjectB->mCollisionSuppress )
         return false;
         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;
 }
 }

ファイルの差分が大きいため隠しています
+ 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"
 #include "component/behaviors/behaviorComponent.h"
 #endif
 #endif
 
 
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 extern EnumTable jointTypeTable;
 extern EnumTable jointTypeTable;
@@ -162,11 +166,12 @@ class Scene :
     public virtual Tickable
     public virtual Tickable
 {
 {
 public:
 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<tDeleteRequest>              typeDeleteVector;
     typedef Vector<TickContact>                 typeContactVector;
     typedef Vector<TickContact>                 typeContactVector;
     typedef HashMap<b2Contact*, TickContact>    typeContactHash;
     typedef HashMap<b2Contact*, TickContact>    typeContactHash;
+    typedef Vector<AssetPtr<AssetBase>*>        typeAssetPtrVector;
 
 
     /// Scene Debug Options.
     /// Scene Debug Options.
     enum DebugOption
     enum DebugOption
@@ -193,7 +198,8 @@ public:
         PICK_INVALID,
         PICK_INVALID,
         ///---
         ///---
         PICK_ANY,
         PICK_ANY,
-        PICK_SIZE,
+        PICK_AABB,
+        PICK_OOBB,
         PICK_COLLISION,
         PICK_COLLISION,
     };
     };
 
 
@@ -202,6 +208,7 @@ public:
 
 
 private:
 private:
     typedef BehaviorComponent   Parent;
     typedef BehaviorComponent   Parent;
+    typedef SceneObject         Children;
 
 
     /// World.
     /// World.
     b2World*                    mpWorld;
     b2World*                    mpWorld;
@@ -219,10 +226,13 @@ private:
     /// Joint access.
     /// Joint access.
     typeJointHash               mJoints;
     typeJointHash               mJoints;
     typeReverseJointHash        mReverseJoints;
     typeReverseJointHash        mReverseJoints;
-    U32                         mJointMasterId;
+    S32                         mJointMasterId;
 
 
-	/// Scene controllers.
-	SimObjectPtr<SimSet>	    mControllers;
+    /// Scene controllers.
+    SimObjectPtr<SimSet>	    mControllers;
+
+    /// Asset pre-loads.
+    typeAssetPtrVector          mAssetPreloads;
 
 
     /// Scene time.
     /// Scene time.
     F32                         mSceneTime;
     F32                         mSceneTime;
@@ -343,7 +353,13 @@ public:
 
 
     void                    mergeScene( const Scene* pScene );
     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.
     /// Scene time.
     inline F32              getSceneTime( void ) const                  { return mSceneTime; };
     inline F32              getSceneTime( void ) const                  { return mSceneTime; };
@@ -352,15 +368,15 @@ public:
 
 
     /// Joint access.
     /// Joint access.
     inline U32              getJointCount( void ) const                 { return mJoints.size(); }
     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                    deleteJoint( const U32 jointId );
     bool                    hasJoints( SceneObject* pSceneObject );
     bool                    hasJoints( SceneObject* pSceneObject );
 
 
     /// Distance joint.
     /// Distance joint.
-    U32                     createDistanceJoint(
+    S32                     createDistanceJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 length = -1.0f,
                                 const F32 length = -1.0f,
@@ -387,7 +403,7 @@ public:
     F32                     getDistanceJointDampingRatio( const U32 jointId );
     F32                     getDistanceJointDampingRatio( const U32 jointId );
 
 
     /// Rope joint.
     /// Rope joint.
-    U32                     createRopeJoint(
+    S32                     createRopeJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 maxLength = -1.0f,
                                 const F32 maxLength = -1.0f,
@@ -400,7 +416,7 @@ public:
     F32                     getRopeJointMaxLength( const U32 jointId );
     F32                     getRopeJointMaxLength( const U32 jointId );
 
 
     /// Revolute joint.
     /// Revolute joint.
-    U32                     createRevoluteJoint(
+    S32                     createRevoluteJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const bool collideConnected = false );
                                 const bool collideConnected = false );
@@ -426,8 +442,12 @@ public:
                                 bool& enableMotor,
                                 bool& enableMotor,
                                 F32& motorSpeed,
                                 F32& motorSpeed,
                                 F32& maxMotorTorque );
                                 F32& maxMotorTorque );
+
+	F32                     getRevoluteJointAngle( const U32 jointId );
+	F32						getRevoluteJointSpeed( const U32 jointId );
+
     /// Weld joint.
     /// Weld joint.
-    U32                     createWeldJoint(
+    S32                     createWeldJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 frequency = 0.0f,
                                 const F32 frequency = 0.0f,
@@ -447,7 +467,7 @@ public:
     F32                     getWeldJointDampingRatio( const U32 jointId );
     F32                     getWeldJointDampingRatio( const U32 jointId );
 
 
     /// Wheel joint.
     /// Wheel joint.
-    U32                     createWheelJoint(
+    S32                     createWheelJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldAxis,
                                 const b2Vec2& worldAxis,
@@ -478,7 +498,7 @@ public:
     F32                     getWheelJointDampingRatio( const U32 jointId );
     F32                     getWheelJointDampingRatio( const U32 jointId );
 
 
     /// Friction joint.
     /// Friction joint.
-    U32                     createFrictionJoint(
+    S32                     createFrictionJoint(
                                 const SceneObject* pSceneObjectA,const  SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA,const  SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const b2Vec2& localAnchorA = b2Vec2_zero, const b2Vec2& localAnchorB = b2Vec2_zero,
                                 const F32 maxForce = 0.0f,
                                 const F32 maxForce = 0.0f,
@@ -498,7 +518,7 @@ public:
     F32                     getFrictionJointMaxTorque( const U32 jointId );
     F32                     getFrictionJointMaxTorque( const U32 jointId );
 
 
     /// Prismatic joint.
     /// Prismatic joint.
-    U32                     createPrismaticJoint(
+    S32                     createPrismaticJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldAxis,
                                 const b2Vec2& worldAxis,
@@ -527,7 +547,7 @@ public:
                                 F32& maxMotorTorque );
                                 F32& maxMotorTorque );
 
 
     /// Pulley joint.
     /// Pulley joint.
-    U32                     createPulleyJoint(
+    S32                     createPulleyJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& localAnchorA, const b2Vec2& localAnchorB,
                                 const b2Vec2& worldGroundAnchorA, const b2Vec2& worldGroundAnchorB,
                                 const b2Vec2& worldGroundAnchorA, const b2Vec2& worldGroundAnchorB,
@@ -536,7 +556,7 @@ public:
                                 const bool collideConnected = false );
                                 const bool collideConnected = false );
 
 
     /// Target (a.k.a Mouse) joint.
     /// Target (a.k.a Mouse) joint.
-    U32                     createTargetJoint(
+    S32                     createTargetJoint(
                                 const SceneObject* pSceneObject,
                                 const SceneObject* pSceneObject,
                                 const b2Vec2& worldTarget,
                                 const b2Vec2& worldTarget,
                                 const F32 maxForce,
                                 const F32 maxForce,
@@ -570,7 +590,7 @@ public:
     F32                     getTargetJointDampingRatio( const U32 jointId );
     F32                     getTargetJointDampingRatio( const U32 jointId );
 
 
     /// Motor Joint.
     /// Motor Joint.
-    U32                     createMotorJoint(
+    S32                     createMotorJoint(
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const SceneObject* pSceneObjectA, const SceneObject* pSceneObjectB,
                                 const b2Vec2 linearOffset = b2Vec2_zero,
                                 const b2Vec2 linearOffset = b2Vec2_zero,
                                 const F32 angularOffset = 0.0f,
                                 const F32 angularOffset = 0.0f,
@@ -629,7 +649,9 @@ public:
 
 
     /// Destruction listeners.
     /// Destruction listeners.
     virtual                 void SayGoodbye( b2Joint* pJoint );
     virtual                 void SayGoodbye( b2Joint* pJoint );
-    virtual                 void SayGoodbye( b2Fixture* pFixture );
+    virtual                 void SayGoodbye( b2Fixture* pFixture )      {}
+
+    virtual SceneObject*    create( const char* pType );
 
 
     /// Miscellaneous.
     /// Miscellaneous.
     inline void             setBatchingEnabled( const bool enabled )    { mBatchRenderer.setBatchEnabled( enabled ); }
     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,
         U32 renderGroupMask,
         const Vector2& renderScale,
         const Vector2& renderScale,
         DebugStats* pDebugStats,
         DebugStats* pDebugStats,
-        GuiControl* pGuiControl )
+        SimObject* pRenderHost )
     {
     {
         mRenderArea       = renderArea;
         mRenderArea       = renderArea;
         mRenderAABB       = CoreMath::mRectFtoAABB( renderArea );
         mRenderAABB       = CoreMath::mRectFtoAABB( renderArea );
@@ -56,7 +56,7 @@ struct SceneRenderState
         mRenderLayerMask  = renderLayerMask;
         mRenderLayerMask  = renderLayerMask;
         mRenderGroupMask  = renderGroupMask;
         mRenderGroupMask  = renderGroupMask;
         mpDebugStats      = pDebugStats;
         mpDebugStats      = pDebugStats;
-        mpGuiControl      = pGuiControl;
+        mpRenderHost      = pRenderHost;
     }
     }
 
 
     RectF           mRenderArea;
     RectF           mRenderArea;
@@ -67,7 +67,7 @@ struct SceneRenderState
     U32             mRenderGroupMask;
     U32             mRenderGroupMask;
     Vector2         mRenderScale;
     Vector2         mRenderScale;
     DebugStats*     mpDebugStats;
     DebugStats*     mpDebugStats;
-    GuiControl*     mpGuiControl;
+    SimObject*      mpRenderHost;
 
 
 
 
 };
 };

ファイルの差分が大きいため隠しています
+ 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),
         mpScene(pScene),
         mIsRaycastQueryResult(false),
         mIsRaycastQueryResult(false),
         mMasterQueryKey(0),
         mMasterQueryKey(0),
-        mCheckFixturePoint(false),
-        mFixturePoint(0.0f, 0.0f)
+        mCheckPoint(false),
+        mCheckAABB(false),
+        mCheckOOBB(false),
+        mCheckCircle(false)
 {
 {
     // Set debug associations.
     // Set debug associations.
     for ( U32 n = 0; n < MAX_LAYERS_SUPPORTED; n++ )
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryArea);
+    PROFILE_SCOPE(WorldQuery_collisionQueryAABB);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -141,7 +143,16 @@ U32 WorldQuery::fixtureQueryArea( const b2AABB& aabb )
     mIsRaycastQueryResult = false;
     mIsRaycastQueryResult = false;
 
 
     // Query.
     // 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 );
     mpScene->getWorld()->QueryAABB( this, aabb );
+    mCheckAABB = false;
 
 
     // Inject always-in-scope.
     // Inject always-in-scope.
     injectAlwaysInScope();
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryRay);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryRay);
 
 
     mMasterQueryKey++;
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_FixtureQueryPoint);
+    PROFILE_SCOPE(WorldQuery_CollisionQueryPoint);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -186,10 +197,10 @@ U32 WorldQuery::fixtureQueryPoint( const Vector2& point )
     b2AABB aabb;
     b2AABB aabb;
     aabb.lowerBound = point;
     aabb.lowerBound = point;
     aabb.upperBound = point;
     aabb.upperBound = point;
-    mCheckFixturePoint = true;
-    mFixturePoint = point;
+    mCheckPoint = true;
+    mComparePoint = point;
     mpScene->getWorld()->QueryAABB( this, aabb );
     mpScene->getWorld()->QueryAABB( this, aabb );
-    mCheckFixturePoint = false;
+    mCheckPoint = false;
 
 
     // Inject always-in-scope.
     // Inject always-in-scope.
     injectAlwaysInScope();
     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.
     // 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++;
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryRay);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -231,13 +270,35 @@ U32 WorldQuery::renderQueryRay( const Vector2& point1, const Vector2& point2 )
     mIsRaycastQueryResult = true;
     mIsRaycastQueryResult = true;
 
 
     // Query.
     // 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.
     // Inject always-in-scope.
     injectAlwaysInScope();
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_RenderQueryPoint);
+    PROFILE_SCOPE(WorldQuery_AABBQueryCircle);
 
 
     mMasterQueryKey++;
     mMasterQueryKey++;
 
 
@@ -258,12 +319,46 @@ U32 WorldQuery::renderQueryPoint( const Vector2& point )
     mIsRaycastQueryResult = false;
     mIsRaycastQueryResult = false;
 
 
     // Query.
     // 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.
     // Inject always-in-scope.
     injectAlwaysInScope();
     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.
     // Debug Profiling.
-    PROFILE_SCOPE(WorldQuery_AnyQueryAreaAABB);
+    PROFILE_SCOPE(WorldQuery_AABBQueryRay);
+
+    mMasterQueryKey++;
+
+    // Flag as a ray-cast query result.
+    mIsRaycastQueryResult = true;
 
 
     // Query.
     // 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.
     // Inject always-in-scope.
     injectAlwaysInScope();
     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.
     // 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;
     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.
     // 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);
     PROFILE_SCOPE(WorldQuery_AnyQueryRay);
 
 
     // Query.
     // Query.
-    renderQueryRay( point1, point2 );
+    oobbQueryRay( point1, point2 );
     mMasterQueryKey--;
     mMasterQueryKey--;
-    fixtureQueryRay( point1, point2 );
+    collisionQueryRay( point1, point2 );
 
 
     // Inject always-in-scope.
     // Inject always-in-scope.
     injectAlwaysInScope();
     injectAlwaysInScope();
@@ -331,9 +497,27 @@ U32 WorldQuery::anyQueryPoint( const Vector2& point )
     PROFILE_SCOPE(WorldQuery_AnyQueryPoint);
     PROFILE_SCOPE(WorldQuery_AnyQueryPoint);
 
 
     // Query.
     // Query.
-    renderQueryPoint( point );
+    oobbQueryPoint( point );
     mMasterQueryKey--;
     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.
     // Inject always-in-scope.
     injectAlwaysInScope();
     injectAlwaysInScope();
@@ -425,12 +609,19 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
         return true;
 
 
-    // Check fixture point.
-    if ( mCheckFixturePoint && !fixture->TestPoint( mFixturePoint ) )
+    // Check collision point.
+    if ( mCheckPoint && !fixture->TestPoint( mComparePoint ) )
         return true;
         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.
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -442,6 +633,9 @@ bool WorldQuery::ReportFixture( b2Fixture* fixture )
         WorldQueryResult queryResult( pSceneObject );
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
     }
 
 
     return true;
     return true;
@@ -478,9 +672,6 @@ F32 WorldQuery::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
         return 1.0f;
 
 
-    // Tag with world query key.
-    pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
     // Fetch layer and group masks.
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneGroupMask = pSceneObject->getSceneGroupMask();
     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 );
     const S32 shapeIndex = pSceneObject->getCollisionShapeIndex( fixture );
 
 
     // Sanity!
     // 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.
     // Compare masks and report.
     if ( (mQueryFilter.mSceneLayerMask & sceneLayerMask) != 0 && (mQueryFilter.mSceneGroupMask & sceneGroupMask) != 0 )
     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 );
         WorldQueryResult queryResult( pSceneObject, point, normal, fraction, (U32)shapeIndex );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
     }
 
 
     return 1.0f;
     return 1.0f;
@@ -533,8 +727,48 @@ bool WorldQuery::QueryCallback( S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return true;
         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.
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -546,6 +780,9 @@ bool WorldQuery::QueryCallback( S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
     }
 
 
     return true;
     return true;
@@ -582,8 +819,16 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
     if ( mQueryFilter.mPickingAllowedFilter && !pSceneObject->getPickingAllowed() )
         return 1.0f;
         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.
     // Fetch layer and group masks.
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
     const U32 sceneLayerMask = pSceneObject->getSceneLayerMask();
@@ -595,6 +840,9 @@ F32 WorldQuery::RayCastCallback( const b2RayCastInput& input, S32 proxyId )
         WorldQueryResult queryResult( pSceneObject );
         WorldQueryResult queryResult( pSceneObject );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
         mQueryResults.push_back( queryResult );
         mQueryResults.push_back( queryResult );
+
+        // Tag with world query key.
+        pSceneObject->setWorldQueryKey( mMasterQueryKey );
     }
     }
 
 
     return 1.0f;
     return 1.0f;
@@ -621,9 +869,6 @@ void WorldQuery::injectAlwaysInScope( void )
         if ( pSceneObject->getWorldQueryKey() == mMasterQueryKey )
         if ( pSceneObject->getWorldQueryKey() == mMasterQueryKey )
             continue;
             continue;
 
 
-        // Tag with world query key.
-        pSceneObject->setWorldQueryKey( mMasterQueryKey );
-
         // Enabled filter.
         // Enabled filter.
         if ( mQueryFilter.mEnabledFilter && !pSceneObject->isEnabled() )
         if ( mQueryFilter.mEnabledFilter && !pSceneObject->isEnabled() )
             continue;
             continue;
@@ -646,6 +891,9 @@ void WorldQuery::injectAlwaysInScope( void )
             WorldQueryResult queryResult( pSceneObject );
             WorldQueryResult queryResult( pSceneObject );
             mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
             mLayeredQueryResults[pSceneObject->getSceneLayer()].push_back( queryResult );
             mQueryResults.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            addAlwaysInScope( SceneObject* pSceneObject );
     void            removeAlwaysInScope( 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             anyQueryRay( const Vector2& point1, const Vector2& point2 );
     U32             anyQueryPoint( const Vector2& point );
     U32             anyQueryPoint( const Vector2& point );
+    U32             anyQueryCircle( const Vector2& centroid, const F32 radius );
 
 
     /// Filtering.
     /// Filtering.
     inline void     setQueryFilter( const WorldQueryFilter& queryFilter ) { mQueryFilter = queryFilter; }
     inline void     setQueryFilter( const WorldQueryFilter& queryFilter ) { mQueryFilter = queryFilter; }
@@ -96,8 +104,15 @@ private:
 private:
 private:
     Scene*                      mpScene;
     Scene*                      mpScene;
     WorldQueryFilter            mQueryFilter;
     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  mLayeredQueryResults[MAX_LAYERS_SUPPORTED];
     typeWorldQueryResultVector  mQueryResults;
     typeWorldQueryResultVector  mQueryResults;
     bool                        mIsRaycastQueryResult;
     bool                        mIsRaycastQueryResult;

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

@@ -81,10 +81,6 @@ const char* CompositeSprite::getBatchLayoutTypeDescription(const CompositeSprite
     return StringTable->EmptyString;
     return StringTable->EmptyString;
 }
 }
 
 
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(CompositeSprite);
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 CompositeSprite::CompositeSprite() :
 CompositeSprite::CompositeSprite() :
@@ -108,8 +104,8 @@ void CompositeSprite::initPersistFields()
     Parent::initPersistFields();
     Parent::initPersistFields();
 
 
     /// Defaults.
     /// 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( "DefaultSpriteAngle", TypeF32, Offset(mDefaultSpriteSize, CompositeSprite), &setDefaultSpriteAngle, &getDefaultSpriteAngle, &writeDefaultSpriteAngle, "");
     addProtectedField( "BatchLayout", TypeEnum, Offset(mBatchLayoutType, CompositeSprite), &setBatchLayout, &defaultProtectedGetFn, &writeBatchLayout, 1, &batchLayoutTypeTable, "");
     addProtectedField( "BatchLayout", TypeEnum, Offset(mBatchLayoutType, CompositeSprite), &setBatchLayout, &defaultProtectedGetFn, &writeBatchLayout, 1, &batchLayoutTypeTable, "");
     addProtectedField( "BatchCulling", TypeBool, Offset(mBatchCulling, CompositeSprite), &setBatchCulling, &defaultProtectedGetFn, &writeBatchCulling, "");
     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 )
 void CompositeSprite::preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats )
 {
 {
     // Are the spatials dirty?
     // Are the spatials dirty?
@@ -248,8 +267,8 @@ SpriteBatchItem* CompositeSprite::createSprite( const SpriteBatchItem::LogicalPo
             return createCustomLayout( logicalPosition );
             return createCustomLayout( logicalPosition );
 
 
         default:
         default:
-            // Sanity!
-            AssertFatal( false, "CompositeSprite::createSprite() - Unknown layout type encountered." );
+            // Warn.
+            Con::warnf( "CompositeSprite::createSprite() - Unknown layout type encountered." );
             return SpriteBatch::createSprite( logicalPosition );
             return SpriteBatch::createSprite( logicalPosition );
     }
     }
 }
 }
@@ -386,18 +405,8 @@ void CompositeSprite::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Call parent.
     // Call parent.
     Parent::onTamlCustomWrite( customNodes );
     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.
     // Write node with sprite batch.
-    SpriteBatch::onTamlCustomWrite( pSpritesNode );
+    SpriteBatch::onTamlCustomWrite( customNodes );
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -407,13 +416,22 @@ void CompositeSprite::onTamlCustomRead( const TamlCustomNodes& customNodes )
     // Call parent.
     // Call parent.
     Parent::onTamlCustomRead( customNodes );
     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();
     static void initPersistFields();
 
 
+    virtual bool onAdd();
+    virtual void onRemove();
+
     virtual void preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
     virtual void preIntegrate( const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats );
     virtual void integrateObject( 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 interpolateObject( const F32 timeDelta );
@@ -89,9 +92,11 @@ protected:
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
     virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
 
 
 protected:
 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 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 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         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; }
     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 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." )
                                                                 "@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.")
                                                                         "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getSpriteBlendColor();
     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 );
     point = b2MulT( renderTransform, point );
 
 
     // Perform query.
     // Perform query.
-    pSpriteBatchQuery->renderQueryPoint( point );
+    pSpriteBatchQuery->queryPoint( point, true );
 
 
     // Fetch result count.
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
     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 );
     CoreMath::mRotateAABB( aabb, -renderTransform.q.GetAngle(), aabb );
 
 
     // Perform query.
     // Perform query.
-    pSpriteBatchQuery->renderQueryArea( aabb );
+    pSpriteBatchQuery->queryArea( aabb, true );
 
 
     // Fetch result count.
     // Fetch result count.
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
     const U32 resultCount = pSpriteBatchQuery->getQueryResultsCount();
@@ -1146,7 +1153,7 @@ ConsoleMethod(CompositeSprite, pickRay, const char*, 4, 6,  "(startx/y, endx/y)
     v2 = b2MulT( renderTransform, v2 );
     v2 = b2MulT( renderTransform, v2 );
 
 
     // Perform query.
     // Perform query.
-    pSpriteBatchQuery->renderQueryRay( v1, v2 );
+    pSpriteBatchQuery->queryRay( v1, v2, true );
 
 
     // Sanity!
     // Sanity!
     AssertFatal( pSpriteBatchQuery->getIsRaycastQueryResult(), "Invalid non-ray-cast query result returned." );
     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!
     // Sanity!
     AssertFatal( mOwner != NULL, "ParticlePlayer::EmitterNode::freeParticle() - Cannot free a particle with a NULL owner." );
     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.
     // Remove the node from the emitter chain.
     pParticleNode->mPreviousNode->mNextNode = pParticleNode->mNextNode;
     pParticleNode->mPreviousNode->mNextNode = pParticleNode->mNextNode;
     pParticleNode->mNextNode->mPreviousNode = pParticleNode->mPreviousNode;
     pParticleNode->mNextNode->mPreviousNode = pParticleNode->mPreviousNode;
@@ -97,7 +100,8 @@ ParticlePlayer::ParticlePlayer() :
     mEmissionRateScale = Con::getFloatVariable( PARTICLE_PLAYER_EMISSION_RATE_SCALE, 1.0f );
     mEmissionRateScale = Con::getFloatVariable( PARTICLE_PLAYER_EMISSION_RATE_SCALE, 1.0f );
     mSizeScale         = Con::getFloatVariable( PARTICLE_PLAYER_SIZE_SCALE, 1.0f );
     mSizeScale         = Con::getFloatVariable( PARTICLE_PLAYER_SIZE_SCALE, 1.0f );
     mForceScale        = Con::getFloatVariable( PARTICLE_PLAYER_FORCE_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.
     // Register for refresh notifications.
     mParticleAsset.registerRefreshNotify( this );
     mParticleAsset.registerRefreshNotify( this );
 }
 }
@@ -123,6 +127,7 @@ void ParticlePlayer::initPersistFields()
     addProtectedField( "EmissionRateScale", TypeF32, Offset(mEmissionRateScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeEmissionRateScale, "" );
     addProtectedField( "EmissionRateScale", TypeF32, Offset(mEmissionRateScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeEmissionRateScale, "" );
     addProtectedField( "SizeScale", TypeF32, Offset(mSizeScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeSizeScale, "" );
     addProtectedField( "SizeScale", TypeF32, Offset(mSizeScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeSizeScale, "" );
     addProtectedField( "ForceScale", TypeF32, Offset(mForceScale, ParticlePlayer), &defaultProtectedSetFn, &defaultProtectedGetFn, &writeForceScale, "" );
     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->setEmissionRateScale( getEmissionRateScale() );
    pParticlePlayer->setSizeScale( getSizeScale() );
    pParticlePlayer->setSizeScale( getSizeScale() );
    pParticlePlayer->setForceScale( getForceScale() );
    pParticlePlayer->setForceScale( getForceScale() );
+   pParticlePlayer->setTimeScale( getTimeScale() );
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -265,6 +271,9 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
             mEmitters.size() == 0 )
             mEmitters.size() == 0 )
         return;
         return;
 
 
+    // Calculate scaled time.
+    const F32 scaledTime = elapsedTime * mTimeScale;
+
     // Fetch particle asset.
     // Fetch particle asset.
     ParticleAsset* pParticleAsset = mParticleAsset;
     ParticleAsset* pParticleAsset = mParticleAsset;
 
 
@@ -279,7 +288,7 @@ void ParticlePlayer::integrateObject( const F32 totalTime, const F32 elapsedTime
     if ( !mCameraIdle )
     if ( !mCameraIdle )
     {
     {
         // No, so update the particle player age.
         // No, so update the particle player age.
-        mAge += elapsedTime;
+        mAge += scaledTime;
 
 
         // Iterate the emitters.
         // Iterate the emitters.
         for( typeEmitterVector::iterator emitterItr = mEmitters.begin(); emitterItr != mEmitters.end(); ++emitterItr )
         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 )
             while ( pParticleNode != pParticleNodeHead )
             {
             {
                 // Update the particle age.
                 // Update the particle age.
-                pParticleNode->mParticleAge += elapsedTime;
+                pParticleNode->mParticleAge += scaledTime;
 
 
                 // Has the particle expired?
                 // Has the particle expired?
                 // NOTE:-   If we're in single-particle mode then the particle lives as long as the particle player does.
                 // 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
                 else
                 {
                 {
                     // No, so integrate the particle.
                     // 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.
                     // Move to the next particle node.
                     pParticleNode = pParticleNode->mNextNode;
                     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
                 // 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!
                 //          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.
                 // Fetch the particle player age.
                 const F32 particlePlayerAge = mAge;
                 const F32 particlePlayerAge = mAge;
@@ -545,10 +554,10 @@ void ParticlePlayer::sceneRender( const SceneRenderState* pSceneRenderState, con
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
 
 
         // Fetch static mode.
         // Fetch static mode.
-        const bool isStaticMode = pParticleAssetEmitter->isStaticMode();
+        const bool isStaticFrameProvider = pParticleAssetEmitter->isStaticFrameProvider();
 
 
         // Are we in static mode?
         // Are we in static mode?
-        if ( isStaticMode )
+        if ( isStaticFrameProvider )
         {
         {
             // Yes, so skip if no image available.
             // Yes, so skip if no image available.
             if ( imageAsset.isNull() )
             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.
         // Fetch the oldest-in-front flag.
         const bool oldestInFront = pParticleAssetEmitter->getOldestInFront();
         const bool oldestInFront = pParticleAssetEmitter->getOldestInFront();
 
 
@@ -636,23 +625,17 @@ void ParticlePlayer::sceneRender( const SceneRenderState* pSceneRenderState, con
         // Fetch the particle node head.
         // Fetch the particle node head.
         ParticleSystem::ParticleNode* pParticleNodeHead = pEmitterNode->getParticleNodeHead();
         ParticleSystem::ParticleNode* pParticleNodeHead = pEmitterNode->getParticleNodeHead();
 
 
-        // Process All particle nodes.
+        // Process all particle nodes.
         while ( pParticleNode != pParticleNodeHead )
         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.
             // Fetch the particle render OOBB.
             Vector2* renderOOBB = pParticleNode->mRenderOOBB;
             Vector2* renderOOBB = pParticleNode->mRenderOOBB;
@@ -1268,8 +1251,14 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
     // Image, Frame and Animation Controller.
     // 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?
     // Is the emitter in static mode?
-    if ( pParticleAssetEmitter->isStaticMode() )
+    if ( pParticleAssetEmitter->isStaticFrameProvider() )
     {
     {
         // Yes, so is random image frame active?
         // Yes, so is random image frame active?
         if ( pParticleAssetEmitter->getRandomImageFrame() )
         if ( pParticleAssetEmitter->getRandomImageFrame() )
@@ -1278,12 +1267,12 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
             const U32 frameCount = pParticleAssetEmitter->getImageAsset()->getFrameCount();
             const U32 frameCount = pParticleAssetEmitter->getImageAsset()->getFrameCount();
 
 
             // Choose a random frame.
             // Choose a random frame.
-            pParticleNode->mImageFrame = (U32)CoreMath::mGetRandomI( 0, frameCount-1 );
+            frameProvider.setImageFrame( (U32)CoreMath::mGetRandomI( 0, frameCount-1 ) );
         }
         }
         else
         else
         {
         {
             // No, so set the emitter image frame.
             // No, so set the emitter image frame.
-            pParticleNode->mImageFrame = pParticleAssetEmitter->getImageFrame();
+            frameProvider.setImageFrame( pParticleAssetEmitter->getImageFrame() );
         }
         }
     }
     }
     else
     else
@@ -1291,12 +1280,8 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
         // No, so fetch the animation asset.
         // No, so fetch the animation asset.
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
         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?
     // Is the emitter in static mode?
-    if ( !pParticleAssetEmitter->isStaticMode() )
+    if ( !pParticleAssetEmitter->isStaticFrameProvider() )
     {
     {
         // No, so update animation.
         // 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();
         const AssetPtr<AnimationAsset>& animationAsset = pParticleAssetEmitter->getAnimationAsset();
 
 
         // Skip if the emitter does not have a valid assigned asset to render.
         // 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;
             continue;
 
 
         // Create a new emitter node.
         // Create a new emitter node.

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

@@ -31,28 +31,20 @@
 #include "2d/core/particleSystem.h"
 #include "2d/core/particleSystem.h"
 #endif
 #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_EMISSION_RATE_SCALE     "$pref::T2D::ParticlePlayerEmissionRateScale"
 #define PARTICLE_PLAYER_SIZE_SCALE              "$pref::T2D::ParticlePlayerSizeScale"
 #define PARTICLE_PLAYER_SIZE_SCALE              "$pref::T2D::ParticlePlayerSizeScale"
 #define PARTICLE_PLAYER_FORCE_SCALE             "$pref::T2D::ParticlePlayerForceScale"
 #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:
 private:
     typedef SceneObject Parent;
     typedef SceneObject Parent;
 
 
-
     /// Emitter node.
     /// Emitter node.
     class EmitterNode
     class EmitterNode
     {
     {
@@ -134,7 +126,7 @@ private:
     F32                         mEmissionRateScale;
     F32                         mEmissionRateScale;
     F32                         mSizeScale;
     F32                         mSizeScale;
     F32                         mForceScale;
     F32                         mForceScale;
-
+    F32                         mTimeScale;
 
 
     bool                        mWaitingForParticles;
     bool                        mWaitingForParticles;
     bool                        mWaitingForDelete;
     bool                        mWaitingForDelete;
@@ -174,6 +166,9 @@ public:
     inline void setForceScale( const F32 scale ) { mForceScale = scale; }
     inline void setForceScale( const F32 scale ) { mForceScale = scale; }
     inline F32 getForceScale( void  ) const { return mForceScale; }
     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(); }
     inline const U32 getEmitterCount( void ) const { return (U32)mEmitters.size(); }
 
 
     void setEmitterPaused( const bool paused, const U32 emitterIndex );
     void setEmitterPaused( const bool paused, const U32 emitterIndex );
@@ -194,6 +189,8 @@ protected:
     virtual void OnRegisterScene( Scene* pScene );
     virtual void OnRegisterScene( Scene* pScene );
     virtual void OnUnregisterScene( Scene* pScene );
     virtual void OnUnregisterScene( Scene* pScene );
 
 
+    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
+
     /// Particle Creation/Integration.
     /// Particle Creation/Integration.
     void configureParticle( EmitterNode* pEmitterNode, ParticleSystem::ParticleNode* pParticleNode );
     void configureParticle( EmitterNode* pEmitterNode, ParticleSystem::ParticleNode* pParticleNode );
     void integrateParticle( EmitterNode* pEmitterNode, ParticleSystem::ParticleNode* pParticleNode, const F32 particleAge, const F32 elapsedTime );
     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     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     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     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:
 private:
-    virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase );
-
     void initializeParticleAsset( void );
     void initializeParticleAsset( void );
     void destroyParticleAsset( void );
     void destroyParticleAsset( void );
 };
 };

+ 397 - 59
engine/source/2d/sceneobject/SceneObject.cc

@@ -76,33 +76,26 @@
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-IMPLEMENT_CONOBJECT(SceneObject);
-
-//-----------------------------------------------------------------------------
-
 // Scene-Object counter.
 // Scene-Object counter.
 static U32 sGlobalSceneObjectCount = 0;
 static U32 sGlobalSceneObjectCount = 0;
 static U32 sSceneObjectMasterSerialId = 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),
     mSerialId(0),
     mRenderGroup( StringTable->EmptyString )
     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.
     // Set Vector Associations.
     VECTOR_SET_ASSOCIATION( mDestroyNotifyList );
     VECTOR_SET_ASSOCIATION( mDestroyNotifyList );
     VECTOR_SET_ASSOCIATION( mCollisionFixtureDefs );
     VECTOR_SET_ASSOCIATION( mCollisionFixtureDefs );
@@ -373,9 +343,6 @@ bool SceneObject::onAdd()
 
 
         mpTargetScene = NULL;
         mpTargetScene = NULL;
     }
     }
-
-    // Perform the callback.
-    Con::executef(this, 1, "onAdd");
    
    
     // Return Okay.
     // Return Okay.
     return true;
     return true;
@@ -385,9 +352,6 @@ bool SceneObject::onAdd()
 
 
 void SceneObject::onRemove()
 void SceneObject::onRemove()
 {
 {
-    // Perform the callback.
-    Con::executef(this, 1, "onRemove");
-
     // Detach Any GUI Control.
     // Detach Any GUI Control.
     detachGui();
     detachGui();
 
 
@@ -1442,14 +1406,14 @@ void SceneObject::setCollisionAgainst( const SceneObject* pSceneObject, const bo
     if ( clearMasks )
     if ( clearMasks )
     {
     {
         // Yes, so just set the masks to the referenced-objects' masks.
         // Yes, so just set the masks to the referenced-objects' masks.
-        setCollisionGroupMask( pSceneObject->getCollisionGroupMask() );
-        setCollisionLayerMask( pSceneObject->getCollisionLayerMask() ); 
+        setCollisionGroupMask( pSceneObject->getSceneGroupMask() );
+        setCollisionLayerMask( pSceneObject->getSceneLayerMask() ); 
     }
     }
     else
     else
     {
     {
         // No, so merge with existing masks.
         // 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.
         // Set Blend Function.
         glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
         glBlendFunc( mSrcBlendFactor, mDstBlendFactor );
 
 
-        // Set Colour.
+        // Set color.
         glColor4f(mBlendColor.red,mBlendColor.green,mBlendColor.blue,mBlendColor.alpha );
         glColor4f(mBlendColor.red,mBlendColor.green,mBlendColor.blue,mBlendColor.alpha );
     }
     }
     else
     else
     {
     {
         // Disable Blending.
         // Disable Blending.
         glDisable( GL_BLEND );
         glDisable( GL_BLEND );
-        // Reset Colour.
+        // Reset color.
         glColor4f(1,1,1,1);
         glColor4f(1,1,1,1);
     }
     }
 
 
@@ -2673,7 +2637,7 @@ void SceneObject::resetBlendOptions( void )
 
 
     glDisable( GL_ALPHA_TEST);
     glDisable( GL_ALPHA_TEST);
 
 
-    // Reset Colour.
+    // Reset color.
     glColor4f(1,1,1,1);
     glColor4f(1,1,1,1);
 }
 }
 
 
@@ -4132,3 +4096,377 @@ const char* SceneObject::getDstBlendFactorDescription(const GLenum factor)
 
 
     return StringTable->EmptyString;
     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 bodyTypeTable;
 extern EnumTable srcBlendFactorTable;
 extern EnumTable srcBlendFactorTable;
 extern EnumTable dstBlendFactorTable;
 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; }
     static bool             writeUseInputEvents( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUseInputEvents() == true; }
 
 
     /// Picking.
     /// 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.
     /// Script callbacks.
     static bool             writeUpdateCallback( void* obj, StringTableEntry pFieldName ) { return static_cast<SceneObject*>(obj)->getUpdateCallback() == true; }
     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.
     // Grab the element count of the first parameter.
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
@@ -1123,6 +1127,24 @@ ConsoleMethod(SceneObject, setCollisionLayers, void, 3, 2 + MASK_BITCOUNT, "(lay
         object->setCollisionLayerMask(MASK_ALL);
         object->setCollisionLayerMask(MASK_ALL);
         return;
         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.
     // Space separated list.
     if (argc == 3)
     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.
     // Grab the element count of the first parameter.
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
     const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
@@ -1183,6 +1209,22 @@ ConsoleMethod(SceneObject, setCollisionGroups, void, 3, 2 + MASK_BITCOUNT, "(gro
         object->setCollisionGroupMask(MASK_ALL);
         object->setCollisionGroupMask(MASK_ALL);
         return;
         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.
     // Space separated list.
     if (argc == 3)
     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.")
                                                                 "@return (float red / float green / float blue / float alpha) The sprite blend color.")
 {
 {
-    // Get Blend Colour.
+    // Get Blend color.
     ColorF blendColor = object->getBlendColor();
     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 )
 void Scroller::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
 {
 {
     // Finish if we can't render.
     // Finish if we can't render.
-    if ( !SpriteProxyBase::validRender() )
+    if ( !ImageFrameProvider::validRender() )
         return;
         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.
     // Calculate render offset.
     F32 renderOffsetX = mFmod( mRenderTickTextureOffset.x, 1.0f );
     F32 renderOffsetX = mFmod( mRenderTickTextureOffset.x, 1.0f );

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

@@ -63,11 +63,11 @@ ShapeVector::~ShapeVector()
 void ShapeVector::initPersistFields()
 void ShapeVector::initPersistFields()
 {
 {
    addProtectedField("PolyList", TypePoint2FVector, Offset(mPolygonBasisList, ShapeVector), &setPolyList, &defaultProtectedGetFn, &writePolyList, "");
    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();
    Parent::initPersistFields();
 }
 }
@@ -151,7 +151,7 @@ void ShapeVector::sceneRender( const SceneRenderState* pSceneRenderState, const
         renderPolygonShape(vertexCount);
         renderPolygonShape(vertexCount);
     }
     }
 
 
-    // Restore Colour.
+    // Restore color.
     glColor4f( 1,1,1,1 );
     glColor4f( 1,1,1,1 );
 
 
     // Restore Matrix.
     // Restore Matrix.
@@ -220,7 +220,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         // Yes, so set polygon mode to FILL.
         //glPolygonMode( GL_FRONT_AND_BACK, GL_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 );
         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
         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 );
     glColor4f(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha );
     
     
         for ( U32 n = 1; n <= vertexCount; n++ )
         for ( U32 n = 1; n <= vertexCount; n++ )
@@ -276,7 +276,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         // Yes, so set polygon mode to FILL.
         // Yes, so set polygon mode to FILL.
         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
         glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
 
 
-        // Set Fill Colour.
+        // Set Fill color.
         glColor4fv( (GLfloat*)&mFillColor );
         glColor4fv( (GLfloat*)&mFillColor );
 
 
         // Draw Object.
         // Draw Object.
@@ -288,7 +288,7 @@ void ShapeVector::renderPolygonShape(U32 vertexCount)
         glEnd();
         glEnd();
     }
     }
 
 
-    // Set Line Colour.
+    // Set Line color.
     glColor4fv( (GLfloat*)&mLineColor );
     glColor4fv( (GLfloat*)&mLineColor );
 
 
     // Draw Object.
     // Draw Object.
@@ -374,10 +374,10 @@ void ShapeVector::setPolyPrimitive( const U32 polyVertexCount )
     else if ( polyVertexCount == 4 )
     else if ( polyVertexCount == 4 )
     {
     {
         // Yes, so set Quad.
         // 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
     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 ShapeVector::getBoxFromPoints()
 {
 {
     Vector2 box(1.0f, 1.0f);
     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 setPolyScale( const Vector2& scale );
     void setPolyPrimitive( const U32 polyVertexCount );
     void setPolyPrimitive( const U32 polyVertexCount );
     void setPolyCustom( const U32 polyVertexCount, const char* pCustomPolygon );
     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()); };
     U32 getPolyVertexCount( void ) { return U32(mPolygonBasisList.size()); };
+    inline const Vector2* getPolyBasis( void ) const { return &(mPolygonBasisList[0]); };
     const char* getPoly( void );
     const char* getPoly( void );
     const char* getWorldPoly( 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 );
     Vector2 getBoxFromPoints( void );
 
 
     /// Internal Crunchers.
     /// Internal Crunchers.
@@ -112,25 +108,15 @@ public:
 protected:
 protected:
     static bool setPolyList(void* obj, const char* data)
     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);
        static_cast<ShapeVector*>(obj)->setPolyCustom(count, data);
        return false;
        return false;
     }
     }
     static bool writePolyList( void* obj, StringTableEntry pFieldName ) { return static_cast<ShapeVector*>(obj)->mPolygonBasisList.size() > 0; }
     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 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 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 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 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; }
     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 )
 void Sprite::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
 {
 {
     // Let the parent render.
     // Let the parent render.
-    SpriteProxyBase::render(
+    ImageFrameProvider::render(
         getFlipX(), getFlipY(),
         getFlipX(), getFlipY(),
         mRenderOOBB[0],
         mRenderOOBB[0],
         mRenderOOBB[1],
         mRenderOOBB[1],

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

@@ -60,7 +60,6 @@ public:
 protected:
 protected:
     static bool writeFlipX( void* obj, StringTableEntry pFieldName )        { return static_cast<Sprite*>(obj)->getFlipX() == true; }
     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; }
     static bool writeFlipY( void* obj, StringTableEntry pFieldName )        { return static_cast<Sprite*>(obj)->getFlipY() == true; }
-
 };
 };
 
 
 #endif // _SPRITE_H_
 #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." );
     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 )
 void AssetBase::setAssetDescription( const char* pAssetDescription )
@@ -167,7 +188,7 @@ StringTableEntry AssetBase::expandAssetFilePath( const char* pAssetFilePath ) co
 
 
     // Fetch the asset base-path hint.
     // Fetch the asset base-path hint.
     StringTableEntry assetBasePathHint;
     StringTableEntry assetBasePathHint;
-    if ( getOwned() )
+    if ( getOwned() && !getAssetPrivate() )
     {
     {
         assetBasePathHint = mpOwningAssetManager->getAssetPath( getAssetId() );
         assetBasePathHint = mpOwningAssetManager->getAssetPath( getAssetId() );
     }
     }
@@ -204,10 +225,10 @@ StringTableEntry AssetBase::collapseAssetFilePath( const char* pAssetFilePath )
 
 
     char assetFilePathBuffer[1024];
     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 );
         Con::collapsePath( assetFilePathBuffer, sizeof(assetFilePathBuffer), pAssetFilePath );
         return StringTable->insert( assetFilePathBuffer );
         return StringTable->insert( assetFilePathBuffer );
     }
     }

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

@@ -67,6 +67,7 @@ public:
 
 
     /// Engine.
     /// Engine.
     static void initPersistFields();
     static void initPersistFields();
+    virtual void copyTo(SimObject* object);
 
 
     /// Asset configuration.
     /// Asset configuration.
     inline void             setAssetName( const char* pAssetName )              { if ( mpOwningAssetManager == NULL ) mpAssetDefinition->mAssetName = StringTable->insert(pAssetName); }
     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.
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
     PROFILE_SCOPE(AssetManager_AddDeclaredAssets);
@@ -191,7 +191,7 @@ bool AssetManager::addDeclaredAssets( ModuleDefinition* pModuleDefinition )
         if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
         if ( !scanDeclaredAssets( filePathBuffer, pDeclaredAssets->getExtension(), pDeclaredAssets->getRecurse(), pModuleDefinition ) )
         {
         {
             // Warn.
             // 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.
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
     PROFILE_SCOPE(AssetManager_AddSingleDeclaredAsset);
@@ -220,7 +220,7 @@ bool AssetManager::addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition,
     if ( pFileStart == NULL )
     if ( pFileStart == NULL )
     {
     {
         // No, so warn.
         // 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,
             assetFilePathBuffer,
             pModuleDefinition->getModulePath() );
             pModuleDefinition->getModulePath() );
         return false;
         return false;
@@ -236,7 +236,7 @@ bool AssetManager::addSingleDeclaredAsset( ModuleDefinition* pModuleDefinition,
     if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
     if ( !scanDeclaredAssets( assetFilePathBuffer, pFileStart, false, pModuleDefinition ) )
     {
     {
         // Warn.
         // 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;
         return false;
     }
     }
 
 
@@ -273,10 +273,10 @@ StringTableEntry AssetManager::addPrivateAsset( AssetBase* pAssetBase )
     pAssetDefinition->mpAssetBase = pAssetBase;
     pAssetDefinition->mpAssetBase = pAssetBase;
     pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
     pAssetDefinition->mAssetDescription = pSourceAssetDefinition->mAssetDescription;
     pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
     pAssetDefinition->mAssetCategory = pSourceAssetDefinition->mAssetCategory;
-    pAssetDefinition->mAssetAutoUnload = false;
+    pAssetDefinition->mAssetAutoUnload = true;
     pAssetDefinition->mAssetRefreshEnable = false;
     pAssetDefinition->mAssetRefreshEnable = false;
     pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
     pAssetDefinition->mAssetType = StringTable->insert( pAssetBase->getClassName() );
-    pAssetDefinition->mAssetLoadedCount = 1;
+    pAssetDefinition->mAssetLoadedCount = 0;
     pAssetDefinition->mAssetInternal = false;
     pAssetDefinition->mAssetInternal = false;
     pAssetDefinition->mAssetPrivate = true;
     pAssetDefinition->mAssetPrivate = true;
 
 
@@ -326,7 +326,7 @@ bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
         AssetDefinition* pAssetDefinition = *moduleAssets.begin();
         AssetDefinition* pAssetDefinition = *moduleAssets.begin();
 
 
         // Remove this asset.
         // Remove this asset.
-        removeSingleDeclaredAsset( pAssetDefinition->mAssetId );
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
     }
     }
 
 
     // Info.
     // Info.
@@ -338,7 +338,7 @@ bool AssetManager::removeDeclaredAssets( ModuleDefinition* pModuleDefinition )
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-bool AssetManager::removeSingleDeclaredAsset( const char* pAssetId )
+bool AssetManager::removeDeclaredAsset( const char* pAssetId )
 {
 {
     // Debug Profiling.
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_RemoveSingleDeclaredAsset);
     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 )
 bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies )
 {
 {
     // Debug Profiling.
     // Debug Profiling.
@@ -1250,7 +1100,7 @@ bool AssetManager::deleteAsset( const char* pAssetId, const bool deleteLooseFile
     pAssetDefinition = NULL;
     pAssetDefinition = NULL;
 
 
     // Remove asset.
     // Remove asset.
-    removeSingleDeclaredAsset( pAssetId );
+    removeDeclaredAsset( pAssetId );
 
 
     // Delete the asset definition file.
     // Delete the asset definition file.
     if ( !Platform::fileDelete( assetDefinitionFile ) )
     if ( !Platform::fileDelete( assetDefinitionFile ) )
@@ -3106,7 +2956,7 @@ void AssetManager::unloadAsset( AssetDefinition* pAssetDefinition )
         mLoadedPrivateAssetsCount--;
         mLoadedPrivateAssetsCount--;
 
 
         // Remove it completely.
         // Remove it completely.
-        removeSingleDeclaredAsset( pAssetDefinition->mAssetId );
+        removeDeclaredAsset( pAssetDefinition->mAssetId );
     }
     }
 }
 }
 
 
@@ -3117,8 +2967,8 @@ void AssetManager::onModulePreLoad( ModuleDefinition* pModuleDefinition )
     // Debug Profiling.
     // Debug Profiling.
     PROFILE_SCOPE(AssetManager_OnModulePreLoad);
     PROFILE_SCOPE(AssetManager_OnModulePreLoad);
 
 
-    // Add declared assets.
-    addDeclaredAssets( pModuleDefinition );
+    // Add module declared assets.
+    addModuleDeclaredAssets( pModuleDefinition );
 
 
     // Is an asset tags manifest specified?
     // Is an asset tags manifest specified?
     if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString )
     if ( pModuleDefinition->getAssetTagsManifest() != StringTable->EmptyString )

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

@@ -47,10 +47,6 @@
 #include "assets/assetDefinition.h"
 #include "assets/assetDefinition.h"
 #endif
 #endif
 
 
-#ifndef _ASSET_SNAPSHOT_H_
-#include "assets/assetSnapshot.h"
-#endif
-
 #ifndef _ASSET_TAGS_MANIFEST_H_
 #ifndef _ASSET_TAGS_MANIFEST_H_
 #include "assets/assetTagsManifest.h"
 #include "assets/assetTagsManifest.h"
 #endif
 #endif
@@ -125,11 +121,11 @@ public:
     static void initPersistFields();
     static void initPersistFields();
 
 
     /// Declared assets.
     /// 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 );
     StringTableEntry addPrivateAsset( AssetBase* pAssetBase );
     bool removeDeclaredAssets( ModuleDefinition* pModuleDefinition );
     bool removeDeclaredAssets( ModuleDefinition* pModuleDefinition );
-    bool removeSingleDeclaredAsset( const char* pAssetId );
+    bool removeDeclaredAsset( const char* pAssetId );
     bool renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
     bool renameDeclaredAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
     StringTableEntry getAssetName( const char* pAssetId );
     StringTableEntry getAssetName( const char* pAssetId );
     StringTableEntry getAssetDescription( const char* pAssetId );
     StringTableEntry getAssetDescription( const char* pAssetId );
@@ -151,7 +147,7 @@ public:
     bool isReferencedAsset( const char* pAssetId );
     bool isReferencedAsset( const char* pAssetId );
     bool renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
     bool renameReferencedAsset( const char* pAssetIdFrom, const char* pAssetIdTo );
 
 
-    /// Asset acquisition.
+    /// Public asset acquisition.
     template<typename T> T* acquireAsset( const char* pAssetId )
     template<typename T> T* acquireAsset( const char* pAssetId )
     {
     {
         // Sanity!
         // Sanity!
@@ -298,13 +294,34 @@ public:
         return pAcquiredAsset;
         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 );
     bool releaseAsset( const char* pAssetId );
     void purgeAssets( void );
     void purgeAssets( void );
 
 
-    /// Asset snapshot.
-    bool getAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId );
-    bool setAssetSnapshot( AssetSnapshot* pAssetSnapshot, const char* pAssetId );
-
     /// Asset deletion.
     /// Asset deletion.
     bool deleteAsset( const char* pAssetId, const bool deleteLooseFiles, const bool deleteDependencies );
     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.
     // Fetch module definition.
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
@@ -56,15 +56,15 @@ ConsoleMethod( AssetManager, addDeclaredAssets, bool, 3, 3,     "(moduleDefiniti
         return false;
         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.
     // Fetch module definition.
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
     ModuleDefinition* pModuleDefinition = Sim::findObject<ModuleDefinition>( argv[2] );
@@ -73,15 +73,15 @@ ConsoleMethod( AssetManager, addSingleDeclaredAsset, bool, 4, 4,    "(moduleDefi
     if ( pModuleDefinition == NULL )
     if ( pModuleDefinition == NULL )
     {
     {
         // No, so warn.
         // 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;
         return false;
     }
     }
 
 
     // Fetch asset file-path.
     // Fetch asset file-path.
     const char* pAssetFilePath = argv[3];
     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.
     // 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"
                                                                 "You must release the asset once you're finish with it using 'releaseAsset'.\n"
                                                                 "@param assetId The selected asset Id.\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.")
                                                                 "@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;
     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"
 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 assetId The selected asset Id.\n"
                                                         "@param deleteLooseFiles Whether to delete an assets loose files or not.\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;
     friend class AssetManager;
 
 
-private:
+protected:
     virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase ) = 0;    
     virtual void onAssetRefreshed( AssetPtrBase* pAssetPtrBase ) = 0;    
 };
 };
 
 
@@ -61,7 +61,7 @@ public:
     virtual bool notNull( void ) const = 0;
     virtual bool notNull( void ) const = 0;
 
 
     /// Notification.
     /// Notification.
-    void registerRefreshNotify( AssetPtrCallback* pCallback )
+    inline void registerRefreshNotify( AssetPtrCallback* pCallback )
     {
     {
         // Sanity!
         // Sanity!
         AssertFatal( AssetDatabase.isProperlyAdded(), "AssetPtrBase::registerRefreshNotify() - Cannot register an asset pointer with the asset system." );
         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));
    //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 )
 void AudioAsset::initializeAsset( void )

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

@@ -63,6 +63,7 @@ private:
 public:
 public:
    AudioAsset();
    AudioAsset();
    static void initPersistFields();
    static void initPersistFields();
+   virtual void copyTo(SimObject* object);
 
 
    void setAudioFile( const char* pAudioFile );
    void setAudioFile( const char* pAudioFile );
    inline StringTableEntry getAudioFile( void ) const { return mAudioFile; }
    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);
    mActionName = StringTable->insert(actionName);
    mUndoManager = NULL;
    mUndoManager = NULL;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 }
 
 
 // Modified to clean up quiet sub actions [KNM | 08/10/11 | ITGB-152]
 // 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()
    UndoScriptAction() : UndoAction()
    {
    {
-      mNSLinkMask = LinkSuperClassName | LinkClassName;
    };
    };
 
 
    virtual void undo() { Con::executef(this, 1, "undo"); };
    virtual void undo() { Con::executef(this, 1, "undo"); };
@@ -159,11 +158,6 @@ public:
       if(!Parent::onAdd())
       if(!Parent::onAdd())
          return false;
          return false;
 
 
-
-      // Notify Script.
-      if(isMethod("onAdd"))
-         Con::executef(this, 1, "onAdd");
-
       // Return Success.
       // Return Success.
       return true;
       return true;
    };
    };
@@ -173,10 +167,6 @@ public:
       if (mUndoManager)
       if (mUndoManager)
          mUndoManager->removeAction((UndoAction*)this);
          mUndoManager->removeAction((UndoAction*)this);
 
 
-      // notify script
-      if(isMethod("onRemove"))
-         Con::executef(this, 1, "onRemove");
-
       Parent::onRemove();
       Parent::onRemove();
    }
    }
 
 

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

@@ -35,17 +35,18 @@
 #include "persistence/taml/tamlCustom.h"
 #include "persistence/taml/tamlCustom.h"
 #endif
 #endif
 
 
+#ifndef _TAML_H_
+#include "persistence/Taml/taml.h"
+#endif
+
 // Script bindings.
 // Script bindings.
 #include "behaviorComponent_ScriptBinding.h"
 #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 )
 void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
 {
 {
     // Call parent.
     // Call parent.
@@ -952,10 +1130,7 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
     // Finish if no behavior connections.
     // Finish if no behavior connections.
     if ( behaviorConnectionCount == 0 )
     if ( behaviorConnectionCount == 0 )
         return;
         return;
-
-    // Add custom behavior connection property.
-    TamlCustomNode* pCustomConnection = customNodes.addNode( BEHAVIOR_CONNECTION_NODE_NAME );
-    
+   
     // Iterate instance connections.
     // Iterate instance connections.
     for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
     for( typeInstanceConnectionHash::iterator instanceItr = mBehaviorConnections.begin(); instanceItr != mBehaviorConnections.end(); ++instanceItr )
     {
     {
@@ -975,7 +1150,7 @@ void BehaviorComponent::onTamlCustomWrite( TamlCustomNodes& customNodes )
                 BehaviorPortConnection* pConnection = connectionItr;
                 BehaviorPortConnection* pConnection = connectionItr;
 
 
                 // Add connectionnode.
                 // Add connectionnode.
-                TamlCustomNode* pConnectionNode = pCustomConnection->addNode( BEHAVIOR_CONNECTION_TYPE_NAME );
+                TamlCustomNode* pConnectionNode = pCustomBehaviorNode->addNode( BEHAVIOR_CONNECTION_TYPE_NAME );
 
 
                 // Add behavior field.
                 // Add behavior field.
                 pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
                 pConnectionNode->addField( pConnection->mOutputName, pConnection->mOutputInstance->getBehaviorId() );
@@ -1016,408 +1191,228 @@ void BehaviorComponent::onTamlCustomRead( const TamlCustomNodes& customNodes )
             // Fetch behavior node.
             // Fetch behavior node.
             TamlCustomNode* pBehaviorNode = *behaviorNodeItr;
             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.
                         // 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() );
                         behaviorFieldName2, pBehaviorInstance2->getTemplateName() );
                     continue;
                     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.
                     // 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;
                     continue;
                 }
                 }
-
-                // Assign output/input appropriately.
-                pOutputInstance = pBehaviorInstance2;
-                pInputInstance = pBehaviorInstance1;
-                outputName = behaviorFieldName2;
-                inputName = behaviorFieldName1;
             }
             }
             else
             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
 class BehaviorComponent : public DynamicConsoleMethodComponent
 {
 {
     friend class BehaviorInterface;
     friend class BehaviorInterface;

+ 0 - 1
engine/source/component/behaviors/behaviorInstance.cpp

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

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

@@ -33,8 +33,6 @@ SimComponent::SimComponent() : mOwner( NULL )
    mMutex = Mutex::createMutex();
    mMutex = Mutex::createMutex();
    
    
    mEnabled = true;
    mEnabled = true;
-
-   mNSLinkMask = LinkSuperClassName | LinkClassName;
 }
 }
 
 
 SimComponent::~SimComponent()
 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.
 // 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;
     const char* prevVal = NULL;
    
    
@@ -364,7 +364,7 @@ static void getFieldComponent( SimObject* object, StringTableEntry field, const
         prevVal = object->getDataField( field, array );
         prevVal = object->getDataField( field, array );
    
    
     // Otherwise, grab from the string stack. The value coming in will always
     // 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
     else
         prevVal = STR.getStringValue();
         prevVal = STR.getStringValue();
 
 
@@ -372,22 +372,22 @@ static void getFieldComponent( SimObject* object, StringTableEntry field, const
     if ( prevVal && *prevVal )
     if ( prevVal && *prevVal )
     {
     {
         if ( subField == _count )
         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] )
         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] )
         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] )
         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] )
         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) )
         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
         else
             val[0] = 0;
             val[0] = 0;
@@ -404,9 +404,10 @@ static void setFieldComponent( SimObject* object, StringTableEntry field, const
 {
 {
     // Copy the current string value
     // Copy the current string value
     char strValue[1024];
     char strValue[1024];
-    dStrncpy( strValue, STR.getStringValue(), 1024 );
+    dStrncpy( strValue, STR.getStringValue(), sizeof(strValue) );
 
 
     char val[1024] = "";
     char val[1024] = "";
+    const U32 bufferSize = sizeof(val);
     const char* prevVal = NULL;
     const char* prevVal = NULL;
 
 
     // Set the value on an object field.
     // 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
     // Ensure that the variable has a value
     if (!prevVal)
     if (!prevVal)
-	    return;
+        return;
 
 
     if ( subField == _xyzw[0] || subField == _rgba[0] || subField == _size[0] )
     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] )
     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] )
     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] )
     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) )
     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 )
     if ( val[0] != 0 )
     {
     {
@@ -1236,7 +1237,8 @@ breakContinue:
             {
             {
                // The field is not being retrieved from an object. Maybe it's
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                intStack[UINT+1] = dAtoi( valBuffer );
                intStack[UINT+1] = dAtoi( valBuffer );
             }
             }
             UINT++;
             UINT++;
@@ -1249,7 +1251,7 @@ breakContinue:
             {
             {
                // The field is not being retrieved from an object. Maybe it's
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                floatStack[FLT+1] = dAtof( valBuffer );
                floatStack[FLT+1] = dAtof( valBuffer );
             }
             }
             FLT++;
             FLT++;
@@ -1265,7 +1267,7 @@ breakContinue:
             {
             {
                // The field is not being retrieved from an object. Maybe it's
                // The field is not being retrieved from an object. Maybe it's
                // a special accessor?
                // a special accessor?
-               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer );
+               getFieldComponent( prevObject, prevField, prevFieldArray, curField, valBuffer, VAL_BUFFER_SIZE );
                STR.setStringValue( valBuffer );
                STR.setStringValue( valBuffer );
             }
             }
 
 

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

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

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

@@ -38,40 +38,56 @@
 #ifndef _CONSOLE_H_
 #ifndef _CONSOLE_H_
 #include "console/console.h"
 #include "console/console.h"
 #endif
 #endif
+#ifndef TINYXML_INCLUDED
+#include "persistence/tinyXML/tinyxml.h"
+#endif
+
+//-----------------------------------------------------------------------------
 
 
 class Namespace;
 class Namespace;
 class ConsoleObject;
 class ConsoleObject;
 
 
+//-----------------------------------------------------------------------------
+
 enum NetClassTypes {
 enum NetClassTypes {
-   NetClassTypeObject = 0,
-   NetClassTypeDataBlock,
-   NetClassTypeEvent,
-   NetClassTypesCount,
+    NetClassTypeObject = 0,
+    NetClassTypeDataBlock,
+    NetClassTypeEvent,
+    NetClassTypesCount,
 };
 };
 
 
+//-----------------------------------------------------------------------------
+
 enum NetClassGroups {
 enum NetClassGroups {
-   NetClassGroupGame = 0,
-   NetClassGroupCommunity,
-   NetClassGroup3,
-   NetClassGroup4,
-   NetClassGroupsCount,
+    NetClassGroupGame = 0,
+    NetClassGroupCommunity,
+    NetClassGroup3,
+    NetClassGroup4,
+    NetClassGroupsCount,
 };
 };
 
 
+//-----------------------------------------------------------------------------
+
 enum NetClassMasks {
 enum NetClassMasks {
-   NetClassGroupGameMask      = BIT(NetClassGroupGame),
-   NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
+    NetClassGroupGameMask      = BIT(NetClassGroupGame),
+    NetClassGroupCommunityMask = BIT(NetClassGroupCommunity),
 };
 };
 
 
+//-----------------------------------------------------------------------------
+
 enum NetDirection
 enum NetDirection
 {
 {
-   NetEventDirAny,
-   NetEventDirServerToClient,
-   NetEventDirClientToServer,
+    NetEventDirAny,
+    NetEventDirServerToClient,
+    NetEventDirClientToServer,
 };
 };
 
 
+//-----------------------------------------------------------------------------
+
 class SimObject;
 class SimObject;
 class ConsoleTypeValidator;
 class ConsoleTypeValidator;
 
 
+//-----------------------------------------------------------------------------
 /// Core functionality for class manipulation.
 /// Core functionality for class manipulation.
 ///
 ///
 /// @section AbstractClassRep_intro Introduction (or, Why AbstractClassRep?)
 /// @section AbstractClassRep_intro Introduction (or, Why AbstractClassRep?)
@@ -164,235 +180,251 @@ class ConsoleTypeValidator;
 ///        bit allocations for network ID fields.
 ///        bit allocations for network ID fields.
 ///
 ///
 /// @nosubgrouping
 /// @nosubgrouping
+//-----------------------------------------------------------------------------
+
 class AbstractClassRep
 class AbstractClassRep
 {
 {
-   friend class ConsoleObject;
+    friend class ConsoleObject;
 
 
 public:
 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:
 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:
 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:
 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()
 inline AbstractClassRep *AbstractClassRep::getClassList()
 {
 {
-   return classLinkList;
+    return classLinkList;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline U32 AbstractClassRep::getClassCRC(U32 group)
 inline U32 AbstractClassRep::getClassCRC(U32 group)
 {
 {
-   return classCRC[group];
+    return classCRC[group];
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep *AbstractClassRep::getNextClass()
 inline AbstractClassRep *AbstractClassRep::getNextClass()
 {
 {
-   return nextClass;
+    return nextClass;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep *AbstractClassRep::getParentClass()
 inline AbstractClassRep *AbstractClassRep::getParentClass()
 {
 {
-   return parentClass;
+    return parentClass;
 }
 }
 
 
+
+//-----------------------------------------------------------------------------
 inline S32 AbstractClassRep::getClassId(U32 group) const
 inline S32 AbstractClassRep::getClassId(U32 group) const
 {
 {
-   return mClassId[group];
+    return mClassId[group];
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline const char* AbstractClassRep::getClassName() const
 inline const char* AbstractClassRep::getClassName() const
 {
 {
-   return mClassName;
+    return mClassName;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline Namespace *AbstractClassRep::getNameSpace()
 inline Namespace *AbstractClassRep::getNameSpace()
 {
 {
-   return mNamespace;
+    return mNamespace;
 }
 }
 
 
-//------------------------------------------------------------------------------
-//-------------------------------------- ConcreteClassRep
-//
-
+//-----------------------------------------------------------------------------
 
 
-/// Helper class for AbstractClassRep.
-///
-/// @see AbtractClassRep
-/// @see ConsoleObject
 template <class T>
 template <class T>
 class ConcreteClassRep : public AbstractClassRep
 class ConcreteClassRep : public AbstractClassRep
 {
 {
 public:
 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
 // Forward declarations so they can be used in the class
 const char *defaultProtectedGetFn( void *obj, const char *data );
 const char *defaultProtectedGetFn( void *obj, const char *data );
 bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
 bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
 
 
+//-----------------------------------------------------------------------------
 /// Interface class to the console.
 /// Interface class to the console.
 ///
 ///
 /// @section ConsoleObject_basics The Basics
 /// @section ConsoleObject_basics The Basics
@@ -443,396 +475,451 @@ bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName );
 ///
 ///
 /// @see AbstractClassRep for gory implementation details.
 /// @see AbstractClassRep for gory implementation details.
 /// @nosubgrouping
 /// @nosubgrouping
+//-----------------------------------------------------------------------------
+
 class ConsoleObject
 class ConsoleObject
 {
 {
 protected:
 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:
 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:
 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:
 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:
 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:
 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 addNamedField(fieldName,type,className) addField(#fieldName, type, Offset(fieldName,className))
 #define addNamedFieldV(fieldName,type,className, validator) addFieldV(#fieldName, type, Offset(fieldName,className), validator)
 #define addNamedFieldV(fieldName,type,className, validator) addFieldV(#fieldName, type, Offset(fieldName,className), validator)
 
 
-//------------------------------------------------------------------------------
-//-------------------------------------- Inlines
-//
+//-----------------------------------------------------------------------------
+
 inline S32 ConsoleObject::getClassId(U32 netClassGroup) const
 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
 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
 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)
 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)
 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)
 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
 inline const AbstractClassRep::FieldList& ConsoleObject::getFieldList() const
 {
 {
-   return getClassRep()->mFieldList;
+    return getClassRep()->mFieldList;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline AbstractClassRep::FieldList& ConsoleObject::getModifiableFieldList()
 inline AbstractClassRep::FieldList& ConsoleObject::getModifiableFieldList()
 {
 {
-   return getClassRep()->mFieldList;
+    return getClassRep()->mFieldList;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline bool& ConsoleObject::getDynamicGroupExpand()
 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 )
 inline bool defaultProtectedSetFn( void *obj, const char *data )
 {
 {
-   return true;
+    return true;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline const char *defaultProtectedGetFn( void *obj, const char *data )
 inline const char *defaultProtectedGetFn( void *obj, const char *data )
 {
 {
-   return data;
+    return data;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName )
 inline bool defaultProtectedWriteFn( void* obj, StringTableEntry pFieldName )
 {
 {
     return true;
     return true;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedNotSetFn(void* obj, const char* data)
 inline bool defaultProtectedNotSetFn(void* obj, const char* data)
 {
 {
     return false;
     return false;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
 inline bool defaultProtectedNotWriteFn( void* obj, StringTableEntry pFieldName )
 inline bool defaultProtectedNotWriteFn( void* obj, StringTableEntry pFieldName )
 {
 {
     return false;
     return false;

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

@@ -31,26 +31,6 @@ IMPLEMENT_CONOBJECT(PNGImage);
 
 
 #define PNGSIGSIZE 8
 #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)
 PNGImage::PNGImage() : mPNGImageType(PNGTYPE_UNKNOWN)
 {
 {
     mWidth = 0;
     mWidth = 0;

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

@@ -58,12 +58,6 @@ public:
     PNGImage();
     PNGImage();
     ~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);
     DECLARE_CONOBJECT(PNGImage);
 
 
     /// Construct the png information from the .png file path provided.
     /// 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 )
 TextureHandle::TextureHandle( const char* pTextureKey, TextureHandleType type, bool clampToEdge, bool force16Bit )
 {
 {
     // Sanity!
     // Sanity!

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

@@ -187,4 +187,8 @@ private:
 
 
 };
 };
 
 
+//-----------------------------------------------------------------------------
+
+extern TextureHandle BadTextureHandle;
+
 #endif // _TEXTURE_HANDLE_H_
 #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 StockColorTable[] =
 {
 {
     StockColorItem( "InvisibleBlack", 0, 0, 0, 0 ),
     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 )
 ColorF::ColorF( const char* pStockColorName )
 {
 {
     // Set stock color.
     // Set stock color.
@@ -582,7 +579,7 @@ ConsoleSetType( TypeColorI )
 ConsoleFunction( getStockColorCount, S32, 1, 1, "() - Gets a count of available stock colors.\n"
 ConsoleFunction( getStockColorCount, S32, 1, 1, "() - Gets a count of available stock colors.\n"
                                                 "@return A count of available stock colors." )
                                                 "@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.
     // Fetch stock color index.
     const S32 stockColorIndex = dAtoi(argv[1]);
     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( TypeColorI )
 DefineConsoleType( TypeColorF )
 DefineConsoleType( TypeColorF )
 
 
+
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 class ColorI;
 class ColorI;
@@ -110,6 +111,9 @@ class ColorF
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (blue  >= 0.0f && blue  <= 1.0f) &&
                                       (alpha >= 0.0f && alpha <= 1.0f); }
                                       (alpha >= 0.0f && alpha <= 1.0f); }
    void clamp();
    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 get565()  const;
    U16 get4444() 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 ColorF& color );
     static StringTableEntry name( const ColorI& color );
     static StringTableEntry name( const ColorI& color );
 
 
+    static S32 getCount( void );
+    static const StockColorItem* getColorItem( const S32 index );
+
     static void create( void );
     static void create( void );
     static void destroy( 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
 // Scene Events
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////

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

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

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません