Browse Source

Merge pull request #2 from TorqueGameEngines/development

Development - Update fork from origin
Meredith Purk 5 years ago
parent
commit
2e0f8fd365
100 changed files with 14583 additions and 9607 deletions
  1. 1 1
      .gitignore
  2. 12 4
      README.md
  3. 46 11
      editor/AssetAdmin/AssetAdmin.cs
  4. 76 10
      engine/compilers/VisualStudio 2017/Torque 2D.vcxproj
  5. 224 27
      engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters
  6. 1 1
      engine/compilers/VisualStudio 2017/libogg.vcxproj
  7. 1 1
      engine/compilers/VisualStudio 2017/libvorbis.vcxproj
  8. 1 1
      engine/compilers/VisualStudio 2017/ljpeg.vcxproj
  9. 1 1
      engine/compilers/VisualStudio 2017/lpng.vcxproj
  10. 1 1
      engine/compilers/VisualStudio 2017/zlib.vcxproj
  11. 3 4
      engine/compilers/VisualStudio 2019/Torque 2D.rc
  12. 31 2
      engine/compilers/VisualStudio 2019/Torque 2D.vcxproj
  13. 87 1
      engine/compilers/VisualStudio 2019/Torque 2D.vcxproj.filters
  14. 2 2
      engine/compilers/VisualStudio 2019/libogg.vcxproj
  15. 2 2
      engine/compilers/VisualStudio 2019/libvorbis.vcxproj
  16. 2 2
      engine/compilers/VisualStudio 2019/ljpeg.vcxproj
  17. 2 2
      engine/compilers/VisualStudio 2019/lpng.vcxproj
  18. 2 2
      engine/compilers/VisualStudio 2019/zlib.vcxproj
  19. 384 322
      engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj
  20. 62 0
      engine/source/2d/assets/ParticleAssetEmitter.cc
  21. 57 1
      engine/source/2d/assets/ParticleAssetEmitter.h
  22. 57 0
      engine/source/2d/assets/ParticleAssetEmitter_ScriptBinding.h
  23. 0 386
      engine/source/2d/assets/SkeletonAsset.cc
  24. 0 101
      engine/source/2d/assets/SkeletonAsset.h
  25. 434 0
      engine/source/2d/assets/SpineAsset.cc
  26. 107 0
      engine/source/2d/assets/SpineAsset.h
  27. 16 16
      engine/source/2d/assets/SpineAsset_ScriptBinding.h
  28. 18 38
      engine/source/2d/core/BatchRender.cc
  29. 9 7
      engine/source/2d/core/BatchRender.h
  30. 10 0
      engine/source/2d/core/CoreMath.h
  31. 83 30
      engine/source/2d/core/ImageFrameProviderCore.cc
  32. 24 2
      engine/source/2d/core/ImageFrameProviderCore.h
  33. 5 0
      engine/source/2d/core/ParticleSystem.h
  34. 32 24
      engine/source/2d/core/SpriteBatch.cc
  35. 3 1
      engine/source/2d/core/SpriteBatch.h
  36. 64 23
      engine/source/2d/core/SpriteBatchItem.cc
  37. 31 4
      engine/source/2d/core/SpriteBatchItem.h
  38. 1 1
      engine/source/2d/scene/DebugDraw.h
  39. 3 0
      engine/source/2d/scene/Scene.cc
  40. 1 1
      engine/source/2d/scene/Scene.h
  41. 1 1
      engine/source/2d/scene/SceneRenderRequest.h
  42. 239 0
      engine/source/2d/sceneobject/LightObject.cc
  43. 96 0
      engine/source/2d/sceneobject/LightObject.h
  44. 52 0
      engine/source/2d/sceneobject/LightObject_ScriptBinding.h
  45. 16 4
      engine/source/2d/sceneobject/ParticlePlayer.cc
  46. 285 0
      engine/source/2d/sceneobject/Path.cc
  47. 113 0
      engine/source/2d/sceneobject/Path.h
  48. 134 0
      engine/source/2d/sceneobject/Path_ScriptBinding.h
  49. 2 2
      engine/source/2d/sceneobject/SceneObject.cc
  50. 0 472
      engine/source/2d/sceneobject/SkeletonObject.cc
  51. 0 161
      engine/source/2d/sceneobject/SkeletonObject.h
  52. 0 311
      engine/source/2d/sceneobject/SkeletonObject_ScriptBinding.h
  53. 44 0
      engine/source/2d/sceneobject/SpineCollisionProxy.cc
  54. 53 0
      engine/source/2d/sceneobject/SpineCollisionProxy.h
  55. 1394 0
      engine/source/2d/sceneobject/SpineObject.cc
  56. 315 0
      engine/source/2d/sceneobject/SpineObject.h
  57. 682 0
      engine/source/2d/sceneobject/SpineObject_ScriptBinding.h
  58. 68 68
      engine/source/Box2D/Box2D.h
  59. 203 188
      engine/source/Box2D/Collision/Shapes/b2ChainShape.cpp
  60. 106 102
      engine/source/Box2D/Collision/Shapes/b2ChainShape.h
  61. 111 100
      engine/source/Box2D/Collision/Shapes/b2CircleShape.cpp
  62. 107 91
      engine/source/Box2D/Collision/Shapes/b2CircleShape.h
  63. 168 139
      engine/source/Box2D/Collision/Shapes/b2EdgeShape.cpp
  64. 94 74
      engine/source/Box2D/Collision/Shapes/b2EdgeShape.h
  65. 504 434
      engine/source/Box2D/Collision/Shapes/b2PolygonShape.cpp
  66. 134 101
      engine/source/Box2D/Collision/Shapes/b2PolygonShape.h
  67. 109 101
      engine/source/Box2D/Collision/Shapes/b2Shape.h
  68. 119 121
      engine/source/Box2D/Collision/b2BroadPhase.cpp
  69. 257 257
      engine/source/Box2D/Collision/b2BroadPhase.h
  70. 154 154
      engine/source/Box2D/Collision/b2CollideCircle.cpp
  71. 698 698
      engine/source/Box2D/Collision/b2CollideEdge.cpp
  72. 239 317
      engine/source/Box2D/Collision/b2CollidePolygon.cpp
  73. 252 249
      engine/source/Box2D/Collision/b2Collision.cpp
  74. 277 276
      engine/source/Box2D/Collision/b2Collision.h
  75. 614 603
      engine/source/Box2D/Collision/b2Distance.cpp
  76. 141 141
      engine/source/Box2D/Collision/b2Distance.h
  77. 784 781
      engine/source/Box2D/Collision/b2DynamicTree.cpp
  78. 289 289
      engine/source/Box2D/Collision/b2DynamicTree.h
  79. 487 476
      engine/source/Box2D/Collision/b2TimeOfImpact.cpp
  80. 58 58
      engine/source/Box2D/Collision/b2TimeOfImpact.h
  81. 225 217
      engine/source/Box2D/Common/b2BlockAllocator.cpp
  82. 68 62
      engine/source/Box2D/Common/b2BlockAllocator.h
  83. 44 44
      engine/source/Box2D/Common/b2Draw.cpp
  84. 92 86
      engine/source/Box2D/Common/b2Draw.h
  85. 57 0
      engine/source/Box2D/Common/b2FreeList.cpp
  86. 113 0
      engine/source/Box2D/Common/b2FreeList.h
  87. 200 0
      engine/source/Box2D/Common/b2GrowableBuffer.h
  88. 87 85
      engine/source/Box2D/Common/b2GrowableStack.h
  89. 369 0
      engine/source/Box2D/Common/b2IntrusiveList.h
  90. 94 94
      engine/source/Box2D/Common/b2Math.cpp
  91. 800 731
      engine/source/Box2D/Common/b2Math.h
  92. 136 44
      engine/source/Box2D/Common/b2Settings.cpp
  93. 267 150
      engine/source/Box2D/Common/b2Settings.h
  94. 244 0
      engine/source/Box2D/Common/b2SlabAllocator.h
  95. 120 83
      engine/source/Box2D/Common/b2StackAllocator.cpp
  96. 64 60
      engine/source/Box2D/Common/b2StackAllocator.h
  97. 67 0
      engine/source/Box2D/Common/b2Stat.cpp
  98. 57 0
      engine/source/Box2D/Common/b2Stat.h
  99. 134 100
      engine/source/Box2D/Common/b2Timer.cpp
  100. 50 50
      engine/source/Box2D/Common/b2Timer.h

+ 1 - 1
.gitignore

@@ -27,7 +27,7 @@ Torque2D_DEBUG.exe
 Torque2DGame.app
 Torque2DGame.app
 Torque2DGame_Debug.app
 Torque2DGame_Debug.app
 linkmap.txt
 linkmap.txt
-.vs/
+**/.vs/**
 
 
 # Compiled source #
 # Compiled source #
 ###################
 ###################

+ 12 - 4
README.md

@@ -1,4 +1,4 @@
-![Torque Logo](http://static.garagegames.com/static/pg/logokits/Torque-Logo_H.png)
+![Torque Logo](modules/Sandbox/1/assets/t2d.png)
 ## Torque 2D 3.4
 ## Torque 2D 3.4
 
 
 MIT Licensed Open Source version of Torque 2D from GarageGames. Maintained by the T2D Steering Committee and contributions from the community.
 MIT Licensed Open Source version of Torque 2D from GarageGames. Maintained by the T2D Steering Committee and contributions from the community.
@@ -15,7 +15,7 @@ Here is an overview of the branches found in the Torque 2D repository:
 
 
 ### Precompiled Version
 ### Precompiled Version
 
 
-If you do not wish to compile the source code yourself, precompiled binary files for Windows and OSX are available from the [Torque 2D Release Page](https://github.com/GarageGames/Torque2D/releases).
+If you do not wish to compile the source code yourself, precompiled binary files for Windows and OSX are available from the [Torque 2D Release Page](https://github.com/TorqueGameEngines/Torque2D/releases).
 
 
 ### Building the Source
 ### Building the Source
 
 
@@ -28,7 +28,7 @@ After downloading a copy of the source code, the following project files for eac
 * **Android:** Android Studio
 * **Android:** Android Studio
 * **Web:** Emscripten/Cmake
 * **Web:** Emscripten/Cmake
 
 
-See the [wiki](https://github.com/GarageGames/Torque2D/wiki) for available guides on platform setup and development.
+See the [wiki](https://github.com/TorqueGameEngines/Torque2D/wiki) for available guides on platform setup and development.
 
 
 ### Batteries Included
 ### Batteries Included
 
 
@@ -40,7 +40,7 @@ The Sandbox is also an excellent framework for rapidly prototyping your own game
 
 
 ### Documentation
 ### Documentation
 
 
-All documentation for the open source version of Torque 2D can be found on our [Github wiki page](https://github.com/GarageGames/Torque2D/wiki). It contains many tutorials, detailed technical information on engine systems, a script reference guide automatically generated from the source code, and articles on how to contribute to our open source development.
+All documentation for the open source version of Torque 2D can be found on our [Github wiki page](https://github.com/TorqueGameEngines/Torque2D/wiki). It contains many tutorials, detailed technical information on engine systems, a script reference guide automatically generated from the source code, and articles on how to contribute to our open source development.
 
 
 ### Community
 ### Community
 
 
@@ -54,6 +54,14 @@ You also might be able to find useful information on the less active GarageGames
 * [Torque 2D Professional Forum](http://www.garagegames.com/community/forums/85)
 * [Torque 2D Professional Forum](http://www.garagegames.com/community/forums/85)
 * [GarageGames Community Blogs](http://www.garagegames.com/community/blogs)
 * [GarageGames Community Blogs](http://www.garagegames.com/community/blogs)
 
 
+### Support
+
+Torque 2D is completely free to use, but like all things, it takes time and energy to maintain and develop. You can support T2D by becoming a sponsor on Patreon. Doing so ensures that T2D will continue receiving the attention it needs to remain competitive.
+
+[Become a Patron](https://www.patreon.com/bePatron?u=15485520)
+
+You can also support development directly by submitting pull requests or joining the steering committee! See the wiki for details.
+
 # License
 # License
 Copyright (c) 2012 GarageGames, LLC
 Copyright (c) 2012 GarageGames, LLC
 
 

+ 46 - 11
editor/AssetAdmin/AssetAdmin.cs

@@ -24,18 +24,50 @@ function AssetAdmin::create(%this)
 {
 {
 	%this.guiPage = EditorCore.RegisterEditor("Asset Manager", %this);
 	%this.guiPage = EditorCore.RegisterEditor("Asset Manager", %this);
 
 
-	%this.comingSoon = new GuiControl()
+	%this.scroller = new GuiScrollCtrl()
 	{
 	{
-		Profile = EditorCore.themes.panelProfile;
-		HorizSizing="center";
-		VertSizing="center";
-		Position="412 324";
-		Extent="200 120";
-		minExtent="8 8";
-		Visible="1";
-		Text = "Coming Soon!";
+		Profile=EditorCore.themes.scrollingPanelProfile;
+		ThumbProfile = EditorCore.themes.scrollingPanelThumbProfile;
+		TrackProfile = EditorCore.themes.scrollingPanelTrackProfile;
+		ArrowProfile = EditorCore.themes.scrollingPanelArrowProfile;
+		HorizSizing="left";
+		VertSizing="height";
+		Position="700 0";
+		Extent="324 768";
+		MinExtent="220 200";
+		hScrollBar="dynamic";
+		vScrollBar="alwaysOn";
+		constantThumbHeight="0";
+		showArrowButtons="1";
+		scrollBarThickness="14";
 	};
 	};
-	%this.guiPage.add(%this.comingSoon);
+	%this.guiPage.add(%this.scroller);
+
+	%this.testLogButton = new GuiButtonCtrl()
+	{
+		Profile = EditorCore.themes.buttonProfile;
+		Text="Test";
+		command="";
+		HorizSizing="bottom";
+		VertSizing="right";
+		Position="0 0";
+		Extent="100 30";
+		MinExtent="80 20";
+	};
+	%this.scroller.add(%this.testLogButton);
+
+	%this.testLogButton2 = new GuiButtonCtrl()
+	{
+		Profile = EditorCore.themes.buttonProfile;
+		Text="Test2";
+		command="";
+		HorizSizing="bottom";
+		VertSizing="right";
+		Position="0 800";
+		Extent="100 30";
+		MinExtent="80 20";
+	};
+	%this.scroller.add(%this.testLogButton2);
 
 
 	EditorCore.FinishRegistration(%this.guiPage);
 	EditorCore.FinishRegistration(%this.guiPage);
 }
 }
@@ -47,7 +79,10 @@ function AssetAdmin::destroy(%this)
 
 
 function AssetAdmin::onThemeChanged(%this, %theme)
 function AssetAdmin::onThemeChanged(%this, %theme)
 {
 {
-	%this.comingSoon.setProfile(%theme.panelProfile);
+	%this.scroller.setProfile(%theme.scrollingPanelProfile);
+	%this.scroller.setThumbProfile(%theme.scrollingPanelThumbProfile);
+	%this.scroller.setTrackProfile(%theme.scrollingPanelTrackProfile);
+	%this.scroller.setArrowProfile(%theme.scrollingPanelArrowProfile);
 }
 }
 
 
 function AssetAdmin::open(%this)
 function AssetAdmin::open(%this)

+ 76 - 10
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj

@@ -18,7 +18,7 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -247,7 +247,7 @@
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetField.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetField.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetFieldCollection.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetFieldCollection.cc" />
-    <ClCompile Include="..\..\source\2d\assets\SkeletonAsset.cc" />
+    <ClCompile Include="..\..\source\2d\assets\SpineAsset.cc" />
     <ClCompile Include="..\..\source\2d\controllers\AmbientForceController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\AmbientForceController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\core\GroupedSceneController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\core\GroupedSceneController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\core\PickingSceneController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\core\PickingSceneController.cc" />
@@ -272,12 +272,15 @@
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ParticlePlayer.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ParticlePlayer.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\Path.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Scroller.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Scroller.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\LightObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ShapeVector.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ShapeVector.cc" />
-    <ClCompile Include="..\..\source\2d\sceneobject\SkeletonObject.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\SpineCollisionProxy.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\SpineObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Sprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Sprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\TextSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\TextSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Trigger.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Trigger.cc" />
@@ -316,10 +319,13 @@
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Draw.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Draw.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2FreeList.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Math.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Math.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Settings.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Settings.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2StackAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2StackAllocator.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2Stat.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Timer.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Timer.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2TrackedBlock.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Fixture.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Fixture.cpp" />
@@ -347,6 +353,11 @@
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2Particle.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleAssembly.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleGroup.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleSystem.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.cpp" />
     <ClCompile Include="..\..\source\Box2D\Rope\b2Rope.cpp" />
     <ClCompile Include="..\..\source\Box2D\Rope\b2Rope.cpp" />
     <ClCompile Include="..\..\source\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
@@ -371,7 +382,7 @@
     <ClCompile Include="..\..\source\graphics\bitmapBmp.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapBmp.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapJpeg.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapJpeg.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapPng.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapPng.cc" />
-    <ClCompile Include="..\..\source\graphics\color.cc" />
+    <ClCompile Include="..\..\source\graphics\gColor.cc" />
     <ClCompile Include="..\..\source\graphics\dgl.cc" />
     <ClCompile Include="..\..\source\graphics\dgl.cc" />
     <ClCompile Include="..\..\source\graphics\dglMatrix.cc" />
     <ClCompile Include="..\..\source\graphics\dglMatrix.cc" />
     <ClCompile Include="..\..\source\graphics\DynamicTexture.cc" />
     <ClCompile Include="..\..\source\graphics\DynamicTexture.cc" />
@@ -589,6 +600,7 @@
     <ClCompile Include="..\..\source\spine\Animation.c" />
     <ClCompile Include="..\..\source\spine\Animation.c" />
     <ClCompile Include="..\..\source\spine\AnimationState.c" />
     <ClCompile Include="..\..\source\spine\AnimationState.c" />
     <ClCompile Include="..\..\source\spine\AnimationStateData.c" />
     <ClCompile Include="..\..\source\spine\AnimationStateData.c" />
+    <ClCompile Include="..\..\source\spine\Array.c" />
     <ClCompile Include="..\..\source\spine\Atlas.c" />
     <ClCompile Include="..\..\source\spine\Atlas.c" />
     <ClCompile Include="..\..\source\spine\AtlasAttachmentLoader.c" />
     <ClCompile Include="..\..\source\spine\AtlasAttachmentLoader.c" />
     <ClCompile Include="..\..\source\spine\Attachment.c" />
     <ClCompile Include="..\..\source\spine\Attachment.c" />
@@ -596,18 +608,34 @@
     <ClCompile Include="..\..\source\spine\Bone.c" />
     <ClCompile Include="..\..\source\spine\Bone.c" />
     <ClCompile Include="..\..\source\spine\BoneData.c" />
     <ClCompile Include="..\..\source\spine\BoneData.c" />
     <ClCompile Include="..\..\source\spine\BoundingBoxAttachment.c" />
     <ClCompile Include="..\..\source\spine\BoundingBoxAttachment.c" />
+    <ClCompile Include="..\..\source\spine\ClippingAttachment.c" />
+    <ClCompile Include="..\..\source\spine\Color.c" />
     <ClCompile Include="..\..\source\spine\Event.c" />
     <ClCompile Include="..\..\source\spine\Event.c" />
     <ClCompile Include="..\..\source\spine\EventData.c" />
     <ClCompile Include="..\..\source\spine\EventData.c" />
     <ClCompile Include="..\..\source\spine\extension.c" />
     <ClCompile Include="..\..\source\spine\extension.c" />
+    <ClCompile Include="..\..\source\spine\IkConstraint.c" />
+    <ClCompile Include="..\..\source\spine\IkConstraintData.c" />
     <ClCompile Include="..\..\source\spine\Json.c" />
     <ClCompile Include="..\..\source\spine\Json.c" />
+    <ClCompile Include="..\..\source\spine\MeshAttachment.c" />
+    <ClCompile Include="..\..\source\spine\PathAttachment.c" />
+    <ClCompile Include="..\..\source\spine\PathConstraint.c" />
+    <ClCompile Include="..\..\source\spine\PathConstraintData.c" />
+    <ClCompile Include="..\..\source\spine\PointAttachment.c" />
     <ClCompile Include="..\..\source\spine\RegionAttachment.c" />
     <ClCompile Include="..\..\source\spine\RegionAttachment.c" />
     <ClCompile Include="..\..\source\spine\Skeleton.c" />
     <ClCompile Include="..\..\source\spine\Skeleton.c" />
+    <ClCompile Include="..\..\source\spine\SkeletonBinary.c" />
     <ClCompile Include="..\..\source\spine\SkeletonBounds.c" />
     <ClCompile Include="..\..\source\spine\SkeletonBounds.c" />
+    <ClCompile Include="..\..\source\spine\SkeletonClipping.c" />
     <ClCompile Include="..\..\source\spine\SkeletonData.c" />
     <ClCompile Include="..\..\source\spine\SkeletonData.c" />
     <ClCompile Include="..\..\source\spine\SkeletonJson.c" />
     <ClCompile Include="..\..\source\spine\SkeletonJson.c" />
     <ClCompile Include="..\..\source\spine\Skin.c" />
     <ClCompile Include="..\..\source\spine\Skin.c" />
     <ClCompile Include="..\..\source\spine\Slot.c" />
     <ClCompile Include="..\..\source\spine\Slot.c" />
     <ClCompile Include="..\..\source\spine\SlotData.c" />
     <ClCompile Include="..\..\source\spine\SlotData.c" />
+    <ClCompile Include="..\..\source\spine\TransformConstraint.c" />
+    <ClCompile Include="..\..\source\spine\TransformConstraintData.c" />
+    <ClCompile Include="..\..\source\spine\Triangulator.c" />
+    <ClCompile Include="..\..\source\spine\VertexAttachment.c" />
+    <ClCompile Include="..\..\source\spine\VertexEffect.c" />
     <ClCompile Include="..\..\source\string\findMatch.cc" />
     <ClCompile Include="..\..\source\string\findMatch.cc" />
     <ClCompile Include="..\..\source\string\stringBuffer.cc" />
     <ClCompile Include="..\..\source\string\stringBuffer.cc" />
     <ClCompile Include="..\..\source\string\stringStack.cc" />
     <ClCompile Include="..\..\source\string\stringStack.cc" />
@@ -651,8 +679,8 @@
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetField.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetField.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetFieldCollection.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetFieldCollection.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAsset_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\2d\assets\SkeletonAsset.h" />
-    <ClInclude Include="..\..\source\2d\assets\SkeletonAsset_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\assets\SpineAsset.h" />
+    <ClInclude Include="..\..\source\2d\assets\SpineAsset_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\controllers\AmbientForceController.h" />
     <ClInclude Include="..\..\source\2d\controllers\AmbientForceController.h" />
     <ClInclude Include="..\..\source\2d\controllers\AmbientForceController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\controllers\AmbientForceController_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\controllers\core\GroupedSceneController.h" />
     <ClInclude Include="..\..\source\2d\controllers\core\GroupedSceneController.h" />
@@ -694,6 +722,8 @@
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\Path.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\Path_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectList.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectList.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h" />
@@ -703,10 +733,13 @@
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject.h" />
-    <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineCollisionProxy.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineObject.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Sprite.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Sprite.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Sprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Sprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\TextSprite.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\TextSprite.h" />
@@ -768,11 +801,17 @@
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Draw.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Draw.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2FreeList.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2GrowableBuffer.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2GrowableStack.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2GrowableStack.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2IntrusiveList.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Settings.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Settings.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2SlabAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2StackAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2StackAllocator.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2Stat.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Timer.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Timer.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2TrackedBlock.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Body.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Body.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2ContactManager.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2ContactManager.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Fixture.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Fixture.h" />
@@ -801,6 +840,12 @@
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2Particle.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleAssembly.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleGroup.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleSystem.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2StackQueue.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.h" />
     <ClInclude Include="..\..\source\Box2D\Rope\b2Rope.h" />
     <ClInclude Include="..\..\source\Box2D\Rope\b2Rope.h" />
     <ClInclude Include="..\..\source\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
@@ -859,8 +904,8 @@
     <ClInclude Include="..\..\source\game\gameInterface.h" />
     <ClInclude Include="..\..\source\game\gameInterface.h" />
     <ClInclude Include="..\..\source\game\gameInterface_ScriptBinding.h" />
     <ClInclude Include="..\..\source\game\gameInterface_ScriptBinding.h" />
     <ClInclude Include="..\..\source\game\version_ScriptBinding.h" />
     <ClInclude Include="..\..\source\game\version_ScriptBinding.h" />
-    <ClInclude Include="..\..\source\graphics\color.h" />
-    <ClInclude Include="..\..\source\graphics\color_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\graphics\gColor.h" />
+    <ClInclude Include="..\..\source\graphics\gColor_ScriptBinding.h" />
     <ClInclude Include="..\..\source\graphics\dgl.h" />
     <ClInclude Include="..\..\source\graphics\dgl.h" />
     <ClInclude Include="..\..\source\graphics\dglMac_Scriptbinding.h" />
     <ClInclude Include="..\..\source\graphics\dglMac_Scriptbinding.h" />
     <ClInclude Include="..\..\source\graphics\dgl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\graphics\dgl_ScriptBinding.h" />
@@ -1168,6 +1213,7 @@
     <ClInclude Include="..\..\source\spine\Animation.h" />
     <ClInclude Include="..\..\source\spine\Animation.h" />
     <ClInclude Include="..\..\source\spine\AnimationState.h" />
     <ClInclude Include="..\..\source\spine\AnimationState.h" />
     <ClInclude Include="..\..\source\spine\AnimationStateData.h" />
     <ClInclude Include="..\..\source\spine\AnimationStateData.h" />
+    <ClInclude Include="..\..\source\spine\Array.h" />
     <ClInclude Include="..\..\source\spine\Atlas.h" />
     <ClInclude Include="..\..\source\spine\Atlas.h" />
     <ClInclude Include="..\..\source\spine\AtlasAttachmentLoader.h" />
     <ClInclude Include="..\..\source\spine\AtlasAttachmentLoader.h" />
     <ClInclude Include="..\..\source\spine\Attachment.h" />
     <ClInclude Include="..\..\source\spine\Attachment.h" />
@@ -1175,19 +1221,36 @@
     <ClInclude Include="..\..\source\spine\Bone.h" />
     <ClInclude Include="..\..\source\spine\Bone.h" />
     <ClInclude Include="..\..\source\spine\BoneData.h" />
     <ClInclude Include="..\..\source\spine\BoneData.h" />
     <ClInclude Include="..\..\source\spine\BoundingBoxAttachment.h" />
     <ClInclude Include="..\..\source\spine\BoundingBoxAttachment.h" />
+    <ClInclude Include="..\..\source\spine\ClippingAttachment.h" />
+    <ClInclude Include="..\..\source\spine\Color.h" />
+    <ClInclude Include="..\..\source\spine\dll.h" />
     <ClInclude Include="..\..\source\spine\Event.h" />
     <ClInclude Include="..\..\source\spine\Event.h" />
     <ClInclude Include="..\..\source\spine\EventData.h" />
     <ClInclude Include="..\..\source\spine\EventData.h" />
     <ClInclude Include="..\..\source\spine\extension.h" />
     <ClInclude Include="..\..\source\spine\extension.h" />
+    <ClInclude Include="..\..\source\spine\IkConstraint.h" />
+    <ClInclude Include="..\..\source\spine\IkConstraintData.h" />
     <ClInclude Include="..\..\source\spine\Json.h" />
     <ClInclude Include="..\..\source\spine\Json.h" />
+    <ClInclude Include="..\..\source\spine\MeshAttachment.h" />
+    <ClInclude Include="..\..\source\spine\PathAttachment.h" />
+    <ClInclude Include="..\..\source\spine\PathConstraint.h" />
+    <ClInclude Include="..\..\source\spine\PathConstraintData.h" />
+    <ClInclude Include="..\..\source\spine\PointAttachment.h" />
     <ClInclude Include="..\..\source\spine\RegionAttachment.h" />
     <ClInclude Include="..\..\source\spine\RegionAttachment.h" />
     <ClInclude Include="..\..\source\spine\Skeleton.h" />
     <ClInclude Include="..\..\source\spine\Skeleton.h" />
+    <ClInclude Include="..\..\source\spine\SkeletonBinary.h" />
     <ClInclude Include="..\..\source\spine\SkeletonBounds.h" />
     <ClInclude Include="..\..\source\spine\SkeletonBounds.h" />
+    <ClInclude Include="..\..\source\spine\SkeletonClipping.h" />
     <ClInclude Include="..\..\source\spine\SkeletonData.h" />
     <ClInclude Include="..\..\source\spine\SkeletonData.h" />
     <ClInclude Include="..\..\source\spine\SkeletonJson.h" />
     <ClInclude Include="..\..\source\spine\SkeletonJson.h" />
     <ClInclude Include="..\..\source\spine\Skin.h" />
     <ClInclude Include="..\..\source\spine\Skin.h" />
     <ClInclude Include="..\..\source\spine\Slot.h" />
     <ClInclude Include="..\..\source\spine\Slot.h" />
     <ClInclude Include="..\..\source\spine\SlotData.h" />
     <ClInclude Include="..\..\source\spine\SlotData.h" />
     <ClInclude Include="..\..\source\spine\spine.h" />
     <ClInclude Include="..\..\source\spine\spine.h" />
+    <ClInclude Include="..\..\source\spine\TransformConstraint.h" />
+    <ClInclude Include="..\..\source\spine\TransformConstraintData.h" />
+    <ClInclude Include="..\..\source\spine\Triangulator.h" />
+    <ClInclude Include="..\..\source\spine\VertexAttachment.h" />
+    <ClInclude Include="..\..\source\spine\VertexEffect.h" />
     <ClInclude Include="..\..\source\string\findMatch.h" />
     <ClInclude Include="..\..\source\string\findMatch.h" />
     <ClInclude Include="..\..\source\string\stringBuffer.h" />
     <ClInclude Include="..\..\source\string\stringBuffer.h" />
     <ClInclude Include="..\..\source\string\stringBuffer_ScriptBinding.h" />
     <ClInclude Include="..\..\source\string\stringBuffer_ScriptBinding.h" />
@@ -1286,6 +1349,9 @@
   <ItemGroup>
   <ItemGroup>
     <Image Include="Torque 2D.ico" />
     <Image Include="Torque 2D.ico" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>

+ 224 - 27
engine/compilers/VisualStudio 2017/Torque 2D.vcxproj.filters

@@ -199,6 +199,9 @@
     <Filter Include="bitmapFont">
     <Filter Include="bitmapFont">
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
     </Filter>
     </Filter>
+    <Filter Include="Box2D\Particle">
+      <UniqueIdentifier>{b2903a96-6c49-4961-82a8-f1832989d4a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1173,9 +1176,6 @@
     <ClCompile Include="..\..\source\platformWin32\nativeDialogs\win32FileDialog.cc">
     <ClCompile Include="..\..\source\platformWin32\nativeDialogs\win32FileDialog.cc">
       <Filter>platformWin32\nativeDialogs</Filter>
       <Filter>platformWin32\nativeDialogs</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\graphics\color.cc">
-      <Filter>graphics</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc">
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc">
       <Filter>2d\assets</Filter>
       <Filter>2d\assets</Filter>
     </ClCompile>
     </ClCompile>
@@ -1350,12 +1350,6 @@
     <ClCompile Include="..\..\source\spine\SlotData.c">
     <ClCompile Include="..\..\source\spine\SlotData.c">
       <Filter>spine</Filter>
       <Filter>spine</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\2d\assets\SkeletonAsset.cc">
-      <Filter>2d\assets</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\source\2d\sceneobject\SkeletonObject.cc">
-      <Filter>2d\sceneobject</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\audio\vorbisStreamSource.cc">
     <ClCompile Include="..\..\source\audio\vorbisStreamSource.cc">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClCompile>
     </ClCompile>
@@ -1384,6 +1378,99 @@
     <ClCompile Include="..\..\source\gui\guiTextCtrl.cc">
     <ClCompile Include="..\..\source\gui\guiTextCtrl.cc">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2Particle.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleAssembly.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleGroup.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleSystem.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2FreeList.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2Stat.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2TrackedBlock.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\LightObject.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\Path.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\Array.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\ClippingAttachment.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\Color.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\IkConstraint.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\IkConstraintData.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\MeshAttachment.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\PathAttachment.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\PathConstraint.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\PathConstraintData.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\PointAttachment.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\SkeletonBinary.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\SkeletonClipping.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\TransformConstraint.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\TransformConstraintData.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\Triangulator.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\VertexAttachment.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\spine\VertexEffect.c">
+      <Filter>spine</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\graphics\gColor.cc">
+      <Filter>graphics</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\SpineObject.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\assets\SpineAsset.cc">
+      <Filter>2d\assets</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\SpineCollisionProxy.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2178,9 +2265,6 @@
     <ClInclude Include="..\..\source\algorithm\hashFunction.h">
     <ClInclude Include="..\..\source\algorithm\hashFunction.h">
       <Filter>algorithm</Filter>
       <Filter>algorithm</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\graphics\color.h">
-      <Filter>graphics</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\collection\bitMatrix.h">
     <ClInclude Include="..\..\source\collection\bitMatrix.h">
       <Filter>collection</Filter>
       <Filter>collection</Filter>
     </ClInclude>
     </ClInclude>
@@ -2769,9 +2853,6 @@
     <ClInclude Include="..\..\source\console\expando_ScriptBinding.h">
     <ClInclude Include="..\..\source\console\expando_ScriptBinding.h">
       <Filter>console</Filter>
       <Filter>console</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\graphics\color_ScriptBinding.h">
-      <Filter>graphics</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\sim\simObject_ScriptBinding.h">
     <ClInclude Include="..\..\source\sim\simObject_ScriptBinding.h">
       <Filter>sim</Filter>
       <Filter>sim</Filter>
     </ClInclude>
     </ClInclude>
@@ -3031,18 +3112,6 @@
     <ClInclude Include="..\..\source\spine\spine.h">
     <ClInclude Include="..\..\source\spine\spine.h">
       <Filter>spine</Filter>
       <Filter>spine</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\SkeletonAsset.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\source\2d\assets\SkeletonAsset_ScriptBinding.h">
-      <Filter>2d\assets</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject_ScriptBinding.h">
-      <Filter>2d\sceneobject</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject.h">
-      <Filter>2d\sceneobject</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\audio\vorbisStreamSource.h">
     <ClInclude Include="..\..\source\audio\vorbisStreamSource.h">
       <Filter>audio</Filter>
       <Filter>audio</Filter>
     </ClInclude>
     </ClInclude>
@@ -3103,6 +3172,129 @@
     <ClInclude Include="..\..\source\gui\guiTextCtrl.h">
     <ClInclude Include="..\..\source\gui\guiTextCtrl.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2Particle.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleAssembly.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleGroup.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleSystem.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2StackQueue.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2FreeList.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2GrowableBuffer.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2IntrusiveList.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2SlabAllocator.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2Stat.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2TrackedBlock.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\Path.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\Path_ScriptBinding.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject_ScriptBinding.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\Array.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\ClippingAttachment.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\Color.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\dll.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\IkConstraint.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\IkConstraintData.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\MeshAttachment.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\PathAttachment.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\PathConstraint.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\PathConstraintData.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\PointAttachment.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\SkeletonBinary.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\SkeletonClipping.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\TransformConstraint.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\TransformConstraintData.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\Triangulator.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\VertexAttachment.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\spine\VertexEffect.h">
+      <Filter>spine</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\graphics\gColor.h">
+      <Filter>graphics</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\graphics\gColor_ScriptBinding.h">
+      <Filter>graphics</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineObject.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineObject_ScriptBinding.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\assets\SpineAsset.h">
+      <Filter>2d\assets</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\assets\SpineAsset_ScriptBinding.h">
+      <Filter>2d\assets</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\SpineCollisionProxy.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
@@ -3124,4 +3316,9 @@
   <ItemGroup>
   <ItemGroup>
     <Image Include="Torque 2D.ico" />
     <Image Include="Torque 2D.ico" />
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s">
+      <Filter>Box2D\Particle</Filter>
+    </None>
+  </ItemGroup>
 </Project>
 </Project>

+ 1 - 1
engine/compilers/VisualStudio 2017/libogg.vcxproj

@@ -30,7 +30,7 @@
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <RootNamespace>libogg</RootNamespace>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/libvorbis.vcxproj

@@ -22,7 +22,7 @@
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <RootNamespace>libvorbis</RootNamespace>
     <RootNamespace>libvorbis</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/ljpeg.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/lpng.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 1 - 1
engine/compilers/VisualStudio 2017/zlib.vcxproj

@@ -46,7 +46,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">

+ 3 - 4
engine/compilers/VisualStudio 2019/Torque 2D.rc

@@ -36,18 +36,18 @@ IDI_TORQUE2D               ICON    DISCARDABLE     "Torque 2D.ico"
 // TEXTINCLUDE
 // TEXTINCLUDE
 //
 //
 
 
-1 TEXTINCLUDE DISCARDABLE 
+1 TEXTINCLUDE DISCARDABLE
 BEGIN
 BEGIN
     "resource.h\0"
     "resource.h\0"
 END
 END
 
 
-2 TEXTINCLUDE DISCARDABLE 
+2 TEXTINCLUDE DISCARDABLE
 BEGIN
 BEGIN
     "#include ""afxres.h""\r\n"
     "#include ""afxres.h""\r\n"
     "\0"
     "\0"
 END
 END
 
 
-3 TEXTINCLUDE DISCARDABLE 
+3 TEXTINCLUDE DISCARDABLE
 BEGIN
 BEGIN
     "\r\n"
     "\r\n"
     "\0"
     "\0"
@@ -107,4 +107,3 @@ END
 
 
 /////////////////////////////////////////////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////
 #endif    // not APSTUDIO_INVOKED
 #endif    // not APSTUDIO_INVOKED
-

+ 31 - 2
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj

@@ -18,7 +18,7 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -272,10 +272,12 @@
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ParticlePlayer.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ParticlePlayer.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\Path.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Scroller.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Scroller.cc" />
+    <ClCompile Include="..\..\source\2d\sceneobject\LightObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ShapeVector.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\ShapeVector.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SkeletonObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SkeletonObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Sprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Sprite.cc" />
@@ -316,10 +318,13 @@
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Draw.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Draw.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2FreeList.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Math.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Math.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Settings.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Settings.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2StackAllocator.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2StackAllocator.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2Stat.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Timer.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2Timer.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Common\b2TrackedBlock.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Fixture.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Fixture.cpp" />
@@ -347,6 +352,11 @@
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2Particle.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleAssembly.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleGroup.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleSystem.cpp" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.cpp" />
     <ClCompile Include="..\..\source\Box2D\Rope\b2Rope.cpp" />
     <ClCompile Include="..\..\source\Box2D\Rope\b2Rope.cpp" />
     <ClCompile Include="..\..\source\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
@@ -704,6 +714,8 @@
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\Path.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\Path_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectList.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectList.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObjectMoveToEvent.h" />
@@ -713,6 +725,8 @@
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SceneObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\Scroller_ScriptBinding.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject.h" />
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ShapeVector_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject.h" />
@@ -778,11 +792,17 @@
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Draw.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Draw.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2FreeList.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2GrowableBuffer.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2GrowableStack.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2GrowableStack.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2IntrusiveList.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Settings.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Settings.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2SlabAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2StackAllocator.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2StackAllocator.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2Stat.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Timer.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Timer.h" />
+    <ClInclude Include="..\..\source\Box2D\Common\b2TrackedBlock.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Body.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Body.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2ContactManager.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2ContactManager.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Fixture.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\b2Fixture.h" />
@@ -811,6 +831,12 @@
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2RopeJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WeldJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.h" />
     <ClInclude Include="..\..\source\Box2D\Dynamics\Joints\b2WheelJoint.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2Particle.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleAssembly.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleGroup.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleSystem.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2StackQueue.h" />
+    <ClInclude Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.h" />
     <ClInclude Include="..\..\source\Box2D\Rope\b2Rope.h" />
     <ClInclude Include="..\..\source\Box2D\Rope\b2Rope.h" />
     <ClInclude Include="..\..\source\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
@@ -1300,7 +1326,10 @@
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
     </ProjectReference>
     </ProjectReference>
   </ItemGroup>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 87 - 1
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj.filters

@@ -199,6 +199,9 @@
     <Filter Include="bitmapFont">
     <Filter Include="bitmapFont">
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
     </Filter>
     </Filter>
+    <Filter Include="Box2D\Particle">
+      <UniqueIdentifier>{b2903a96-6c49-4961-82a8-f1832989d4a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1414,6 +1417,36 @@
     <ClCompile Include="..\..\source\platform\platformNet.cpp" />
     <ClCompile Include="..\..\source\platform\platformNet.cpp" />
     <ClCompile Include="..\..\source\platform\platformNetAsync.cpp" />
     <ClCompile Include="..\..\source\platform\platformNetAsync.cpp" />
     <ClCompile Include="..\..\source\platform\platformNet_ScriptBinding.cc" />
     <ClCompile Include="..\..\source\platform\platformNet_ScriptBinding.cc" />
+    <ClCompile Include="..\..\source\Box2D\Particle\b2Particle.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleAssembly.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleGroup.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2ParticleSystem.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.cpp">
+      <Filter>Box2D\Particle</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2FreeList.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2Stat.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\Box2D\Common\b2TrackedBlock.cpp">
+      <Filter>Box2D\Common</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\LightObject.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\source\2d\sceneobject\Path.cc">
+      <Filter>2d\sceneobject</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3156,6 +3189,54 @@
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h">
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h">
       <Filter>gui\containers</Filter>
       <Filter>gui\containers</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2VoronoiDiagram.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2Particle.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleAssembly.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleGroup.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2ParticleSystem.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Particle\b2StackQueue.h">
+      <Filter>Box2D\Particle</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2FreeList.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2GrowableBuffer.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2IntrusiveList.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2SlabAllocator.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2Stat.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\Box2D\Common\b2TrackedBlock.h">
+      <Filter>Box2D\Common</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\Path.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\Path_ScriptBinding.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\2d\sceneobject\LightObject_ScriptBinding.h">
+      <Filter>2d\sceneobject</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
@@ -3174,4 +3255,9 @@
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <ResourceCompile Include="Torque 2D.rc" />
   </ItemGroup>
   </ItemGroup>
-</Project>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s">
+      <Filter>Box2D\Particle</Filter>
+    </None>
+  </ItemGroup>
+</Project>

+ 2 - 2
engine/compilers/VisualStudio 2019/libogg.vcxproj

@@ -30,7 +30,7 @@
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <ProjectGuid>{15CBFEFF-7965-41F5-B4E2-21E8795C9159}</ProjectGuid>
     <RootNamespace>libogg</RootNamespace>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -179,4 +179,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 2 - 2
engine/compilers/VisualStudio 2019/libvorbis.vcxproj

@@ -22,7 +22,7 @@
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <ProjectGuid>{3A214E06-B95E-4D61-A291-1F8DF2EC10FD}</ProjectGuid>
     <RootNamespace>libvorbis</RootNamespace>
     <RootNamespace>libvorbis</RootNamespace>
     <Keyword>Win32Proj</Keyword>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -241,4 +241,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 2 - 2
engine/compilers/VisualStudio 2019/ljpeg.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
     <ProjectGuid>{0B07BA94-AA53-4FD4-ADB4-79EC2DA53B36}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -628,4 +628,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 2 - 2
engine/compilers/VisualStudio 2019/lpng.vcxproj

@@ -16,7 +16,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
     <ProjectGuid>{AF1179E3-A838-46A3-A427-1E62AA4C52F4}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -184,4 +184,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

+ 2 - 2
engine/compilers/VisualStudio 2019/zlib.vcxproj

@@ -46,7 +46,7 @@
   </ItemGroup>
   </ItemGroup>
   <PropertyGroup Label="Globals">
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -182,4 +182,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
   </ImportGroup>
-</Project>
+</Project>

File diff suppressed because it is too large
+ 384 - 322
engine/compilers/Xcode/Torque2D.xcodeproj/project.pbxproj


+ 62 - 0
engine/source/2d/assets/ParticleAssetEmitter.cc

@@ -81,6 +81,56 @@ const char* ParticleAssetEmitter::getEmitterTypeDescription( const EmitterType e
     return StringTable->EmptyString;
     return StringTable->EmptyString;
 }
 }
 
 
+//-----------------------------------------------------------------------------
+
+static EnumTable::Enums physicsParticleType[] =
+{
+   {b2ParticleFlag::b2_barrierParticle,            "BarrierPartice"},
+   {b2ParticleFlag::b2_colorMixingParticle,        "ColorMixingParticle"},
+   {b2ParticleFlag::b2_destructionListenerParticle,"DesctructionListenerParticle"},
+   {b2ParticleFlag::b2_elasticParticle,            "ElasticParticle"},
+   {b2ParticleFlag::b2_powderParticle,             "PowderParticle"},
+   {b2ParticleFlag::b2_reactiveParticle,           "ReactiveParticle"},
+   {b2ParticleFlag::b2_repulsiveParticle,          "RepulsiveParticle"},
+   {b2ParticleFlag::b2_springParticle,             "SpringParticle"},
+   {b2ParticleFlag::b2_staticPressureParticle,     "StaticPressureParticle"},
+   {b2ParticleFlag::b2_tensileParticle,            "TensileParticle"},
+   {b2ParticleFlag::b2_viscousParticle,            "ViscousParticle"},
+   {b2ParticleFlag::b2_wallParticle,               "WallParticle"},
+   {b2ParticleFlag::b2_waterParticle,              "WaterParticle"},
+   {b2ParticleFlag::b2_zombieParticle,             "ZombieParticle"}
+};
+
+
+static EnumTable  PhysicsParticleTypeTable(sizeof(physicsParticleType) / sizeof(EnumTable::Enums), &physicsParticleType[0]);
+
+ParticleAssetEmitter::PhysicsParticleType ParticleAssetEmitter::getPhysicsParticleTypeEnum(const char* label)
+{
+   for (U32 i = 0; i < (sizeof(physicsParticleType) / sizeof(EnumTable::Enums)); i++)
+      if (dStricmp(physicsParticleType[i].label, label) == 0)
+         return((ParticleAssetEmitter::PhysicsParticleType)physicsParticleType[i].index);
+
+   // Warn.
+   Con::warnf("ParticleAssetEmitter::getPhysicsParticleType() - Invalid physics particle type '%s'.", label);
+
+   return ParticleAssetEmitter::INVALID_PHYSICS_PARTICLE_TYPE;
+}
+
+const char* ParticleAssetEmitter::getPhysicsParticleTypeDescription(const PhysicsParticleType particleType)
+{
+   // Search for Mnemonic.
+   for (U32 i = 0; i < (sizeof(physicsParticleType) / sizeof(EnumTable::Enums)); i++)
+   {
+      if (physicsParticleType[i].index == (S32)particleType)
+         return physicsParticleType[i].label;
+   }
+
+   // Warn.
+   Con::warnf("ParticleAssetEmitter::getPhysicsParticleTypeDescription() - Invalid physics particle-type");
+
+   return StringTable->EmptyString;
+}
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 static EnumTable::Enums particleOrientationTypeLookup[] =
 static EnumTable::Enums particleOrientationTypeLookup[] =
@@ -132,7 +182,11 @@ ParticleAssetEmitter::ParticleAssetEmitter() :
                             mEmitterName( StringTable->EmptyString ),
                             mEmitterName( StringTable->EmptyString ),
                             mOwner( NULL ),
                             mOwner( NULL ),
                             mEmitterType( POINT_EMITTER ),
                             mEmitterType( POINT_EMITTER ),
+                            mPhysicsParticleType(b2_waterParticle),
+                            mPhysicsParticles(false),
                             mEmitterOffset( 0.0f, 0.0f),
                             mEmitterOffset( 0.0f, 0.0f),
+                            mTargetParticle(false),
+                            mTargetPosition(0.0f, 0.0f),
                             mEmitterAngle( 0.0f ),
                             mEmitterAngle( 0.0f ),
                             mEmitterSize( 10.0f, 10.0f ),
                             mEmitterSize( 10.0f, 10.0f ),
                             mFixedAspect( true ),
                             mFixedAspect( true ),
@@ -224,6 +278,14 @@ void ParticleAssetEmitter::initPersistFields()
     addProtectedField("EmitterName", TypeString, Offset(mEmitterName, ParticleAssetEmitter), &setEmitterName, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
     addProtectedField("EmitterName", TypeString, Offset(mEmitterName, ParticleAssetEmitter), &setEmitterName, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
     addProtectedField("EmitterType", TypeEnum, Offset(mEmitterType, ParticleAssetEmitter), &setEmitterType, &defaultProtectedGetFn, &writeEmitterType, 1, &EmitterTypeTable);
     addProtectedField("EmitterType", TypeEnum, Offset(mEmitterType, ParticleAssetEmitter), &setEmitterType, &defaultProtectedGetFn, &writeEmitterType, 1, &EmitterTypeTable);
     addProtectedField("EmitterOffset", TypeVector2, Offset(mEmitterOffset, ParticleAssetEmitter), &setEmitterOffset, &defaultProtectedGetFn, &writeEmitterOffset, "");
     addProtectedField("EmitterOffset", TypeVector2, Offset(mEmitterOffset, ParticleAssetEmitter), &setEmitterOffset, &defaultProtectedGetFn, &writeEmitterOffset, "");
+    addProtectedField("IsTargeting", TypeBool, Offset(mTargetParticle, ParticleAssetEmitter), &setIsTargeting, &defaultProtectedGetFn, &writeTargetParticle, "");
+    addProtectedField("TargetPosition", TypeVector2, Offset(mTargetPosition, ParticleAssetEmitter), &setTargetPosition, &defaultProtectedGetFn, &writeTargetPosition, "");
+
+    //Physics Particles
+    addProtectedField("PhysicsParticle", TypeBool, Offset(mPhysicsParticles, ParticleAssetEmitter), &setPhysicsParticles, &defaultProtectedGetFn, &writePhysicsParticles, "");
+    addProtectedField("PhysicsParticleType", TypeEnum, Offset(mPhysicsParticleType, ParticleAssetEmitter), &setPhysicsParticleType, &defaultProtectedGetFn, &writePhysicsParticleType, 1, &PhysicsParticleTypeTable);
+    //Physics Particles end---
+
     addProtectedField("EmitterAngle", TypeF32, Offset(mEmitterAngle, ParticleAssetEmitter), &setEmitterAngle, &defaultProtectedGetFn, &writeEmitterAngle, "");
     addProtectedField("EmitterAngle", TypeF32, Offset(mEmitterAngle, ParticleAssetEmitter), &setEmitterAngle, &defaultProtectedGetFn, &writeEmitterAngle, "");
     addProtectedField("EmitterSize", TypeVector2, Offset(mEmitterSize, ParticleAssetEmitter), &setEmitterSize, &defaultProtectedGetFn, &writeEmitterSize, "");
     addProtectedField("EmitterSize", TypeVector2, Offset(mEmitterSize, ParticleAssetEmitter), &setEmitterSize, &defaultProtectedGetFn, &writeEmitterSize, "");
     addProtectedField("FixedAspect", TypeBool, Offset(mFixedAspect, ParticleAssetEmitter), &setFixedAspect, &defaultProtectedGetFn, &writeFixedAspect, "");
     addProtectedField("FixedAspect", TypeBool, Offset(mFixedAspect, ParticleAssetEmitter), &setFixedAspect, &defaultProtectedGetFn, &writeFixedAspect, "");

+ 57 - 1
engine/source/2d/assets/ParticleAssetEmitter.h

@@ -71,6 +71,26 @@ public:
         TORUS_EMITTER,
         TORUS_EMITTER,
     };
     };
 
 
+    enum PhysicsParticleType
+    {
+       INVALID_PHYSICS_PARTICLE_TYPE,
+
+       b2_barrierParticle,
+       b2_colorMixingParticle,
+       b2_destructionListenerParticle,
+       b2_elasticParticle,
+       b2_powderParticle,
+       b2_reactiveParticle,
+       b2_repulsiveParticle,
+       b2_springParticle,
+       b2_staticPressureParticle,
+       b2_tensileParticle,
+       b2_viscousParticle,
+       b2_wallParticle,
+       b2_waterParticle,
+       b2_zombieParticle
+    };
+
 private:
 private:
     typedef SimObject Parent;
     typedef SimObject Parent;
 
 
@@ -91,7 +111,14 @@ private:
     F32                                     mRandomArc;
     F32                                     mRandomArc;
     F32                                     mFixedAngleOffset;
     F32                                     mFixedAngleOffset;
     Vector2                                 mPivotPoint;
     Vector2                                 mPivotPoint;
-
+    //Physics Particles
+    PhysicsParticleType                     mPhysicsParticleType;
+    bool                                    mPhysicsParticles;
+    //Physics Particles end---
+    //Particle Target
+    bool                                    mTargetParticle;
+    Vector2                                 mTargetPosition;
+    //Particle Target end---
     bool                                    mLinkEmissionRotation;
     bool                                    mLinkEmissionRotation;
     bool                                    mIntenseParticles;
     bool                                    mIntenseParticles;
     bool                                    mSingleParticle;
     bool                                    mSingleParticle;
@@ -157,6 +184,18 @@ public:
     inline const Vector2& getFixedForceDirection( void ) const { return mFixedForceDirection; }
     inline const Vector2& getFixedForceDirection( void ) const { return mFixedForceDirection; }
     inline void setOrientationType( const ParticleOrientationType particleOrientationType ) { mOrientationType = particleOrientationType; refreshAsset(); }
     inline void setOrientationType( const ParticleOrientationType particleOrientationType ) { mOrientationType = particleOrientationType; refreshAsset(); }
     inline ParticleOrientationType getOrientationType( void ) const { return mOrientationType; }
     inline ParticleOrientationType getOrientationType( void ) const { return mOrientationType; }
+    //Physics particles
+    inline void setPhysicsParticleType(const PhysicsParticleType physicsParticleType) { mPhysicsParticleType = physicsParticleType; refreshAsset(); }
+    inline PhysicsParticleType getPhysicsParticleType(void) const { return mPhysicsParticleType; }
+    inline void setPhysicsParticles(const bool physicsPaticle) { mPhysicsParticles = physicsPaticle; refreshAsset(); }
+    inline bool getPhysicsParticles(void) const { return mPhysicsParticles; }
+    //Phyiscs particles end---
+    //Particle Target
+    inline void setTargetPosition(const Vector2& targetPos) { mTargetPosition = targetPos; }
+    inline const Vector2& getTargetPosition(void) const { return mTargetPosition; }
+    inline void setIsTargeting(const bool targetParticle) { mTargetParticle = targetParticle; refreshAsset(); }
+    inline bool getIsTargeting(void) const { return mTargetParticle; }
+    //Particle Target end---
     inline void setKeepAligned( const bool keepAligned ) { mKeepAligned = keepAligned; refreshAsset(); }
     inline void setKeepAligned( const bool keepAligned ) { mKeepAligned = keepAligned; refreshAsset(); }
     inline bool getKeepAligned( void ) const { return mKeepAligned; }
     inline bool getKeepAligned( void ) const { return mKeepAligned; }
     inline void setAlignedAngleOffset( const F32 angleOffset ) { mAlignedAngleOffset = angleOffset; refreshAsset(); }
     inline void setAlignedAngleOffset( const F32 angleOffset ) { mAlignedAngleOffset = angleOffset; refreshAsset(); }
@@ -250,6 +289,10 @@ public:
 
 
     static EmitterType getEmitterTypeEnum(const char* label);
     static EmitterType getEmitterTypeEnum(const char* label);
     static const char* getEmitterTypeDescription( const EmitterType emitterType );
     static const char* getEmitterTypeDescription( const EmitterType emitterType );
+    //phyiscs particles
+    static PhysicsParticleType getPhysicsParticleTypeEnum(const char * label);
+    static const char* getPhysicsParticleTypeDescription(const PhysicsParticleType particleType);
+    //physics particles end----
     static ParticleOrientationType getOrientationTypeEnum(const char* label);
     static ParticleOrientationType getOrientationTypeEnum(const char* label);
     static const char* getOrientationTypeDescription( const ParticleOrientationType orientationType );
     static const char* getOrientationTypeDescription( const ParticleOrientationType orientationType );
 
 
@@ -270,6 +313,12 @@ protected:
     static bool     writeEmitterType( void* obj, StringTableEntry pFieldName )          { return static_cast<ParticleAssetEmitter*>(obj)->getEmitterType() != POINT_EMITTER; }
     static bool     writeEmitterType( void* obj, StringTableEntry pFieldName )          { return static_cast<ParticleAssetEmitter*>(obj)->getEmitterType() != POINT_EMITTER; }
     static bool     setEmitterOffset(void* obj, const char* data)                       { static_cast<ParticleAssetEmitter*>(obj)->setEmitterOffset(Vector2(data)); return false; }
     static bool     setEmitterOffset(void* obj, const char* data)                       { static_cast<ParticleAssetEmitter*>(obj)->setEmitterOffset(Vector2(data)); return false; }
     static bool     writeEmitterOffset( void* obj, StringTableEntry pFieldName )        { return static_cast<ParticleAssetEmitter*>(obj)->getEmitterOffset().notZero(); }
     static bool     writeEmitterOffset( void* obj, StringTableEntry pFieldName )        { return static_cast<ParticleAssetEmitter*>(obj)->getEmitterOffset().notZero(); }
+
+    static bool     setIsTargeting(void* obj, const char* data)                      { static_cast<ParticleAssetEmitter*>(obj)->setIsTargeting(dAtob(data)); return false; }
+    static bool     writeTargetParticle(void* obj, StringTableEntry pFieldName)         { return static_cast<ParticleAssetEmitter*>(obj)->getIsTargeting() == false; }
+    static bool     setTargetPosition(void* obj, const char* data)                      { static_cast<ParticleAssetEmitter*>(obj)->setTargetPosition(Vector2(data)); return false; }
+    static bool     writeTargetPosition(void* obj, StringTableEntry pFieldName)         { return static_cast<ParticleAssetEmitter*>(obj)->getTargetPosition().notZero(); }
+
     static bool     setEmitterAngle(void* obj, const char* data)                        { static_cast<ParticleAssetEmitter*>(obj)->setEmitterAngle(dAtof(data)); return false; }
     static bool     setEmitterAngle(void* obj, const char* data)                        { static_cast<ParticleAssetEmitter*>(obj)->setEmitterAngle(dAtof(data)); return false; }
     static bool     writeEmitterAngle( void* obj, StringTableEntry pFieldName )         { return mNotZero(static_cast<ParticleAssetEmitter*>(obj)->getEmitterAngle()); }
     static bool     writeEmitterAngle( void* obj, StringTableEntry pFieldName )         { return mNotZero(static_cast<ParticleAssetEmitter*>(obj)->getEmitterAngle()); }
     static bool     setEmitterSize(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setEmitterSize(Vector2(data)); return false; }
     static bool     setEmitterSize(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setEmitterSize(Vector2(data)); return false; }
@@ -278,6 +327,13 @@ protected:
     static bool     writeFixedAspect( void* obj, StringTableEntry pFieldName )          { return static_cast<ParticleAssetEmitter*>(obj)->getFixedAspect() == false; }
     static bool     writeFixedAspect( void* obj, StringTableEntry pFieldName )          { return static_cast<ParticleAssetEmitter*>(obj)->getFixedAspect() == false; }
     static bool     setFixedForceAngle(void* obj, const char* data)                     { static_cast<ParticleAssetEmitter*>(obj)->setFixedForceAngle(dAtof(data)); return false; }
     static bool     setFixedForceAngle(void* obj, const char* data)                     { static_cast<ParticleAssetEmitter*>(obj)->setFixedForceAngle(dAtof(data)); return false; }
     static bool     writeFixedForceAngle( void* obj, StringTableEntry pFieldName )      { return mNotZero(static_cast<ParticleAssetEmitter*>(obj)->getFixedForceAngle() ); }
     static bool     writeFixedForceAngle( void* obj, StringTableEntry pFieldName )      { return mNotZero(static_cast<ParticleAssetEmitter*>(obj)->getFixedForceAngle() ); }
+    //Physics Particles
+    static bool     setPhysicsParticleType(void* obj, const char* data)                { static_cast<ParticleAssetEmitter*>(obj)->setPhysicsParticleType(getPhysicsParticleTypeEnum(data)); return false; }
+    static bool     writePhysicsParticleType(void* obj, StringTableEntry pFieldName)   { return static_cast<ParticleAssetEmitter*>(obj)->getPhysicsParticleType() != b2_zombieParticle; }
+    static bool     setPhysicsParticles(void* obj, const char* data)                    { static_cast<ParticleAssetEmitter*>(obj)->setPhysicsParticles(dAtob(data)); return false; }
+    static bool     writePhysicsParticles(void* obj, StringTableEntry pFieldName)       { return static_cast<ParticleAssetEmitter*>(obj)->getPhysicsParticles() == false; }
+    //Physics Particles end---
+
     static bool     setOrientationType(void* obj, const char* data)                     { static_cast<ParticleAssetEmitter*>(obj)->setOrientationType( getOrientationTypeEnum(data) ); return false; }
     static bool     setOrientationType(void* obj, const char* data)                     { static_cast<ParticleAssetEmitter*>(obj)->setOrientationType( getOrientationTypeEnum(data) ); return false; }
     static bool     writeOrientationType( void* obj, StringTableEntry pFieldName )      { return static_cast<ParticleAssetEmitter*>(obj)->getOrientationType() != FIXED_ORIENTATION; }
     static bool     writeOrientationType( void* obj, StringTableEntry pFieldName )      { return static_cast<ParticleAssetEmitter*>(obj)->getOrientationType() != FIXED_ORIENTATION; }
     static bool     setKeepAligned(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setKeepAligned(dAtob(data)); return false; }
     static bool     setKeepAligned(void* obj, const char* data)                         { static_cast<ParticleAssetEmitter*>(obj)->setKeepAligned(dAtob(data)); return false; }

+ 57 - 0
engine/source/2d/assets/ParticleAssetEmitter_ScriptBinding.h

@@ -123,6 +123,63 @@ ConsoleMethodWithDocs(ParticleAssetEmitter, getEmitterOffset, ConsoleString, 2,
     return object->getEmitterOffset().scriptThis();
     return object->getEmitterOffset().scriptThis();
 }
 }
 
 
+/*! Sets if the emitter targets a point.
+    @param target The point that the emitter's particles will be drawn to.
+    @return No return value.
+*/
+ConsoleMethodWithDocs(ParticleAssetEmitter, setIsTargeting, ConsoleVoid, 3, 3, (target))
+{
+   object->setIsTargeting(dAtob(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets whether the emitter targets a point.
+    @return True if the emitter uses a target for particles.
+*/
+ConsoleMethodWithDocs(ParticleAssetEmitter, getIsTargeting, ConsoleBool, 2, 2, ())
+{
+   return object->getIsTargeting();
+}
+
+/* Sets the world point that the emitter will target. Targeting must be turned on with setIsTargeting().
+    @param Position The world point that will be the target.
+    @return No return value.
+*/
+ConsoleMethodWithDocs(ParticleAssetEmitter, setTargetPosition, ConsoleVoid, 3, 4, (float X / float Y))
+{
+   // Grab the element count.
+   U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+   // ("positionX positionY")
+   if ((elementCount == 2) && (argc < 4))
+   {
+      object->setTargetPosition(Vector2(argv[2]));
+      return;
+   }
+
+   // (positionX, positionY)
+   if ((elementCount == 1) && (argc > 3))
+   {
+      object->setTargetPosition(Vector2(dAtof(argv[2]), dAtof(argv[3])));
+      return;
+   }
+
+   // Warn.
+   Con::warnf("ParticleAssetEmitter::setTargetPosition() - Invalid number of parameters!");
+}
+
+//------------------------------------------------------------------------------
+
+/*! Gets the emitter target position.
+    @return (float x/float y) The position of the target of the emitter.
+*/
+ConsoleMethodWithDocs(ParticleAssetEmitter, getTargetPosition, ConsoleString, 2, 2, ())
+{
+   return object->getTargetPosition().scriptThis();
+}
+
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 /*! Sets the emitter size.
 /*! Sets the emitter size.

+ 0 - 386
engine/source/2d/assets/SkeletonAsset.cc

@@ -1,386 +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 _CONSOLE_H_
-#include "console/console.h"
-#endif
-
-#ifndef _CONSOLEINTERNAL_H_
-#include "console/consoleInternal.h"
-#endif
-
-#ifndef _GBITMAP_H_
-#include "graphics/gBitmap.h"
-#endif
-
-#ifndef _UTILITY_H_
-#include "2d/core/Utility.h"
-#endif
-
-#ifndef _SCENE_OBJECT_H_
-#include "2d/sceneobject/SceneObject.h"
-#endif
-
-#ifndef _SKELETON_ASSET_H_
-#include "2d/assets/SkeletonAsset.h"
-#endif
-
-// Script bindings.
-#include "SkeletonAsset_ScriptBinding.h"
-
-//------------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(SkeletonAsset);
-
-//------------------------------------------------------------------------------
-
-ConsoleType( skeletonAssetPtr, TypeSkeletonAssetPtr, sizeof(AssetPtr<SkeletonAsset>), ASSET_ID_FIELD_PREFIX )
-
-//-----------------------------------------------------------------------------
-
-ConsoleGetType( TypeSkeletonAssetPtr )
-{
-    // Fetch asset Id.
-    return (*((AssetPtr<SkeletonAsset>*)dptr)).getAssetId();
-}
-
-//-----------------------------------------------------------------------------
-
-ConsoleSetType( TypeSkeletonAssetPtr )
-{
-    // Was a single argument specified?
-    if( argc == 1 )
-    {
-        // Yes, so fetch field value.
-        const char* pFieldValue = argv[0];
-
-        // Fetch asset pointer.
-        AssetPtr<SkeletonAsset>* pAssetPtr = dynamic_cast<AssetPtr<SkeletonAsset>*>((AssetPtrBase*)(dptr));
-
-        // Is the asset pointer the correct type?
-        if (pAssetPtr == NULL )
-        {
-            // No, so fail.
-            Con::warnf( "(TypeSkeletonAssetPtr) - Failed to set asset Id '%d'.", pFieldValue );
-            return;
-        }
-
-        // Set asset.
-        pAssetPtr->setAssetId( pFieldValue );
-
-        return;
-   }
-
-    // Warn.
-    Con::warnf( "(TypeSkeletonAssetPtr) - Cannot set multiple args to a single asset." );
-}
-
-
-//------------------------------------------------------------------------------
-
-SkeletonAsset::SkeletonAsset() :    mSkeletonFile(StringTable->EmptyString),
-                                    mAtlasFile(StringTable->EmptyString),
-                                    mAtlasDirty(true),
-                                    mAtlas(NULL),
-                                    mSkeletonData(NULL),
-                                    mStateData(NULL)
-{
-}
-
-//------------------------------------------------------------------------------
-
-SkeletonAsset::~SkeletonAsset()
-{
-    spAnimationStateData_dispose(mStateData);
-    spSkeletonData_dispose(mSkeletonData);
-    spAtlas_dispose(mAtlas);
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::initPersistFields()
-{
-    // Call parent.
-    Parent::initPersistFields();
-
-    // Fields.
-    addProtectedField("AtlasFile", TypeAssetLooseFilePath, Offset(mAtlasFile, SkeletonAsset), &setAtlasFile, &defaultProtectedGetFn, &writeAtlasFile, "The loose file pointing to the .atlas file used for skinning");
-    addProtectedField("SkeletonFile", TypeAssetLooseFilePath, Offset(mSkeletonFile, SkeletonAsset), &setSkeletonFile, &defaultProtectedGetFn, &writeSkeletonFile, "The loose file produced by the editor, which is fed into this asset");
-}
-
-//------------------------------------------------------------------------------
-
-bool SkeletonAsset::onAdd()
-{
-    // Call Parent.
-    if (!Parent::onAdd())
-       return false;
-
-    return true;
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::onRemove()
-{
-    // Call Parent.
-    Parent::onRemove();
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::setSkeletonFile( const char* pSkeletonFile )
-{
-    // Sanity!
-    AssertFatal( pSkeletonFile != NULL, "Cannot use a NULL skeleton file." );
-
-    // Fetch skeleton file.
-    pSkeletonFile = StringTable->insert( pSkeletonFile );
-
-    // Ignore no change.
-    if (pSkeletonFile == mSkeletonFile )
-        return;
-
-    // Update.
-    mSkeletonFile = getOwned() ? expandAssetFilePath( pSkeletonFile ) : StringTable->insert( pSkeletonFile );
-
-    // Refresh the asset.
-    refreshAsset();
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::setAtlasFile( const char* pAtlasFile )
-{
-    // Sanity!
-    AssertFatal( pAtlasFile != NULL, "Cannot use a NULL atlas file." );
-
-    // Fetch atlas file.
-    pAtlasFile = StringTable->insert( pAtlasFile );
-
-    // Ignore no change.
-    if (pAtlasFile == mAtlasFile )
-        return;
-
-    // Update.
-    mAtlasFile = getOwned() ? expandAssetFilePath( pAtlasFile ) : StringTable->insert( pAtlasFile );
-    mAtlasDirty = true;
-
-    // Refresh the asset.
-    refreshAsset();
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::copyTo(SimObject* object)
-{
-    // Call to parent.
-    Parent::copyTo(object);
-
-    // Cast to asset.
-    SkeletonAsset* pAsset = static_cast<SkeletonAsset*>(object);
-
-    // Sanity!
-    AssertFatal(pAsset != NULL, "SkeletonAsset::copyTo() - Object is not the correct type.");
-
-    // Copy state.
-    pAsset->setAtlasFile( getAtlasFile() );
-    pAsset->setSkeletonFile( getSkeletonFile() );
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::initializeAsset( void )
-{
-    // Call parent.
-    Parent::initializeAsset();
-
-    // Ensure the skeleton file is expanded.
-    mSkeletonFile = expandAssetFilePath( mSkeletonFile );
-
-    // Ensure the skeleton file is expanded.
-    mAtlasFile = expandAssetFilePath( mAtlasFile );
-
-    // Build the atlas data
-    if (mAtlasDirty)
-        buildAtlasData();
-
-    // Build the skeleton data
-    buildSkeletonData();
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::onAssetRefresh( void )
-{
-    // Ignore if not yet added to the sim.
-    if (!isProperlyAdded() )
-        return;
-
-    // Call parent.
-    Parent::onAssetRefresh();
-
-    // Reset any states or data
-    if (mAtlasDirty)
-        buildAtlasData();
-
-    buildSkeletonData();
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonAsset::buildAtlasData( void )
-{
-    // If the atlas data was previously created, need to release it
-    if (mAtlas)
-        spAtlas_dispose(mAtlas);
-
-    // If we are using a .atlas file
-    if (mAtlasFile != StringTable->EmptyString)
-        mAtlas = spAtlas_readAtlasFile(mAtlasFile);
-
-    // Atlas load failure
-    AssertFatal(mAtlas != NULL, "SkeletonAsset::buildAtlasData() - Atlas was not loaded.");
-
-    spAtlasPage* currentPage = mAtlas->pages;
-
-    while (currentPage != NULL)
-    {
-        // Allocate a new ImageAsset. If we have multiple atlases, we would loop this multiple times
-        ImageAsset* pImageAsset = new ImageAsset();
-
-        const char* imageFilePath = expandAssetFilePath(currentPage->name);
-        
-        // Point to the raw file (png or jpg)
-        pImageAsset->setImageFile( imageFilePath);        
-
-        // Enable Explicit Mode so we can use region coordinates
-        pImageAsset->setExplicitMode( true );
-
-        spAtlasRegion* currentRegion = mAtlas->regions;
-
-        // Add it to the AssetDatabase, making it accessible everywhere
-        mImageAsset = AssetDatabase.addPrivateAsset( pImageAsset );
-
-        // Loop through the Atlas information to create cell regions
-        while (currentRegion != NULL)
-        {
-            pImageAsset->addExplicitCell( currentRegion->x, currentRegion->y, currentRegion->width, currentRegion->height, currentRegion->name );
-
-            currentRegion = currentRegion->next;
-        }
-
-        mImageAsset->forceCalculation();
-        currentPage = currentPage->next;
-    }
-
-    mAtlasDirty = false;
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonAsset::buildSkeletonData( void )
-{
-    // Atlas load failure
-    AssertFatal(mAtlas != NULL, "SkeletonAsset::buildSkeletonData() - Atlas was not loaded.");
-    
-    // Clear state data
-    if (mStateData)
-        spAnimationStateData_dispose(mStateData);
-
-    // Clear skeleton data
-    if (mSkeletonData)
-        spSkeletonData_dispose(mSkeletonData);
-    
-    spSkeletonJson* json = spSkeletonJson_create(mAtlas);
-    mSkeletonData = spSkeletonJson_readSkeletonDataFile(json, mSkeletonFile);
-
-    if (!mSkeletonData)
-    {
-        spAtlas_dispose(mAtlas);
-        mAtlas = 0;
-
-        // Report json->error message
-        AssertFatal(mSkeletonData != NULL, "SkeletonAsset::buildSkeletonData() - Skeleton data was not valid.");
-    }
-
-    spSkeletonJson_dispose(json);
-
-    mStateData = spAnimationStateData_create(mSkeletonData);
-}
-
-//-----------------------------------------------------------------------------
-
-bool SkeletonAsset::isAssetValid( void ) const
-{
-    return ((mAtlas != NULL) && (mSkeletonData != NULL) && (mStateData != NULL) && mImageAsset.notNull());
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonAsset::onTamlPreWrite( void )
-{
-    // Call parent.
-    Parent::onTamlPreWrite();
-
-    // Ensure the skeleton file is collapsed.
-    mSkeletonFile = collapseAssetFilePath( mSkeletonFile );
-
-    // Ensure the atlas file is collapsed.
-    mAtlasFile = collapseAssetFilePath( mAtlasFile );
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonAsset::onTamlPostWrite( void )
-{
-    // Call parent.
-    Parent::onTamlPostWrite();
-
-    // Ensure the skeleton file is expanded.
-    mSkeletonFile = expandAssetFilePath( mSkeletonFile );
-
-    // Ensure the atlas file is expanded.
-    mAtlasFile = expandAssetFilePath( mAtlasFile );
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonAsset::onTamlCustomWrite( TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(SkeletonAsset_OnTamlCustomWrite);
-
-    // Call parent.
-    Parent::onTamlCustomWrite( customNodes );
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonAsset::onTamlCustomRead( const TamlCustomNodes& customNodes )
-{
-    // Debug Profiling.
-    PROFILE_SCOPE(SkeletonAsset_OnTamlCustomRead);
-
-    // Call parent.
-    Parent::onTamlCustomRead( customNodes );
-}

+ 0 - 101
engine/source/2d/assets/SkeletonAsset.h

@@ -1,101 +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 _SKELETON_ASSET_H_
-#define _SKELETON_ASSET_H_
-
-#ifndef _ASSET_PTR_H_
-#include "assets/assetPtr.h"
-#endif
-
-#ifndef _IMAGE_ASSET_H_
-#include "2d/assets/ImageAsset.h"
-#endif
-
-#ifndef SPINE_SPINE_H_
-#include "spine/spine.h"
-#endif
-
-//-----------------------------------------------------------------------------
-
-DefineConsoleType( TypeSkeletonAssetPtr )
-
-//-----------------------------------------------------------------------------
-
-class SkeletonAsset : public AssetBase
-{
-private:
-    typedef AssetBase Parent;
-    bool                            mAtlasDirty;
-
-public:
-    StringTableEntry                mSkeletonFile;
-    StringTableEntry                mAtlasFile;
-    AssetPtr<ImageAsset>            mImageAsset;
-    spAtlas*                        mAtlas;
-    spSkeletonData*                 mSkeletonData;
-    spAnimationStateData*           mStateData;
-
-public:
-    SkeletonAsset();
-    virtual ~SkeletonAsset();
-
-    /// Core.
-    static void initPersistFields();
-    virtual bool onAdd();
-    virtual void onRemove();
-    virtual void copyTo(SimObject* object);
-
-    void                    setSkeletonFile( const char* pSkeletonFile );
-    inline StringTableEntry getSkeletonFile( void ) const                   { return mSkeletonFile; }
-
-    void                    setAtlasFile( const char* pAtlasFile );
-    inline StringTableEntry getAtlasFile( void ) const                      { return mAtlasFile; }
-    
-    virtual bool            isAssetValid( void ) const;
-
-    /// Declare Console Object.
-    DECLARE_CONOBJECT(SkeletonAsset);
-
-private:
-    void buildAtlasData( void );
-    void buildSkeletonData( void );
-
-protected:
-    virtual void initializeAsset( void );
-    virtual void onAssetRefresh( void );
-
-    /// Taml callbacks.
-    virtual void onTamlPreWrite( void );
-    virtual void onTamlPostWrite( void );
-    virtual void onTamlCustomWrite( TamlCustomNodes& customNodes );
-    virtual void onTamlCustomRead( const TamlCustomNodes& customNodes );
-
-
-protected:
-    static bool setSkeletonFile( void* obj, const char* data )              { static_cast<SkeletonAsset*>(obj)->setSkeletonFile(data); return false; }
-    static bool writeSkeletonFile( void* obj, StringTableEntry pFieldName ) { return static_cast<SkeletonAsset*>(obj)->getSkeletonFile() != StringTable->EmptyString; }
-    static bool setAtlasFile( void* obj, const char* data )                 { static_cast<SkeletonAsset*>(obj)->setAtlasFile(data); return false; }
-    static bool writeAtlasFile( void* obj, StringTableEntry pFieldName )    { return static_cast<SkeletonAsset*>(obj)->getAtlasFile() != StringTable->EmptyString; }
-};
-
-#endif // _SKELETON_ASSET_H_

+ 434 - 0
engine/source/2d/assets/SpineAsset.cc

@@ -0,0 +1,434 @@
+//-----------------------------------------------------------------------------
+// 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 _CONSOLE_H_
+#include "console/console.h"
+#endif
+
+#ifndef _CONSOLEINTERNAL_H_
+#include "console/consoleInternal.h"
+#endif
+
+#ifndef _GBITMAP_H_
+#include "graphics/gBitmap.h"
+#endif
+
+#ifndef _UTILITY_H_
+#include "2d/core/Utility.h"
+#endif
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+#ifndef _SPINE_ASSET_H_
+#include "2d/assets/SpineAsset.h"
+#endif
+
+// Script bindings.
+#include "SpineAsset_ScriptBinding.h"
+
+#include "spine/extension.h"
+
+//------------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(SpineAsset);
+
+//------------------------------------------------------------------------------
+
+ConsoleType(spineAssetPtr, TypeSpineAssetPtr, sizeof(AssetPtr<SpineAsset>), ASSET_ID_FIELD_PREFIX)
+
+//-----------------------------------------------------------------------------
+
+ConsoleGetType(TypeSpineAssetPtr)
+{
+	// Fetch asset Id.
+	return (*((AssetPtr<SpineAsset>*)dptr)).getAssetId();
+}
+
+//-----------------------------------------------------------------------------
+
+ConsoleSetType(TypeSpineAssetPtr)
+{
+	// Was a single argument specified?
+	if (argc == 1)
+	{
+		// Yes, so fetch field value.
+		const char* pFieldValue = argv[0];
+
+		// Fetch asset pointer.
+		AssetPtr<SpineAsset>* pAssetPtr = dynamic_cast<AssetPtr<SpineAsset>*>((AssetPtrBase*)(dptr));
+
+		// Is the asset pointer the correct type?
+		if (pAssetPtr == NULL)
+		{
+			// No, so fail.
+			Con::warnf("(TypeSpineAssetPtr) - Failed to set asset Id '%d'.", pFieldValue);
+			return;
+		}
+
+		// Set asset.
+		pAssetPtr->setAssetId(pFieldValue);
+
+		return;
+	}
+
+	// Warn.
+	Con::warnf("(TypeSpineAssetPtr) - Cannot set multiple args to a single asset.");
+}
+
+
+//-----------------------------------------------------------------------------
+// 
+// The following three methods are hooks required to be defined by the spine runtime.
+//
+//-----------------------------------------------------------------------------
+void _spAtlasPage_createTexture(spAtlasPage* self, const char* path) {
+
+	// Allocate a new ImageAsset. 
+	ImageAsset* pImageAsset = new ImageAsset();
+
+	SpineAsset *pSpine = (SpineAsset *)self->atlas->rendererObject;
+	const char* imageFilePath = pSpine->expandAssetFilePath(self->name);
+
+	// Point to the raw file (png or jpg)
+	pImageAsset->setImageFile(imageFilePath);
+
+	// Enable Explicit Mode so we can use region coordinates
+	pImageAsset->setExplicitMode(true);
+
+	// Add it to the AssetDatabase, making it accessible everywhere
+	pSpine->mImageAsset = AssetDatabase.addPrivateAsset(pImageAsset);
+
+	// Attach texture info for the page.
+	self->rendererObject = pSpine->mImageAsset;
+	self->width = pImageAsset->getImageWidth();
+	self->height = pImageAsset->getImageHeight();
+}
+
+void _spAtlasPage_disposeTexture(spAtlasPage* self) {
+}
+
+char* _spUtil_readFile(const char* path, int* length) {
+	return _spReadFile(path, length);
+}
+
+//------------------------------------------------------------------------------
+
+SpineAsset::SpineAsset() : mSpineFile(StringTable->EmptyString),
+mAtlasFile(StringTable->EmptyString),
+mAtlasDirty(true),
+mAtlas(NULL),
+mSkeletonData(NULL),
+mAnimationStateData(NULL),
+mPreMultipliedAlpha(false)
+
+{
+}
+
+//------------------------------------------------------------------------------
+
+SpineAsset::~SpineAsset()
+{
+	spAnimationStateData_dispose(mAnimationStateData);
+	spSkeletonData_dispose(mSkeletonData);
+	spAtlas_dispose(mAtlas);
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::initPersistFields()
+{
+	// Call parent.
+	Parent::initPersistFields();
+
+	// Fields.
+	addProtectedField("AtlasFile", TypeAssetLooseFilePath, Offset(mAtlasFile, SpineAsset), &setAtlasFile, &defaultProtectedGetFn, &writeAtlasFile, "The loose file pointing to the .atlas file used for skinning");
+	addProtectedField("SpineFile", TypeAssetLooseFilePath, Offset(mSpineFile, SpineAsset), &setSpineFile, &defaultProtectedGetFn, &writeSpineFile, "The loose file produced by the editor, which is fed into this asset");
+	addProtectedField("PreMultipliedAlpha", TypeBool, Offset(mPreMultipliedAlpha, SpineAsset), &setPreMultipliedAlpha, &defaultProtectedGetFn, &writePreMultipliedAlpha, "Whether texture is built with pre-multiplied alpha values.");
+}
+
+//------------------------------------------------------------------------------
+
+bool SpineAsset::onAdd()
+{
+	// Call Parent.
+	if (!Parent::onAdd())
+		return false;
+
+	return true;
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::onRemove()
+{
+	// Call Parent.
+	Parent::onRemove();
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::setSpineFile(const char* pSpineFile)
+{
+	// Sanity!
+	AssertFatal(pSpineFile != NULL, "Cannot use a NULL spine file.");
+
+	// Fetch spine file.
+	pSpineFile = StringTable->insert(pSpineFile);
+
+	// Ignore no change.
+	if (pSpineFile == mSpineFile)
+		return;
+
+	// Update.
+	mSpineFile = getOwned() ? expandAssetFilePath(pSpineFile) : StringTable->insert(pSpineFile);
+
+	// Refresh the asset.
+	refreshAsset();
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::setAtlasFile(const char* pAtlasFile)
+{
+	// Sanity!
+	AssertFatal(pAtlasFile != NULL, "Cannot use a NULL atlas file.");
+
+	// Fetch atlas file.
+	pAtlasFile = StringTable->insert(pAtlasFile);
+
+	// Ignore no change.
+	if (pAtlasFile == mAtlasFile)
+		return;
+
+	// Update.
+	mAtlasFile = getOwned() ? expandAssetFilePath(pAtlasFile) : StringTable->insert(pAtlasFile);
+	mAtlasDirty = true;
+
+	// Refresh the asset.
+	refreshAsset();
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::copyTo(SimObject* object)
+{
+	// Call to parent.
+	Parent::copyTo(object);
+
+	// Cast to asset.
+	SpineAsset* pAsset = static_cast<SpineAsset*>(object);
+
+	// Sanity!
+	AssertFatal(pAsset != NULL, "SpineAsset::copyTo() - Object is not the correct type.");
+
+	// Copy state.
+	pAsset->setAtlasFile(getAtlasFile());
+	pAsset->setSpineFile(getSpineFile());
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::initializeAsset(void)
+{
+	// Call parent.
+	Parent::initializeAsset();
+
+	// Ensure the spine file is expanded.
+	mSpineFile = expandAssetFilePath(mSpineFile);
+
+	// Ensure the spine file is expanded.
+	mAtlasFile = expandAssetFilePath(mAtlasFile);
+
+	// Build the atlas data
+	if (mAtlasDirty)
+		buildAtlasData();
+
+	// Build the spine data
+	buildSpineData();
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::onAssetRefresh(void)
+{
+	// Ignore if not yet added to the sim.
+	if (!isProperlyAdded())
+		return;
+
+	// Call parent.
+	Parent::onAssetRefresh();
+
+	// Reset any states or data
+	if (mAtlasDirty)
+		buildAtlasData();
+
+	buildSpineData();
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineAsset::buildAtlasData(void)
+{
+	// If the atlas data was previously created, need to release it
+	if (mAtlas)
+		spAtlas_dispose(mAtlas);
+
+	// If we are using a .atlas file
+	if (mAtlasFile != StringTable->EmptyString)
+		mAtlas = spAtlas_createFromFile(mAtlasFile, this);
+
+	// Atlas load failure
+	AssertFatal(mAtlas != NULL, "SpineAsset::buildAtlasData() - Atlas was not loaded.");
+
+	spAtlasPage* currentPage = mAtlas->pages;
+
+	while (currentPage != NULL)
+	{
+		ImageAsset* pImageAsset = (ImageAsset *)currentPage->rendererObject;
+
+		spAtlasRegion* currentRegion = mAtlas->regions;
+
+		// Loop through the Atlas information to create cell regions
+		while (currentRegion != NULL)
+		{
+			if (currentRegion->rotate) {
+				pImageAsset->addExplicitCell(currentRegion->x, currentRegion->y, currentRegion->height, currentRegion->width, currentRegion->name);
+			}
+			else {
+				pImageAsset->addExplicitCell(currentRegion->x, currentRegion->y, currentRegion->width, currentRegion->height, currentRegion->name);
+			}
+
+			currentRegion = currentRegion->next;
+		}
+
+		mImageAsset->forceCalculation();
+		currentPage = currentPage->next;
+	}
+
+	mAtlasDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineAsset::buildSpineData(void)
+{
+	// Atlas load failure
+	AssertFatal(mAtlas != NULL, "SpineAsset::buildSpineData() - Atlas was not loaded.");
+
+	// Clear state data
+	if (mAnimationStateData)
+		spAnimationStateData_dispose(mAnimationStateData);
+
+	// Clear skeleton data
+	if (mSkeletonData)
+		spSkeletonData_dispose(mSkeletonData);
+
+	// Determine if we have a json or binary file to process.
+	AssertFatal(mSpineFile != NULL, "SpineAsset::buildSpineData() - Spine data file name is not defined.");
+
+	if (Platform::hasExtension(mSpineFile, "skel")) {
+		spSkeletonBinary* skel = spSkeletonBinary_create(mAtlas);
+		skel->scale = 0.01f; // Adapt to box2d coordinate size - where 1 unit = 1 meter.
+		mSkeletonData = spSkeletonBinary_readSkeletonDataFile(skel, mSpineFile);
+		spSkeletonBinary_dispose(skel);
+	}
+	else if (Platform::hasExtension(mSpineFile, "json")) {
+		spSkeletonJson* json = spSkeletonJson_create(mAtlas);
+		json->scale = 0.01f;
+		mSkeletonData = spSkeletonJson_readSkeletonDataFile(json, mSpineFile);
+		spSkeletonJson_dispose(json);
+	}
+	else {
+		AssertFatal(mSkeletonData != NULL,
+			"SpineAsset::buildSpineData: Unrecognized spine data file extension recieved.  Expecting either '.json' or '.skel'.");
+	}
+
+	if (!mSkeletonData)
+	{
+		spAtlas_dispose(mAtlas);
+		mAtlas = 0;
+
+		// Report json->error message
+		AssertFatal(mSkeletonData != NULL, "SpineAsset::buildSpineData() - Spine data was not valid.");
+	}
+
+	mAnimationStateData = spAnimationStateData_create(mSkeletonData);
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineAsset::isAssetValid(void) const
+{
+	return ((mAtlas != NULL) && (mSkeletonData != NULL) && (mAnimationStateData != NULL) && mImageAsset.notNull());
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineAsset::onTamlPreWrite(void)
+{
+	// Call parent.
+	Parent::onTamlPreWrite();
+
+	// Ensure the spine file is collapsed.
+	mSpineFile = collapseAssetFilePath(mSpineFile);
+
+	// Ensure the atlas file is collapsed.
+	mAtlasFile = collapseAssetFilePath(mAtlasFile);
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineAsset::onTamlPostWrite(void)
+{
+	// Call parent.
+	Parent::onTamlPostWrite();
+
+	// Ensure the spine file is expanded.
+	mSpineFile = expandAssetFilePath(mSpineFile);
+
+	// Ensure the atlas file is expanded.
+	mAtlasFile = expandAssetFilePath(mAtlasFile);
+}
+
+//------------------------------------------------------------------------------
+
+void SpineAsset::onTamlCustomWrite(TamlCustomNodes& customNodes)
+{
+	// Debug Profiling.
+	PROFILE_SCOPE(SpineAsset_OnTamlCustomWrite);
+
+	// Call parent.
+	Parent::onTamlCustomWrite(customNodes);
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineAsset::onTamlCustomRead(const TamlCustomNodes& customNodes)
+{
+	// Debug Profiling.
+	PROFILE_SCOPE(SpineAsset_OnTamlCustomRead);
+
+	// Call parent.
+	Parent::onTamlCustomRead(customNodes);
+}

+ 107 - 0
engine/source/2d/assets/SpineAsset.h

@@ -0,0 +1,107 @@
+//-----------------------------------------------------------------------------
+// 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 _SPINE_ASSET_H_
+#define _SPINE_ASSET_H_
+
+#ifndef _ASSET_PTR_H_
+#include "assets/assetPtr.h"
+#endif
+
+#ifndef _IMAGE_ASSET_H_
+#include "2d/assets/ImageAsset.h"
+#endif
+
+#ifndef SPINE_SPINE_H_
+#include "spine/spine.h"
+#endif
+
+//-----------------------------------------------------------------------------
+
+DefineConsoleType(TypeSpineAssetPtr)
+
+//-----------------------------------------------------------------------------
+
+class SpineAsset : public AssetBase
+{
+private:
+	typedef AssetBase Parent;
+	bool                            mAtlasDirty;
+	bool							mPreMultipliedAlpha;
+
+public:
+	StringTableEntry                mSpineFile;
+	StringTableEntry                mAtlasFile;
+	AssetPtr<ImageAsset>            mImageAsset;
+	spAtlas*                        mAtlas;
+	spSkeletonData*                 mSkeletonData;
+	spAnimationStateData*           mAnimationStateData;
+
+public:
+	SpineAsset();
+	virtual ~SpineAsset();
+
+	/// Core.
+	static void initPersistFields();
+	virtual bool onAdd();
+	virtual void onRemove();
+	virtual void copyTo(SimObject* object);
+
+	void                    setSpineFile(const char* pSpineFile);
+	inline StringTableEntry getSpineFile(void) const { return mSpineFile; }
+
+	void                    setAtlasFile(const char* pAtlasFile);
+	inline StringTableEntry getAtlasFile(void) const { return mAtlasFile; }
+
+	virtual bool            isAssetValid(void) const;
+
+	inline void				setPreMultipliedAlpha(const bool usePMA) { mPreMultipliedAlpha = usePMA; }
+	inline bool				getPreMultipliedAlpha(void) const { return mPreMultipliedAlpha; }
+
+	/// Declare Console Object.
+	DECLARE_CONOBJECT(SpineAsset);
+
+private:
+	void buildAtlasData(void);
+	void buildSpineData(void);
+
+protected:
+	virtual void initializeAsset(void);
+	virtual void onAssetRefresh(void);
+
+	/// Taml callbacks.
+	virtual void onTamlPreWrite(void);
+	virtual void onTamlPostWrite(void);
+	virtual void onTamlCustomWrite(TamlCustomNodes& customNodes);
+	virtual void onTamlCustomRead(const TamlCustomNodes& customNodes);
+
+
+protected:
+	static bool setSpineFile(void* obj, const char* data) { static_cast<SpineAsset*>(obj)->setSpineFile(data); return false; }
+	static bool writeSpineFile(void* obj, StringTableEntry pFieldName) { return static_cast<SpineAsset*>(obj)->getSpineFile() != StringTable->EmptyString; }
+	static bool setAtlasFile(void* obj, const char* data) { static_cast<SpineAsset*>(obj)->setAtlasFile(data); return false; }
+	static bool writeAtlasFile(void* obj, StringTableEntry pFieldName) { return static_cast<SpineAsset*>(obj)->getAtlasFile() != StringTable->EmptyString; }
+	static bool setPreMultipliedAlpha(void* obj, const char* data) { static_cast<SpineAsset*>(obj)->setPreMultipliedAlpha(dAtob(data)); return false; }
+	static bool writePreMultipliedAlpha(void* obj, StringTableEntry pFieldName) { return static_cast<SpineAsset*>(obj)->getPreMultipliedAlpha(); }
+};
+
+#endif // _SPINE_ASSET_H_

+ 16 - 16
engine/source/2d/assets/SkeletonAsset_ScriptBinding.h → engine/source/2d/assets/SpineAsset_ScriptBinding.h

@@ -20,46 +20,46 @@
 // IN THE SOFTWARE.
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-ConsoleMethodGroupBeginWithDocs(SkeletonAsset, AssetBase)
+ConsoleMethodGroupBeginWithDocs(SpineAsset, AssetBase)
 
 
 /*! Sets the atlas file.
 /*! Sets the atlas file.
-    @return No return value.
+	@return No return value.
 */
 */
-ConsoleMethodWithDocs(SkeletonAsset, setAtlasFile, ConsoleVoid, 3, 3, (AtlasFile))
+ConsoleMethodWithDocs(SpineAsset, setAtlasFile, ConsoleVoid, 3, 3, (AtlasFile))
 {
 {
-    object->setAtlasFile( argv[2] );
+	object->setAtlasFile(argv[2]);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 /*! Gets the atlas file.
 /*! Gets the atlas file.
-    @return Returns the atlas file.
+	@return Returns the atlas file.
 */
 */
-ConsoleMethodWithDocs(SkeletonAsset, getAtlasFile, ConsoleString, 2, 2, ())
+ConsoleMethodWithDocs(SpineAsset, getAtlasFile, ConsoleString, 2, 2, ())
 {
 {
-    return object->getAtlasFile();
+	return object->getAtlasFile();
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-/*! Sets the skeleton file.
-    @return No return value.
+/*! Sets the spine file.
+	@return No return value.
 */
 */
-ConsoleMethodWithDocs(SkeletonAsset, setSkeletonFile, ConsoleVoid, 3, 3, (SkeletonFile))
+ConsoleMethodWithDocs(SpineAsset, setSpineFile, ConsoleVoid, 3, 3, (SpineFile))
 {
 {
-    object->setSkeletonFile( argv[2] );
+	object->setSpineFile(argv[2]);
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
-/*! Gets the skeleton file.
-    @return Returns the skeleton file.
+/*! Gets the spine file.
+	@return Returns the spine file.
 */
 */
-ConsoleMethodWithDocs(SkeletonAsset, getSkeletonFile, ConsoleString, 2, 2, ())
+ConsoleMethodWithDocs(SpineAsset, getSpineFile, ConsoleString, 2, 2, ())
 {
 {
-    return object->getSkeletonFile();
+	return object->getSpineFile();
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-ConsoleMethodGroupEndWithDocs(SkeletonAsset)
+ConsoleMethodGroupEndWithDocs(SpineAsset)

+ 18 - 38
engine/source/2d/core/BatchRender.cc

@@ -103,8 +103,8 @@ void BatchRender::SubmitTriangles(
         const U32 vertexCount,
         const U32 vertexCount,
         const Vector2* pVertexArray,
         const Vector2* pVertexArray,
         const Vector2* pTextureArray,
         const Vector2* pTextureArray,
-        TextureHandle& texture,
-        const ColorF& color )
+		const ColorF*  pColorArray,
+		TextureHandle& texture)
 {
 {
     // Debug Profiling.
     // Debug Profiling.
     PROFILE_SCOPE(BatchRender_SubmitTriangles);
     PROFILE_SCOPE(BatchRender_SubmitTriangles);
@@ -117,28 +117,17 @@ void BatchRender::SubmitTriangles(
     // Calculate triangle count.
     // Calculate triangle count.
     const U32 triangleCount = vertexCount / 3;
     const U32 triangleCount = vertexCount / 3;
 
 
-    // Would we exceed the triangle buffer size?
     if ( (mTriangleCount + triangleCount) > BATCHRENDER_MAXTRIANGLES )
     if ( (mTriangleCount + triangleCount) > BATCHRENDER_MAXTRIANGLES )
     {
     {
-        // Yes, so flush.
+        // No room in the batch for the incoming request, so flush the current batch contents.
         flush( mpDebugStats->batchBufferFullFlush );
         flush( mpDebugStats->batchBufferFullFlush );
     }
     }
-    // Do we have anything batched?
-    else if ( mTriangleCount > 0 )
-    {
-        // Yes, so do we have any existing colors?
-        if ( mColorCount == 0 )
-        {
-            // No, so flush if color is specified.
-            if ( color != NoColor  )
-                flush( mpDebugStats->batchColorStateFlush );
-        }
-        else
-        {
-            // Yes, so flush if color is not specified.
-            if ( color == NoColor  )
-                flush( mpDebugStats->batchColorStateFlush );
-        }
+    else if ( mTriangleCount > 0 && mColorCount == 0 )
+	{
+		// We have a batch entry without explicit color definition.  This can happen via the other
+		// render methods which do not require color definition.  If so, we have to flush the batch to
+		// prepare for the current run.
+		flush( mpDebugStats->batchColorStateFlush );
     }
     }
 
 
     // Strict order mode?
     // Strict order mode?
@@ -171,28 +160,19 @@ void BatchRender::SubmitTriangles(
         findTextureBatch( texture )->push_back( TriangleRun( TriangleRun::TRIANGLE, triangleCount, mVertexCount ) );
         findTextureBatch( texture )->push_back( TriangleRun( TriangleRun::TRIANGLE, triangleCount, mVertexCount ) );
     }
     }
 
 
-    // Is a color specified?
-    if ( color != NoColor )
-    {
-        // Yes, so add colors.
-        for( U32 n = 0; n < triangleCount; ++n )
-        {
-            mColorBuffer[mColorCount++] = color;
-            mColorBuffer[mColorCount++] = color;
-            mColorBuffer[mColorCount++] = color;
-        }
-    }
-
-    // Add textured vertices.
+    // Load vertex info into batch buffers
     for( U32 n = 0; n < triangleCount; ++n )
     for( U32 n = 0; n < triangleCount; ++n )
     {
     {
-        mVertexBuffer[mVertexCount++]   = *(pVertexArray++);
-        mVertexBuffer[mVertexCount++]   = *(pVertexArray++);
-        mVertexBuffer[mVertexCount++]   = *(pVertexArray++);
+		mColorBuffer[mColorCount++] = *(pColorArray++);
+		mColorBuffer[mColorCount++] = *(pColorArray++);
+		mColorBuffer[mColorCount++] = *(pColorArray++);
+		mVertexBuffer[mVertexCount++] = *(pVertexArray++);
+		mVertexBuffer[mVertexCount++] = *(pVertexArray++);
+		mVertexBuffer[mVertexCount++] = *(pVertexArray++);
+		mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
         mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
         mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
         mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
         mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
-        mTextureBuffer[mTextureCoordCount++] = *(pTextureArray++);
-    }
+	}
 
 
     // Stats.
     // Stats.
     mpDebugStats->batchTrianglesSubmitted += triangleCount;
     mpDebugStats->batchTrianglesSubmitted += triangleCount;

+ 9 - 7
engine/source/2d/core/BatchRender.h

@@ -44,7 +44,7 @@
 #endif
 #endif
 
 
 #ifndef _COLOR_H_
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 #endif
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
@@ -116,6 +116,8 @@ public:
     BatchRender();
     BatchRender();
     virtual ~BatchRender();
     virtual ~BatchRender();
 
 
+	static const U32 maxVertexCount = BATCHRENDER_BUFFERSIZE; 
+
     /// Set the strict order mode.
     /// Set the strict order mode.
     inline void setStrictOrderMode( const bool strictOrder, const bool forceFlush = false )
     inline void setStrictOrderMode( const bool strictOrder, const bool forceFlush = false )
     {
     {
@@ -225,12 +227,12 @@ public:
     ///   |\      |\
     ///   |\      |\
     ///   | \     | \
     ///   | \     | \
     ///  0| _\1  3| _\4
     ///  0| _\1  3| _\4
-    void SubmitTriangles(
-            const U32 vertexCount,
-            const Vector2* pVertexArray,
-            const Vector2* pTextureArray,
-            TextureHandle& texture,
-            const ColorF& color = ColorF(-1.0f, -1.0f, -1.0f) );
+	void SubmitTriangles(
+		const U32 vertexCount,
+		const Vector2* pVertexArray,
+		const Vector2* pTextureArray,
+		const ColorF*  pColorArray,
+		TextureHandle& texture);
 
 
     /// Submit a quad for batching.
     /// Submit a quad for batching.
     /// Vertex and textures are indexed as:
     /// Vertex and textures are indexed as:

+ 10 - 0
engine/source/2d/core/CoreMath.h

@@ -170,6 +170,16 @@ bool mPointInRectangle( const Vector2& point, const Vector2& rectMin, const Vect
 /// Calculate line/rectangle intersection.
 /// Calculate line/rectangle intersection.
 bool mLineRectangleIntersect( const Vector2& startPoint, const Vector2& endPoint, const Vector2& rectMin, const Vector2& rectMax, F32* pTime = NULL );
 bool mLineRectangleIntersect( const Vector2& startPoint, const Vector2& endPoint, const Vector2& rectMin, const Vector2& rectMax, F32* pTime = NULL );
 
 
+/// Transform the incoming point 'v' by rotating it about the point (and by the amount) specified in the transform 'T'.
+/// NOTE: b2Math has a method called b2Mul() that is similar, but doesn't take into account the offset in T. So I made this.
+inline b2Vec2 mRotateAboutArbitraryPoint(const b2Transform& T, const b2Vec2& v)
+{
+	float32 x = (T.q.c * (v.x - T.p.x) - T.q.s * (v.y - T.p.y)) + T.p.x;
+	float32 y = (T.q.s * (v.x - T.p.x) + T.q.c * (v.y - T.p.y)) + T.p.y;
+
+	return b2Vec2(x, y);
+}
+
 } // Namespace CoreMath.
 } // Namespace CoreMath.
 
 
 #endif // _CORE_UTILITY_H_
 #endif // _CORE_UTILITY_H_

+ 83 - 30
engine/source/2d/core/ImageFrameProviderCore.cc

@@ -218,43 +218,96 @@ const ImageAsset::FrameArea& ImageFrameProviderCore::getProviderImageFrameArea(
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
 void ImageFrameProviderCore::render(
 void ImageFrameProviderCore::render(
-    const bool flipX,
-    const bool flipY,
-    const Vector2& vertexPos0,
-    const Vector2& vertexPos1,
-    const Vector2& vertexPos2,
-    const Vector2& vertexPos3,
-    BatchRender* pBatchRenderer ) const
+	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;
+	// 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());
+}
 
 
-    // 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::render(
+	const bool flipX,
+	const bool flipY,
+	const Vector2& vertexPos0,
+	const Vector2& vertexPos1,
+	const Vector2& vertexPos2,
+	const Vector2& vertexPos3,
+	const Vector2& uvPos0,
+	const Vector2& uvPos1,
+	const Vector2& uvPos2,
+	const Vector2& uvPos3,
+	BatchRender* pBatchRenderer) const
+{
+	// Finish if we can't render.
+	if (!validRender())
+		return;
+
+	// Submit batched quad.
+	pBatchRenderer->SubmitQuad(
+		vertexPos0,
+		vertexPos1,
+		vertexPos2,
+		vertexPos3,
+		uvPos0,
+		uvPos1,
+		uvPos2,
+		uvPos3,
+		getProviderTexture());
 }
 }
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
+void ImageFrameProviderCore::render(
+		const U32 vertexCount,
+		const Vector2 *vertexArray,
+		const Vector2 *textureArray,
+		const ColorF *colorArray,
+		BatchRender* pBatchRenderer) const
+{
+	// Finish if we can't render.
+	if (!validRender() || !vertexCount)
+		return;
+
+	// Submit mesh list
+	pBatchRenderer->SubmitTriangles(
+		vertexCount,
+		vertexArray,
+		textureArray,
+		colorArray,
+		getProviderTexture());
+}
+
+//------------------------------------------------------------------------------
 void ImageFrameProviderCore::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
 void ImageFrameProviderCore::renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const
 {
 {
     // Validate frame provider.
     // Validate frame provider.

+ 24 - 2
engine/source/2d/core/ImageFrameProviderCore.h

@@ -110,7 +110,29 @@ public:
         const Vector2& vertexPos3,
         const Vector2& vertexPos3,
         BatchRender* pBatchRenderer ) const;
         BatchRender* pBatchRenderer ) const;
 
 
-    void renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const;
+	// Use uv coordinates explicitly given.
+	virtual void render(
+		const bool flipX,
+		const bool flipY,
+		const Vector2& vertexPos0,
+		const Vector2& vertexPos1,
+		const Vector2& vertexPos2,
+		const Vector2& vertexPos3,
+		const Vector2& uvPos0,
+		const Vector2& uvPos1,
+		const Vector2& uvPos2,
+		const Vector2& uvPos3,
+		BatchRender* pBatchRenderer) const;
+
+	// Render the given list of vertex information directly.
+	void ImageFrameProviderCore::render(
+		const U32 vertexCount,
+		const Vector2 *vertexArray,
+		const Vector2 *textureArray,
+		const ColorF *colorArray,
+		BatchRender* pBatchRenderer) const;
+
+	void renderGui( GuiControl& owner, Point2I offset, const RectI &updateRect ) const;
 
 
     /// Static-Image Frame.
     /// Static-Image Frame.
     inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
     inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
@@ -121,7 +143,7 @@ public:
     inline U32 getImageFrame( void ) const { return mImageFrame; }
     inline U32 getImageFrame( void ) const { return mImageFrame; }
     virtual bool setNamedImageFrame( const char* frame );
     virtual bool setNamedImageFrame( const char* frame );
     inline StringTableEntry getNamedImageFrame( void ) const { return mNamedImageFrame; }
     inline StringTableEntry getNamedImageFrame( void ) const { return mNamedImageFrame; }
-
+	
     /// Animated-Image Frame.
     /// Animated-Image Frame.
     virtual bool setAnimation( const char* pAnimationAssetId );
     virtual bool setAnimation( const char* pAnimationAssetId );
     inline StringTableEntry getAnimation( void ) const { return mpAnimationAsset->getAssetId(); }
     inline StringTableEntry getAnimation( void ) const { return mpAnimationAsset->getAssetId(); }

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

@@ -67,6 +67,11 @@ public:
         F32                     mRandomMotion;
         F32                     mRandomMotion;
         ColorF                  mColor;    
         ColorF                  mColor;    
 
 
+        /// Physics particles
+        bool                    mPhysicsParticles;
+        b2ParticleGroupDef      mParticleGroup;
+        b2ParticleSystem*       mParticleSystem;
+
         /// Interpolated Tick Position.
         /// Interpolated Tick Position.
         Vector2                 mPreTickPosition;
         Vector2                 mPreTickPosition;
         Vector2                 mPostTickPosition;
         Vector2                 mPostTickPosition;

+ 32 - 24
engine/source/2d/core/SpriteBatch.cc

@@ -54,7 +54,9 @@ SpriteBatch::SpriteBatch() :
     mBatchTransformId = 0;
     mBatchTransformId = 0;
 
 
     // Reset local extents.
     // Reset local extents.
-    mLocalExtents.SetZero();
+	mLocalAABB.lowerBound.SetZero();
+	mLocalAABB.upperBound.SetZero();
+	mLocalExtents.SetZero();
     mLocalExtentsDirty = true;
     mLocalExtentsDirty = true;
 }
 }
 
 
@@ -96,9 +98,6 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
     // Set the sort mode.
     // Set the sort mode.
     pSceneRenderQueue->setSortMode( getBatchSortMode() );
     pSceneRenderQueue->setSortMode( getBatchSortMode() );
 
 
-    // Calculate local AABB.
-    const b2AABB localAABB = calculateLocalAABB( pSceneRenderState->mRenderAABB );
-
     // Do we have a sprite batch query?
     // Do we have a sprite batch query?
     if ( mpSpriteBatchQuery != NULL )
     if ( mpSpriteBatchQuery != NULL )
     {
     {
@@ -108,8 +107,11 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
         // Yes, so fetch sprite batch query and clear results.
         // Yes, so fetch sprite batch query and clear results.
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
         SpriteBatchQuery* pSpriteBatchQuery = getSpriteBatchQuery( true );
 
 
-        // Perform query.
-        pSpriteBatchQuery->queryArea( localAABB, false );
+		// Calculate local AABB.
+		const b2AABB localAABB = calculateLocalAABB(pSceneRenderState->mRenderAABB);
+
+		// Perform query.
+		pSpriteBatchQuery->queryArea( localAABB, false );
 
 
         // Debug Profiling.
         // Debug Profiling.
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
         PROFILE_END(); // SpriteBatch_PrepareRenderQuery
@@ -1262,12 +1264,22 @@ void SpriteBatch::setBatchTransform( const b2Transform& batchTransform )
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-void SpriteBatch::updateLocalExtents( void )
+void SpriteBatch::updateLocalExtents(const b2AABB *precalculatedLocalAABB)
 {
 {
     // Debug Profiling.
     // Debug Profiling.
     PROFILE_SCOPE(SpriteBatch_UpdateLocalExtents);
     PROFILE_SCOPE(SpriteBatch_UpdateLocalExtents);
 
 
-    // Finish if the local extents are not dirty.
+	if (precalculatedLocalAABB && precalculatedLocalAABB->IsValid()) {
+		// We are being given our AABB.  Nothing further is needed.
+		mLocalAABB = *precalculatedLocalAABB;
+		mLocalExtents = mLocalAABB.upperBound - mLocalAABB.lowerBound;
+
+		mLocalExtentsDirty = false;
+
+		return;
+	}
+
+	// Finish if the local extents are not dirty.
     if ( !mLocalExtentsDirty )
     if ( !mLocalExtentsDirty )
         return;
         return;
 
 
@@ -1287,26 +1299,22 @@ void SpriteBatch::updateLocalExtents( void )
     typeSpriteBatchHash::iterator spriteItr = mSprites.begin();
     typeSpriteBatchHash::iterator spriteItr = mSprites.begin();
 
 
     // Set render AABB to this sprite.
     // Set render AABB to this sprite.
-    b2AABB localAABB = spriteItr->value->getLocalAABB();
+    mLocalAABB = spriteItr->value->getLocalAABB();
 
 
-    // Combine with the rest of the sprites.
+	// Combine with the rest of the sprites.
     for( ; spriteItr != mSprites.end(); ++spriteItr )
     for( ; spriteItr != mSprites.end(); ++spriteItr )
     {
     {
-        localAABB.Combine( spriteItr->value->getLocalAABB() );
+		mLocalAABB.Combine( spriteItr->value->getLocalAABB() );
     }
     }
-
-    // Fetch local render extents.
-    const b2Vec2& localLowerExtent = localAABB.lowerBound;
-    const b2Vec2& localUpperExtent = localAABB.upperBound;
-
-    // Calculate maximum extents.
-    const F32 lowerExtentX = mFabs(localLowerExtent.x);
-    const F32 lowerExtentY = mFabs(localLowerExtent.y);
-    const F32 upperExtentX = mFabs(localUpperExtent.x);
-    const F32 upperExtentY = mFabs(localUpperExtent.y);
-
-    // Calculate local extents.
-    mLocalExtents.Set( mFabs(lowerExtentX > upperExtentX ? lowerExtentX : upperExtentX) * 2.0f, mFabs(lowerExtentY > upperExtentY ? lowerExtentY : upperExtentY) * 2.0f );
+	
+	float xSize = mLocalAABB.upperBound.x > mLocalAABB.lowerBound.x
+		? mLocalAABB.upperBound.x - mLocalAABB.lowerBound.x
+		: mLocalAABB.lowerBound.x - mLocalAABB.upperBound.x;
+	float ySize = mLocalAABB.upperBound.y > mLocalAABB.lowerBound.y
+		? mLocalAABB.upperBound.y - mLocalAABB.lowerBound.y
+		: mLocalAABB.lowerBound.y - mLocalAABB.upperBound.y;
+
+	mLocalExtents.Set(xSize, ySize);
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------

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

@@ -65,6 +65,7 @@ private:
     bool                            mBatchTransformDirty;
     bool                            mBatchTransformDirty;
     U32                             mBatchTransformId;
     U32                             mBatchTransformId;
 
 
+	b2AABB							mLocalAABB;
     Vector2                         mLocalExtents;
     Vector2                         mLocalExtents;
     bool                            mLocalExtentsDirty;
     bool                            mLocalExtentsDirty;
 
 
@@ -86,6 +87,7 @@ public:
     inline void setLocalExtentsDirty( void ) { mLocalExtentsDirty = true; }
     inline void setLocalExtentsDirty( void ) { mLocalExtentsDirty = true; }
     inline bool getLocalExtentsDirty( void ) const { return mLocalExtentsDirty; }
     inline bool getLocalExtentsDirty( void ) const { return mLocalExtentsDirty; }
     inline const Vector2& getLocalExtents( void ) { if ( getLocalExtentsDirty() ) updateLocalExtents(); return mLocalExtents; }
     inline const Vector2& getLocalExtents( void ) { if ( getLocalExtentsDirty() ) updateLocalExtents(); return mLocalExtents; }
+	inline const b2AABB& getLocalAABB(void) { if (getLocalExtentsDirty()) updateLocalExtents(); return mLocalAABB; }
 
 
     void createQueryProxy( SpriteBatchItem* pSpriteBatchItem );
     void createQueryProxy( SpriteBatchItem* pSpriteBatchItem );
     void destroyQueryProxy( SpriteBatchItem* pSpriteBatchItem );
     void destroyQueryProxy( SpriteBatchItem* pSpriteBatchItem );
@@ -201,7 +203,7 @@ protected:
     void integrateSprites(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats);
     void integrateSprites(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats);
 
 
     void setBatchTransform( const b2Transform& batchTransform );
     void setBatchTransform( const b2Transform& batchTransform );
-    void updateLocalExtents( void );
+    void updateLocalExtents(const b2AABB *precalculatedLocalAABB = NULL);
 
 
     void createSpriteBatchQuery( void );
     void createSpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );

+ 64 - 23
engine/source/2d/core/SpriteBatchItem.cc

@@ -97,6 +97,7 @@ void SpriteBatchItem::resetState( void )
 
 
     mVisible = true;
     mVisible = true;
     mExplicitMode = false;
     mExplicitMode = false;
+	mTriangleRun = false;
 
 
     mLocalPosition.SetZero();
     mLocalPosition.SetZero();
     for (U32 i = 0; i < 4; i++)
     for (U32 i = 0; i < 4; i++)
@@ -222,24 +223,64 @@ void SpriteBatchItem::render( BatchRender* pBatchRenderer, const SceneRenderRequ
     pBatchRenderer->setAlphaTestMode( pSceneRenderRequest );
     pBatchRenderer->setAlphaTestMode( pSceneRenderRequest );
 
 
     // Render.
     // Render.
-    Parent::render( mFlipX, mFlipY,
-                    mRenderOOBB[0],
-                    mRenderOOBB[1],
-                    mRenderOOBB[2],
-                    mRenderOOBB[3],
-                    pBatchRenderer );
+	if (mTriangleRun) {
+		Parent::render(
+			mDrawData.vertexCount,
+			mDrawData.vertexArray.data(),
+			mDrawData.textureArray.data(),
+			mDrawData.colorArray.data(),
+			pBatchRenderer
+		);
+	}
+	else if (mExplicitMode) {
+		Parent::render(mFlipX, mFlipY,
+			mRenderOOBB[0],
+			mRenderOOBB[1],
+			mRenderOOBB[2],
+			mRenderOOBB[3],
+			mExplicitUVs[0],
+			mExplicitUVs[1],
+			mExplicitUVs[2],
+			mExplicitUVs[3],
+			pBatchRenderer);
+	}
+	else {
+		Parent::render(mFlipX, mFlipY,
+			mRenderOOBB[0],
+			mRenderOOBB[1],
+			mRenderOOBB[2],
+			mRenderOOBB[3],
+			pBatchRenderer);
+	}
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-void SpriteBatchItem::setExplicitVertices( const Vector2* explicitVertices )
+// When something else (like an animation runtime) is controlling the vertices and uv's
+// just past them through to the render stage.
+void SpriteBatchItem::setExplicitVertices( const F32* vertices, const F32* uvs)
 {
 {
-    mExplicitMode = true;
-
-    mExplicitVerts[0] = explicitVertices[0];
-    mExplicitVerts[1] = explicitVertices[1];
-    mExplicitVerts[2] = explicitVertices[2];
-    mExplicitVerts[3] = explicitVertices[3];
+	mExplicitMode = true;
+
+	mExplicitVerts[0].x = vertices[0];
+	mExplicitVerts[0].y = vertices[1];
+	mExplicitVerts[1].x = vertices[2];
+	mExplicitVerts[1].y = vertices[3];
+	mExplicitVerts[2].x = vertices[4];
+	mExplicitVerts[2].y = vertices[5];
+	mExplicitVerts[3].x = vertices[6];
+	mExplicitVerts[3].y = vertices[7];
+
+	if (uvs) {
+		mExplicitUVs[0].x = uvs[0];
+		mExplicitUVs[0].y = uvs[1];
+		mExplicitUVs[1].x = uvs[2];
+		mExplicitUVs[1].y = uvs[3];
+		mExplicitUVs[2].x = uvs[4];
+		mExplicitUVs[2].y = uvs[5];
+		mExplicitUVs[3].x = uvs[6];
+		mExplicitUVs[3].y = uvs[7];
+	}
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -256,19 +297,19 @@ void SpriteBatchItem::updateLocalTransform( void )
     if ( !mLocalTransformDirty )
     if ( !mLocalTransformDirty )
         return;
         return;
 
 
-    // Set local transform.
-    b2Transform localTransform;
-    localTransform.p = mLocalPosition;
-    localTransform.q.Set( mLocalAngle );
-
-    // Calculate half size.
-    const F32 halfWidth = mSize.x * 0.5f;
-    const F32 halfHeight = mSize.y * 0.5f;
+	// Set local transform.
+	b2Transform localTransform;
+	localTransform.p = mLocalPosition;
+	localTransform.q.Set(mLocalAngle);
 
 
-    // Set local size vertices.
+	// Set local size vertices.
     if (!mExplicitMode)
     if (!mExplicitMode)
     {
     {
-        mLocalOOBB[0].Set( -halfWidth, -halfHeight );
+		// Calculate half size.
+		const F32 halfWidth = mSize.x * 0.5f;
+		const F32 halfHeight = mSize.y * 0.5f;
+
+		mLocalOOBB[0].Set( -halfWidth, -halfHeight );
         mLocalOOBB[1].Set( +halfWidth, -halfHeight );
         mLocalOOBB[1].Set( +halfWidth, -halfHeight );
         mLocalOOBB[2].Set( +halfWidth, +halfHeight );
         mLocalOOBB[2].Set( +halfWidth, +halfHeight );
         mLocalOOBB[3].Set( -halfWidth, +halfHeight );
         mLocalOOBB[3].Set( -halfWidth, +halfHeight );

+ 31 - 4
engine/source/2d/core/SpriteBatchItem.h

@@ -45,7 +45,25 @@ class SpriteBatchItem : public ImageFrameProvider
     typedef ImageFrameProvider Parent;
     typedef ImageFrameProvider Parent;
 
 
 public:
 public:
-    // Represents a logical position.
+	
+	// Holds items required by call to SubmitTriangles.  Currently, this is only used when
+	// mTriangleRun is true due to processing of Spine's mesh attachments.
+	typedef struct
+	{
+		U32 vertexCount;
+		vector<Vector2> vertexArray;
+		vector<Vector2> textureArray;
+		vector<ColorF>  colorArray;
+
+		inline void size(U32 newSize) {
+			vertexCount = newSize;
+			vertexArray.resize(newSize);
+			textureArray.resize(newSize);
+			colorArray.resize(newSize);
+		}
+	} drawData;
+
+	// Represents a logical position.
     struct LogicalPosition : public IFactoryObjectReset
     struct LogicalPosition : public IFactoryObjectReset
     {
     {
         const static S32 MAX_ARGUMENTS = 6;
         const static S32 MAX_ARGUMENTS = 6;
@@ -199,7 +217,12 @@ protected:
 
 
     Vector2             mLocalPosition;
     Vector2             mLocalPosition;
     Vector2             mExplicitVerts[4];
     Vector2             mExplicitVerts[4];
-    F32                 mLocalAngle;
+	Vector2             mExplicitUVs[4];
+
+	bool				mTriangleRun;
+	drawData			mDrawData;
+
+	F32                 mLocalAngle;
     Vector2             mSize;
     Vector2             mSize;
     F32                 mDepth;
     F32                 mDepth;
     bool                mFlipX;
     bool                mFlipX;
@@ -249,10 +272,14 @@ public:
     inline void setExplicitMode( const bool explicitMode ) { mExplicitMode = explicitMode; }
     inline void setExplicitMode( const bool explicitMode ) { mExplicitMode = explicitMode; }
     inline bool getExplicitMode( void ) const { return mExplicitMode; }
     inline bool getExplicitMode( void ) const { return mExplicitMode; }
 
 
-    inline void setLocalPosition( const Vector2& localPosition ) { mLocalPosition = localPosition; mLocalTransformDirty = true; }
+	inline void setTriangleRun(const bool usesTriangles) { mTriangleRun = usesTriangles; }
+	inline bool getTriangleRun(void) const { return mTriangleRun; }
+	inline drawData *getDrawData(void) { return &mDrawData; }
+
+	inline void setLocalPosition( const Vector2& localPosition ) { mLocalPosition = localPosition; mLocalTransformDirty = true; }
     inline Vector2 getLocalPosition( void ) const { return mLocalPosition; }
     inline Vector2 getLocalPosition( void ) const { return mLocalPosition; }
 
 
-    void setExplicitVertices( const Vector2* explicitVertices );
+    void setExplicitVertices( const F32* vertices, const F32* uvs = 0 );
 
 
     inline void setLocalAngle( const F32 localAngle ) { mLocalAngle = localAngle; mLocalTransformDirty = true; }
     inline void setLocalAngle( const F32 localAngle ) { mLocalAngle = localAngle; mLocalTransformDirty = true; }
     inline F32 getLocalAngle( void ) const { return mLocalAngle; }
     inline F32 getLocalAngle( void ) const { return mLocalAngle; }

+ 1 - 1
engine/source/2d/scene/DebugDraw.h

@@ -32,7 +32,7 @@
 #endif
 #endif
 
 
 #ifndef _COLOR_H_
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 #endif
 
 
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------

+ 3 - 0
engine/source/2d/scene/Scene.cc

@@ -222,6 +222,9 @@ bool Scene::onAdd()
     // Set contact filter.
     // Set contact filter.
     mpWorld->SetContactFilter( &mContactFilter );
     mpWorld->SetContactFilter( &mContactFilter );
 
 
+    const b2ParticleSystemDef particleSystemDef;
+    mParticleSystem = mpWorld->CreateParticleSystem(&particleSystemDef);
+
     // Set contact listener.
     // Set contact listener.
     mpWorld->SetContactListener( this );
     mpWorld->SetContactListener( this );
 
 

+ 1 - 1
engine/source/2d/scene/Scene.h

@@ -678,7 +678,7 @@ public:
     static const char* getPickModeDescription( PickMode pickMode );
     static const char* getPickModeDescription( PickMode pickMode );
     static DebugOption getDebugOptionEnum(const char* label);
     static DebugOption getDebugOptionEnum(const char* label);
     static const char* getDebugOptionDescription( DebugOption debugOption );
     static const char* getDebugOptionDescription( DebugOption debugOption );
-
+    b2ParticleSystem*			mParticleSystem;
     /// Declare Console Object.
     /// Declare Console Object.
     DECLARE_CONOBJECT(Scene);
     DECLARE_CONOBJECT(Scene);
 
 

+ 1 - 1
engine/source/2d/scene/SceneRenderRequest.h

@@ -32,7 +32,7 @@
 #endif
 #endif
 
 
 #ifndef _COLOR_H_
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 #endif
 
 
 // Debug Profiling.
 // Debug Profiling.

+ 239 - 0
engine/source/2d/sceneobject/LightObject.cc

@@ -0,0 +1,239 @@
+#include "graphics/dgl.h"
+#include "console/consoleTypes.h"
+#include "2d/core/Utility.h"
+#include "2d/sceneobject/LightObject.h"
+
+// Script bindings.
+#include "LightObject_ScriptBinding.h"
+
+IMPLEMENT_CONOBJECT(LightObject);
+
+LightObject::LightObject():
+   mLightRadius(10.0f),
+   mLightSegments(15)
+{
+   mSrcBlendFactor = GL_SRC_ALPHA;
+   mDstBlendFactor = GL_ONE;
+   // Use a static body by default.
+   mBodyDefinition.type = b2_staticBody;
+}
+
+LightObject::~LightObject()
+{
+
+}
+
+bool LightObject::onAdd()
+{
+   // Call Parent.
+   if (!Parent::onAdd())
+      return false;
+
+   // Return Okay.
+   return true;
+}
+
+//----------------------------------------------------------------------------
+
+void LightObject::onRemove()
+{
+   // Call Parent.
+   Parent::onRemove();
+}
+
+void LightObject::initPersistFields()
+{
+   Parent::initPersistFields();
+
+   /// Light settings.
+   addProtectedField("LightRadius", TypeF32, Offset(mLightRadius, LightObject), &setLightRadius, &defaultProtectedGetFn, &writeLightRadius, "");
+   addProtectedField("LightSegments", TypeS32, Offset(mLightSegments, LightObject), &setLightSegments, &defaultProtectedGetFn, &writeLightSegments, "");
+
+}
+
+void LightObject::safeDelete(void)
+{
+   Parent::safeDelete();
+}
+
+void LightObject::sceneRender(const SceneRenderState * sceneRenderState, const SceneRenderRequest * sceneRenderRequest, BatchRender * batchRender)
+{
+   Vector2 worldPos = getPosition();
+   Vector<Vector2> verts;
+   Vector<RayList> bList;
+   S32 mSrcLightBlend = getSrcBlendFactor();
+   S32 mDstLightBlend = getDstBlendFactor();
+   ColorF mLightColor = getBlendColor();
+
+   F32 radius = getLightRadius();
+   Scene* scene = getScene();
+   b2World* mWorld = scene->getWorld();
+
+
+   
+
+   glEnable(GL_BLEND);
+   glDisable(GL_TEXTURE_2D);
+   glPushMatrix();
+ 
+   glTranslatef(worldPos.x, worldPos.y, 0);
+   glPolygonMode(GL_FRONT, GL_FILL);
+
+   //additive blending
+   //glBlendFunc(GL_ONE,GL_ONE);
+   
+   glBlendFunc(mSrcLightBlend, mDstLightBlend);
+   // Creates the fading dark region.
+   glBegin(GL_TRIANGLE_FAN);
+   glColor4f(mLightColor.red,mLightColor.green,mLightColor.blue,mLightColor.alpha);
+   glVertex2f(0, 0);
+   //check scene objects
+   U32 objCount = scene->getSceneObjectCount();
+   for (U32 i = 0; i < objCount; i++)
+   {
+      SceneObject *tObj = scene->getSceneObject(i);
+      Vector2 dist = worldPos - tObj->getPosition();
+      const F32 distSqr = dist.LengthSquared();
+      const F32 radSqr = radius * radius;
+      //within radius?
+      if (distSqr < radSqr || distSqr == radSqr)
+      {
+         U32 shapeCount = tObj->getCollisionShapeCount();
+         for (U32 j = 0; j < shapeCount; j++)
+         {
+            //All vertices from polygon collision shape
+            if (tObj->getCollisionShapeType(j) == b2Shape::e_polygon)
+            {
+               U32 pCount = tObj->getPolygonCollisionShapePointCount(j);
+
+               for (U32 k = 0; k < pCount; k++)
+               {
+                  Vector2 locPoint = tObj->getPolygonCollisionShapeLocalPoint(j, k);
+                  Vector2 wPoint = tObj->getWorldPoint(locPoint);
+                  verts.push_back(wPoint);
+               }
+            }
+         }
+      }
+   }
+   ///  \ | /
+   /// -  +  -
+   ///  / | \
+
+   U32 lightSeg = getLightSegments();
+   F32 segAng = 360.0f / lightSeg;
+
+   for (U32 i = 0; i <= lightSeg; i++)
+   {
+      b2Vec2 segStrt = worldPos;
+      b2Vec2 segEnd = segStrt + radius * b2Vec2(mCos(mDegToRad((F32)segAng * i)), mSin(mDegToRad((F32)segAng * i)));
+      verts.push_back(segEnd);
+   }
+
+   //cast ray to vertices
+   for (S32 l = 0; l < verts.size(); l++)
+   {
+      F32 rayLength = radius;
+      Vector2 p1 = worldPos;
+      Vector2 p2 = verts[l];
+      F32 baseAng = mAtan(p2.x, p2.y);
+      F32 cAng = 0;
+      for (int m = 0; m < 2; m++)
+      {
+         if (m == 0)cAng = baseAng - 0.0001f;
+         //if (m == 1)cAng = baseAng;
+         if (m == 1)cAng = baseAng + 0.0001f;
+
+         p2.x = rayLength * mCos(cAng);
+         p2.y = rayLength * mSin(cAng);
+
+         RaysCastCallback callback;
+         mWorld->RayCast(&callback, p1, p2);
+         if (callback.m_fixture)
+         {
+
+            F32 ang = mAtan(callback.m_point.x - p1.x, callback.m_point.y - p1.y);
+            Vector2 intersection = p1 + callback.m_fraction * (p2 - p1);
+            
+            RayList intersectionPoint;
+            intersectionPoint.ang = ang;
+            intersectionPoint.x = intersection.x;
+            intersectionPoint.y = intersection.y;
+            intersectionPoint.l = callback.m_fraction;
+
+
+            bList.push_back_unique(intersectionPoint);
+
+         }
+         else
+         {
+            F32 ang = mAtan(p2.x - p1.x, p2.y - p1.y);
+
+            RayList intersectionPoint;
+            intersectionPoint.ang = ang;
+            intersectionPoint.x = p2.x;
+            intersectionPoint.y = p2.y;
+            intersectionPoint.l = 1.0;
+
+            bList.push_back_unique(intersectionPoint);
+         }
+      }
+   }
+
+   //Con::printf("Rays cast: %i", bList.size());
+   //sort the list
+   if (bList.size() > 1)
+   {
+      dQsort(bList.address(), bList.size(), sizeof(RayList), sortRays);
+   }
+
+   
+
+   //triangle fan
+   for (S32 m = 0; m < bList.size(); m++)
+   {
+      glColor4f(mLightColor.red - (mLightColor.red * bList[m].l), mLightColor.green - (mLightColor.green * bList[m].l), mLightColor.blue - (mLightColor.blue * bList[m].l), mLightColor.alpha - (mLightColor.alpha * bList[m].l));
+      glVertex2f(bList[m].x, bList[m].y);
+
+   }
+   //close off the circle
+   glColor4f(mLightColor.red - (mLightColor.red * bList[0].l), mLightColor.green - (mLightColor.green * bList[0].l), mLightColor.blue - (mLightColor.blue * bList[0].l), mLightColor.alpha - (mLightColor.alpha * bList[0].l));
+   glVertex2f(bList[0].x, bList[0].y);
+
+   glDisable(GL_BLEND);
+
+   glEnd();
+
+   glPopMatrix();
+}
+
+void LightObject::OnRegisterScene(Scene* mScene)
+{
+   Parent::OnRegisterScene(mScene);
+   mScene->getWorldQuery()->addAlwaysInScope(this);
+
+}
+
+void LightObject::OnUnregisterScene(Scene* mScene)
+{
+   mScene->getWorldQuery()->removeAlwaysInScope(this);
+   Parent::OnUnregisterScene(mScene);
+}
+
+S32 QSORT_CALLBACK sortRays(const void* a, const void* b)
+{
+   RayList* ray_a = (RayList*) a;
+   RayList* ray_b = (RayList*) b;
+
+   if (ray_a->ang < ray_b->ang)
+   {
+      return -1;
+   }
+   else if (ray_a->ang > ray_b->ang)
+   {
+      return 1;
+   }
+  
+   return 0;
+
+}

+ 96 - 0
engine/source/2d/sceneobject/LightObject.h

@@ -0,0 +1,96 @@
+#ifndef _LIGHTOBJECT_H_
+#define _LIGHTOBJECT_H_
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+class RayList
+{
+public:
+
+   F32 x;
+   F32 y;
+   F32 l;
+   F32 ang;
+   bool operator == (const RayList& t) const { return ((mFabs(t.x - x) < 0.01) && (mFabs(t.y - y) < 0.01)); }
+
+};
+
+class RaysCastCallback : public b2RayCastCallback
+{
+public:
+
+   RaysCastCallback() : m_fixture(NULL) {}
+
+   float32 ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction) {
+      m_fixture = fixture;
+      m_point = point;
+      m_normal = normal;
+      m_fraction = fraction;
+      return fraction;
+   }
+
+   b2Fixture* m_fixture;
+   b2Vec2 m_point;
+   b2Vec2 m_normal;
+   float32 m_fraction;
+
+};
+
+class LightObject : public SceneObject
+
+{
+   typedef SceneObject Parent;
+
+protected:
+
+   F32                     mLightRadius;
+   U32                     mLightSegments;
+
+public:
+
+   LightObject();
+   ~LightObject();
+
+   static void initPersistFields();
+
+   
+
+   virtual bool onAdd();
+   virtual void onRemove();
+
+   virtual void safeDelete(void);
+   virtual void sceneRender(const SceneRenderState* sceneRenderState, const SceneRenderRequest* sceneRenderRequest, BatchRender* batchRender);
+   //virtual bool validRender(void) const {}
+   virtual bool shouldRender(void) const { return true; }
+
+   /// Light segments.
+   inline void setLightSegments(const U32 lightSegments) { mLightSegments = lightSegments; };
+   inline U32 getLightSegments(void) const { return mLightSegments; }
+
+   /// Light Radius.
+   inline void setLightRadius(const F32 lightRadius) { mLightRadius = lightRadius; }
+   inline F32 getLightRadius(void) const { return mLightRadius; }
+
+   DECLARE_CONOBJECT(LightObject);
+
+
+protected:
+
+   virtual void OnRegisterScene(Scene* mScene);
+   virtual void OnUnregisterScene(Scene* mScene);
+
+protected:
+
+   static bool setLightRadius(void* obj, const char* data) { static_cast<LightObject*>(obj)->setLightRadius(dAtof(data)); return false; }
+   static bool writeLightRadius(void* obj, StringTableEntry pFieldName) { return static_cast<LightObject*>(obj)->getLightRadius() > 0.0f; }
+
+   static bool setLightSegments(void* obj, const char* data) { static_cast<LightObject*>(obj)->setLightSegments(dAtoi(data)); return false; }
+   static bool writeLightSegments(void* obj, StringTableEntry pFieldName) { return static_cast<LightObject*>(obj)->getLightSegments() > 0; }
+
+};
+
+#endif //_LIGHTOBJECT_H_
+
+S32 QSORT_CALLBACK sortRays(const void * a, const void * b);

+ 52 - 0
engine/source/2d/sceneobject/LightObject_ScriptBinding.h

@@ -0,0 +1,52 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+ConsoleMethodGroupBeginWithDocs(LightObject, SceneObject)
+
+/*! Add the object to a scene.
+    @param scene the scene you wish to add this object to.
+    @return No return value.
+*/
+
+ConsoleMethodWithDocs(LightObject, setLightRadius, ConsoleVoid, 3, 3, (float radius))
+{
+   // Set Lifetime.
+   object->setLightRadius(dAtof(argv[2]));
+}
+
+ConsoleMethodWithDocs(LightObject, getLightRadius, ConsoleFloat, 2, 2, ())
+{
+   // Return Lifetime.
+   return object->getLightRadius();
+}
+
+
+ConsoleMethodWithDocs(LightObject, setLightSegments, ConsoleVoid, 3, 3, (integer lightSegments))
+{
+   // Set Layer.
+   object->setLightSegments(dAtoi(argv[2]));
+}
+
+ConsoleMethodWithDocs(LightObject, getLightSegments, ConsoleInt, 2, 2, ())
+{
+   // Return Layer.
+   return object->getLightSegments();
+}

+ 16 - 4
engine/source/2d/sceneobject/ParticlePlayer.cc

@@ -1147,11 +1147,23 @@ void ParticlePlayer::configureParticle( EmitterNode* pEmitterNode, ParticleSyste
                                                                 pParticleAssetEmitter->getEmissionForceVariationField(),
                                                                 pParticleAssetEmitter->getEmissionForceVariationField(),
                                                                 particlePlayerAge) * getForceScale();
                                                                 particlePlayerAge) * getForceScale();
 
 
-        // Calculate Emission Angle.
-        emissionAngle = ParticleAssetField::calculateFieldBV(   pParticleAssetEmitter->getEmissionAngleBaseField(),
-                                                                pParticleAssetEmitter->getEmissionAngleVariationField(),
-                                                                particlePlayerAge );
+        if (pParticleAssetEmitter->getIsTargeting())
+        {
+           Vector2 tPos = pParticleAssetEmitter->getTargetPosition();
+           Vector2 pPos = pParticleNode->mPosition;
+           Vector2 subVec = tPos - pPos;
+           F32 vecN = mAtan(subVec.x, subVec.y);
+           F32 vecDeg = mRadToDeg(vecN);
+           emissionAngle = vecDeg;
+        }
+        else
+        {
 
 
+           // Calculate Emission Angle.
+           emissionAngle = ParticleAssetField::calculateFieldBV(  pParticleAssetEmitter->getEmissionAngleBaseField(),
+                                                                  pParticleAssetEmitter->getEmissionAngleVariationField(),
+                                                                  particlePlayerAge);
+        }
         // Calculate Emission Arc.
         // Calculate Emission Arc.
         // NOTE:-   We're actually interested in half the emission arc!
         // NOTE:-   We're actually interested in half the emission arc!
         emissionArc = ParticleAssetField::calculateFieldBV( pParticleAssetEmitter->getEmissionArcBaseField(),
         emissionArc = ParticleAssetField::calculateFieldBV( pParticleAssetEmitter->getEmissionArcBaseField(),

+ 285 - 0
engine/source/2d/sceneobject/Path.cc

@@ -0,0 +1,285 @@
+#include "graphics/dgl.h"
+#include "2d/sceneobject/Path.h"
+
+#include "2d/sceneobject/Path_ScriptBinding.h"
+
+IMPLEMENT_CONOBJECT(Path);
+
+PathObject::PathObject():
+   mObj(NULL),
+   mPath(NULL)
+{
+   mCurrNode = 0;
+   mPrevNode = 0;
+
+   mMaxSpeed = 1.0f;
+   mMaxForce = 3.0f;
+   mOrient = false;
+   mAngOff = 0.0f;
+   mSnapToNode = false;
+   mLoop = true;
+   mMaxLoop = -1;
+   mLoopCount = 0;
+}
+
+void PathObject::setCurrNode(S32 node)
+{
+}
+
+void PathObject::setNextNode(S32 node)
+{
+}
+
+void PathObject::setPrevNode(S32 node)
+{
+}
+
+
+Path::Path()
+{
+
+   // Use a static body by default.
+   mBodyDefinition.type = b2_staticBody;
+
+   VECTOR_SET_ASSOCIATION(mObjs);
+   VECTOR_SET_ASSOCIATION(mNodes);
+}
+
+Path::~Path()
+{
+
+}
+
+void Path::initPersistFields()
+{
+   Parent::initPersistFields();
+}
+
+void Path::preIntegrate(const F32 totalTime, const F32 elapsedTime, DebugStats * pDebugStats)
+{
+   Parent::preIntegrate(totalTime, elapsedTime, pDebugStats);
+
+   Vector<PathObject*>::iterator i;
+   for (i = mObjs.begin(); i != mObjs.end(); i++)
+   {
+      bool stop = false;
+      PathObject &pObj = *(*i);
+
+      Vector2 cPos = pObj.mObj->getPosition();
+      Node &cNode = mNodes[pObj.mCurrNode];
+      Vector2 cDst = mNodes[pObj.mCurrNode].position;
+      F32 distance = (cDst - cPos).Length();
+
+      if (distance < (pObj.mMaxSpeed * elapsedTime) || distance < cNode.distance )
+      {
+         S32 nCount = mNodes.size();
+         S32 end = nCount - 1;
+         if (pObj.mCurrNode == end)
+         {
+            if (pObj.mLoop)
+            {
+               pObj.mLoopCount++;
+               if ((pObj.mMaxLoop > 0) && (pObj.mLoopCount >= pObj.mMaxLoop))
+               {
+                  stop = true;
+               }
+               else
+               {
+                  pObj.mPrevNode = pObj.mCurrNode;
+                  pObj.mCurrNode = 0;
+                  pObj.mNextNode = pObj.mCurrNode;
+               }
+            }
+            else
+            {
+               stop = true;
+            }
+         }
+         else
+         {
+            pObj.mPrevNode = pObj.mCurrNode;
+            pObj.mCurrNode = pObj.mCurrNode + 1;
+            pObj.mNextNode = pObj.mCurrNode;
+         }
+
+         if (pObj.mCurrNode >= nCount)
+         {
+            pObj.mCurrNode = 0;
+            pObj.mNextNode = pObj.mCurrNode;
+         }
+         else if (pObj.mCurrNode < 0)
+         {
+            pObj.mCurrNode = 0;
+            pObj.mNextNode = pObj.mCurrNode;
+         }
+
+      }
+
+      if (!stop)
+      {
+         moveObject(pObj);
+      }
+
+      else
+      {
+         pObj.mObj->setLinearVelocity(Vector2(0.0f, 0.0f));
+      }
+
+   }
+
+}
+
+void Path::integrateObject(const F32 totalTime, const F32 elapsedTime, DebugStats * pDebugStats)
+{
+   Parent::integrateObject(totalTime, elapsedTime, pDebugStats);
+}
+
+S32 Path::addNode(Vector2 pos, F32 distance, F32 weight)
+{
+   S32 nodeCount = mNodes.size();
+
+   mNodes.push_back(Node(pos, distance, weight));
+
+   return nodeCount;
+}
+
+void Path::attachObject(SceneObject * object, F32 speed, F32 force, bool orientToPath, F32 angleOff, bool snapToNode, S32 startNode, bool loop, S32 maxLoop)
+{
+   if (snapToNode)
+   {
+      if ((startNode >= 0) && (startNode < mNodes.size()))
+         object->setPosition(mNodes[startNode].position);
+   }
+
+   object->setLinearVelocity(Vector2::getZero());
+
+   deleteNotify(object);
+
+   PathObject *pObj  = new PathObject();
+   pObj->mPath       = this;
+   pObj->mObj        = object;
+   pObj->mMaxForce   = force;
+   pObj->mObjId      = object->getId();
+   pObj->mOrient     = orientToPath;
+   pObj->mAngOff     = angleOff;
+   pObj->mLoop       = loop;
+   pObj->mMaxLoop    = maxLoop;
+   pObj->mMaxSpeed   = speed;
+   pObj->mCurrNode   = startNode;
+   pObj->mNextNode   = startNode;
+   
+
+   mObjs.push_back(pObj);
+}
+
+void Path::detachObject(SceneObject * object)
+{
+   if (!object)
+      return;
+
+   Vector<PathObject*>::iterator i;
+
+   for (i = mObjs.begin(); i != mObjs.end(); i++)
+   {
+      PathObject *pObj = (*i);
+      if(object == pObj->mObj)
+      {
+         if (!pObj->mObj.isNull())
+         {
+            pObj->mObj->setLinearVelocity(Vector2(0, 0));
+            clearNotify(pObj->mObj);
+         }
+
+         delete pObj;
+
+         mObjs.erase_fast(i);
+         
+         break;
+      }
+   }
+}
+
+void Path::moveObject(PathObject& obj)
+{
+   Vector2 cDest = mNodes[obj.mNextNode].position;
+   F32 slowRad = mNodes[obj.mNextNode].distance;
+   Vector2 oPos = obj.mObj->getPosition();
+   Vector2 dir = cDest - oPos;
+   Vector2 currVel = obj.mObj->getLinearVelocity();
+   dir.Normalize();
+
+   F32 maxSpeed = obj.mMaxSpeed;
+   F32 maxForce = obj.mMaxForce;
+
+   Vector2 steer = seek(cDest, oPos, maxSpeed, currVel, slowRad);
+   steer = truncate(steer, maxForce);
+   steer = steer.scale(0.5f);
+   currVel = currVel.add(steer);
+   currVel = truncate(currVel.add(steer), maxSpeed);
+   Vector2 pos = oPos.add(currVel);
+
+   //Steering Behavior
+   obj.mObj->applyForce(pos, obj.mObj->getWorldCenter());
+
+   //Simple direct move.
+   //obj.mObj->setLinearVelocity(dir * obj.mMaxSpeed);
+
+   if (obj.mOrient)
+   {
+      F32 rot = mRadToDeg(mAtan(dir.x, dir.y));
+      rot = rot - obj.mAngOff;
+      F32 ang = mDegToRad(rot);
+      F32 speed = obj.mMaxSpeed;
+      obj.mObj->rotateTo(ang, speed);
+   }
+
+}
+
+Vector2 Path::truncate(Vector2 vec, F32 max)
+{
+   F32 i = max;
+   i = i < 1.0f ? 1.0f : i;
+   vec = vec.scale(max);
+   return vec;
+}
+
+Vector2 Path::seek(Vector2 target, Vector2 objPos, F32 max, Vector2 curr, F32 slowRad)
+{
+   Vector2 des = target.sub(objPos);
+   F32 dist = des.Length();
+   des.Normalize();
+
+   if (dist < slowRad)
+   {
+      des = des.scale(max * dist / slowRad);
+   }
+   else
+   {
+      des = des.scale(max);
+   }
+
+   Vector2 force = des.sub(curr);
+
+   return force;
+}
+
+
+
+void Path::onDeleteNotify(SimObject* object)
+{
+   Vector<PathObject*>::iterator i;
+
+   SimObjectId objId = object->getId();
+
+   for (i = mObjs.begin(); i != mObjs.end(); i++)
+   {
+      if ((*i)->mObjId == objId)
+      {
+         delete (*i);
+
+         mObjs.erase_fast(i);
+
+         break;
+      }
+   }
+}

+ 113 - 0
engine/source/2d/sceneobject/Path.h

@@ -0,0 +1,113 @@
+#ifndef _PATH_H_
+#define _PATH_H_
+
+#include "2d/sceneobject/SceneObject.h"
+
+class Path;
+
+class PathObject
+{
+private:
+   friend class Path;
+   void setCurrNode(S32 node);
+   void setNextNode(S32 node);
+   void setPrevNode(S32 node);
+
+   Path* mPath;
+   SimObjectPtr<SceneObject> mObj;
+   SimObjectId mObjId;
+   F32 mMaxSpeed;
+   bool mOrient;
+   F32 mMaxForce;
+   F32 mAngOff;
+   
+   S32 mCurrNode;
+   S32 mPrevNode;
+   S32 mNextNode;
+   bool mLoop; 
+   
+   bool mSnapToNode;
+   S32 mLoopCount;
+   S32 mMaxLoop;
+
+public:
+   PathObject();
+   ~PathObject() {};
+
+};
+
+class Path : public SceneObject
+{
+   typedef SceneObject Parent;
+
+public:
+   struct Node
+   {
+      Node(Vector2 pos, F32 dst, F32 wght)
+      {
+         position = pos;
+         distance = dst;
+         weight = wght;
+      };
+
+      Vector2 position;
+      F32 distance;
+      F32 weight;
+   };
+
+   Path();
+   ~Path();
+   virtual void onDeleteNotify(SimObject* object);
+   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);
+
+   S32 addNode(Vector2 pos, F32 distance, F32 weight);
+
+   S32 getNodeCount() const { return mNodes.size(); }
+
+   inline Node& getNode(S32 index)
+   {
+      if (isValidNode(index)) return mNodes[index];
+      return mNodes[0];
+   }
+
+   inline bool isValidNode(S32 index)
+   {
+      if (mNodes.empty()) return false;
+      if((index >= 0) && (index < mNodes.size())) return true;
+   }
+
+   void attachObject(SceneObject* object, F32 speed, F32 force, bool orientToPath, F32 angleOff, bool snapToNode, S32 startNode, bool loop, S32 maxLoop);
+
+   void detachObject(SceneObject* object);
+
+   S32 getAttachedObjectCount() { return mObjs.size(); }
+
+   SceneObject* getPathObject(U32 index) { if (index < mObjs.size()) return mObjs[index]->mObj; return NULL; }
+   
+   inline PathObject* getAttachedObject(const SceneObject* obj)
+   {
+      if (obj == NULL)
+         return NULL;
+
+      Vector<PathObject*>::iterator i;
+      for (i = mObjs.begin(); i != mObjs.end(); i++)
+         if ((*i)->mObj == obj) return *i;
+   }
+
+   DECLARE_CONOBJECT(Path);
+
+private:
+
+   void moveObject(PathObject& obj);
+   Vector2 truncate(Vector2 vec, F32 max);
+   Vector2 seek(Vector2 target, Vector2 objPos, F32 max, Vector2 curr, F32 slowRad);
+
+   Vector<PathObject*> mObjs;
+   Vector<Node> mNodes;
+
+};
+
+#endif

+ 134 - 0
engine/source/2d/sceneobject/Path_ScriptBinding.h

@@ -0,0 +1,134 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+/*! Attaches a sceneObject to the path.
+@param SceneObject The object that will be attached to the path.
+@param speed The rate that the sceneObject will follow the path.
+@param orient If true, the object will automatically rate to face the direction that it is moving.
+@param angOff The offset that will be applied to the rotation if orient is true.
+@param snapToNode If true, the object will have to get close to a node instead of reaching it exactly. The distance is based on the distance given a node when it is created.
+@param startNode A zero-based integer that represents the node that the object should start at.
+@param loop If true, the object will start the path again when it reaches the last node. The object will travel from the last node to the first.
+@param maxLoop An integer value describing the number of times the object will travel the path if looping is turned on.
+@return No return value.
+*/
+ConsoleMethodWithDocs(Path, attachObject, ConsoleVoid, 4, 11, (sceneObject, float speed,[float force], [bool orient], [float angOff], [bool snapToNode],[integer startNode],[bool loop],[integer maxLoop]))
+{
+   // Set Group.
+   SceneObject* pSceneObject = dynamic_cast<SceneObject*>(Sim::findObject(argv[2]));
+   // Did we find the object?
+   if (!pSceneObject)
+   {
+      // No, so warn.
+      Con::warnf("Path::attachObject() - Could not find the specified object '%s'.", argv[2]);
+      return;
+   }
+
+   F32 speed = dAtof(argv[3]);
+
+   F32 force = 3.0f;
+
+   if (argc > 4)
+   {
+      force = dAtof(argv[4]);
+   }
+
+   bool orient = false;
+   if (argc > 5)
+   {
+      orient = dAtob(argv[5]);
+   }
+
+   F32 angleOff = 0.0f;
+   if (argc > 6)
+   {
+      angleOff = dAtof(argv[6]);
+   }
+
+   bool snapToNode = false;
+   if (argc > 7)
+   {
+      snapToNode = dAtob(argv[7]);
+   }
+
+   S32 startNode = 0;
+   if (argc > 8)
+   {
+      startNode = dAtoi(argv[8]);
+   }
+
+   bool loop = true;
+   if (argc > 9)
+   {
+      loop = dAtob(argv[9]);
+   }
+
+   S32 maxLoop = 0;
+   if (argc > 10)
+   {
+      maxLoop = dAtoi(argv[10]);
+   }
+
+   object->attachObject(pSceneObject, speed, force, orient, angleOff, snapToNode, startNode, loop, maxLoop);
+
+}
+
+/*! Removes a sceneObject from a path.
+@param SceneObject The object that will be detached from the path.
+@return No return value.
+*/
+ConsoleMethodWithDocs(Path, detachObject, ConsoleVoid, 3, 3, (sceneObject))
+{
+   // Set Group.
+   SceneObject* pSceneObject = dynamic_cast<SceneObject*>(Sim::findObject(argv[2]));
+
+   if (pSceneObject)
+      object->detachObject(pSceneObject);
+   else
+      Con::warnf("Path::detachObject() - Could not find the specified object '%s'.", argv[2]);
+}
+
+/*! Adds a node to a path.
+@param x The horizontal position of the node in world units.
+@param y The vertical position of the node in world units.
+@param distance The distance a from a node that it object must reach before it is considered to have reached the node, if snapToNode is set true for the object.
+@return No return value.
+*/
+ConsoleMethodWithDocs(Path, addNode, ConsoleVoid, 3, 6, (float x, float y, [float distance], [float weight]))
+{
+   Vector2 position;
+   position.Set(dAtof(argv[2]), dAtof(argv[3]));
+
+   F32 distance = 0.0f;
+   if (argc > 4)
+   {
+      distance = dAtof(argv[4]);
+   }
+
+   F32 weight = 0.0f;
+   if(argc > 5)
+   {
+      weight = dAtof(argv[5]);
+   }
+
+   object->addNode(position, distance, weight);
+}

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

@@ -29,7 +29,7 @@
 #endif
 #endif
 
 
 #ifndef _COLOR_H_
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 #endif
 
 
 #ifndef _BITSTREAM_H_
 #ifndef _BITSTREAM_H_
@@ -581,7 +581,7 @@ void SceneObject::preIntegrate( const F32 totalTime, const F32 elapsedTime, Debu
    // Finish if nothing is dirty.
    // Finish if nothing is dirty.
     if ( !mSpatialDirty )
     if ( !mSpatialDirty )
         return;
         return;
-
+    
     // Reset spatial changed.
     // Reset spatial changed.
     mSpatialDirty = false;
     mSpatialDirty = false;
 
 

+ 0 - 472
engine/source/2d/sceneobject/SkeletonObject.cc

@@ -1,472 +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 _SKELETON_OBJECT_H_
-#include "2d/sceneobject/SkeletonObject.h"
-#endif
-
-#include "spine/extension.h"
-
-// Script bindings.
-#include "2d/sceneobject/SkeletonObject_ScriptBinding.h"
-
-//-----------------------------------------------------------------------------
-
-/*void _spAtlasPage_createTexture (spAtlasPage* self, const char* path) {
-}
-void _spAtlasPage_disposeTexture (spAtlasPage* self) {
-}
-
-char* _spUtil_readFile (const char* path, int* length) {
-    return _readFile(path, length);
-}*/
-
-//-----------------------------------------------------------------------------
-
-IMPLEMENT_CONOBJECT(SkeletonObject);
-
-//------------------------------------------------------------------------------
-
-SkeletonObject::SkeletonObject() :  mPreTickTime( 0.0f ),
-                                    mPostTickTime( 0.0f ),
-                                    mTimeScale(1),
-                                    mLastFrameTime(0),
-                                    mTotalAnimationTime(0),
-                                    mSkeleton(NULL),
-                                    mState(NULL),
-                                    mAnimationCycle(false),
-                                    mAnimationFinished(true),
-                                    mAnimationDuration(0.0),
-                                    mFlipX(false),
-                                    mFlipY(false)
-{
-    mCurrentAnimation = StringTable->insert("");
-    mSkeletonScale.SetZero();
-    mSkeletonOffset.SetZero();
-}
-
-//------------------------------------------------------------------------------
-
-SkeletonObject::~SkeletonObject()
-{
-    if (mSkeleton) {
-        spSkeleton_dispose(mSkeleton);
-        mSkeleton = NULL;
-    }
-    if (mState) {
-        spAnimationState_dispose(mState);
-        mState = NULL;
-    }
-}
-
-//------------------------------------------------------------------------------
-
-void SkeletonObject::initPersistFields()
-{
-    // Call parent.
-    Parent::initPersistFields();
-    
-    addProtectedField("Asset", TypeSkeletonAssetPtr, Offset(mSkeletonAsset, SkeletonObject), &setSkeletonAsset, &getSkeletonAsset, &writeSkeletonAsset, "The skeleton asset ID used for the skeleton.");
-    addProtectedField("AnimationName", TypeString, Offset(mCurrentAnimation, SkeletonObject), &setAnimationName, &getAnimationName, &writeAnimationName, "The animation name to play.");
-    addProtectedField("Skin", TypeString, Offset(mCurrentSkin, SkeletonObject), &setCurrentSkin, &getCurrentSkin, &writeCurrentSkin, "The skin to use.");
-    addProtectedField("RootBoneScale", TypeVector2, 0, &setRootBoneScale, &getRootBoneScale, &writeRootBoneScale, "Scaling of the skeleton's root bone");
-    addProtectedField("RootBoneOffset", TypeVector2, 0, &setRootBoneOffset, &getRootBoneOffset, &writeRootBoneOffset, "X/Y offset of the skeleton's root bone");
-    addProtectedField("AnimationCycle", TypeBool, Offset(mAnimationCycle, SkeletonObject), &setAnimationCycle, &defaultProtectedGetFn, &writeAnimationCycle, "Whether the animation loops or not");
-    addField("FlipX", TypeBool, Offset(mFlipX, SkeletonObject), &writeFlipX, "");
-    addField("FlipY", TypeBool, Offset(mFlipY, SkeletonObject), &writeFlipY, "");
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::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 SkeletonObject::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 SkeletonObject::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 SkeletonObject::copyTo(SimObject* object)
-{
-    // Call to parent.
-    Parent::copyTo(object);
-    
-    // Fetch object.
-    SkeletonObject* pComposite = dynamic_cast<SkeletonObject*>(object);
-    
-    // Sanity!
-    AssertFatal(pComposite != NULL, "SkeletonObject::copyTo() - Object is not the correct type.");
-    
-    // Copy state.
-    pComposite->setSkeletonAsset( getSkeletonAsset() );
-    pComposite->setAnimationName( getAnimationName(), getAnimationCycle() );
-    pComposite->setCurrentSkin( getCurrentSkin() );
-    pComposite->setRootBoneScale( getRootBoneScale() );
-    pComposite->setRootBoneOffset( getRootBoneOffset() );
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::scenePrepareRender( const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue )
-{
-    // Prepare render.
-    SpriteBatch::prepareRender( this, pSceneRenderState, pSceneRenderQueue );
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
-{
-    // Render.
-    SpriteBatch::render( pSceneRenderState, pSceneRenderRequest, pBatchRenderer );
-    
-}
-
-//-----------------------------------------------------------------------------
-
-bool SkeletonObject::setSkeletonAsset( const char* pSkeletonAssetId )
-{
-    // Sanity!
-    AssertFatal( pSkeletonAssetId != NULL, "Cannot use a NULL asset Id." );
-    
-    // Fetch the asset Id.
-    mSkeletonAsset = pSkeletonAssetId;
-    
-    // Generate composition.
-    generateComposition();
-    
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool SkeletonObject::setAnimationName( const char* pAnimation, const bool isLooping )
-{
-    // Make sure an asset was loaded.
-    if (mSkeletonAsset.isNull())
-        return false;
-    
-    // Set the animation.
-    mCurrentAnimation = StringTable->insert(pAnimation);
-    
-    mAnimationCycle = isLooping;
-    
-    // Generate composition.
-    generateComposition();
-    
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool SkeletonObject::setMix( const char* pFromAnimation, const char* pToAnimation, float time)
-{
-    if (mSkeletonAsset.isNull())
-    {
-        Con::warnf("SkeletonObject::setMix() - Cannot mix. No asset assigned");
-        return false;
-    }
-    
-    // Check for valid animation state data
-    AssertFatal( mSkeletonAsset->mStateData != NULL, "SkeletonObject::setMix() - Animation state data invalid" );
-    
-    // Check to see if the "from animation" is valid
-    spAnimation* from = spSkeletonData_findAnimation(mSkeleton->data, pFromAnimation);
-    
-    if (!from)
-    {
-        Con::warnf("SkeletonObject::setMix() - Animation %s does not exist.", pFromAnimation);
-        return false;
-    }
-    
-    // Check to see if the "to animation" is valid
-    spAnimation* to = spSkeletonData_findAnimation(mSkeleton->data, pToAnimation);
-    
-    if (!to)
-    {
-        Con::warnf("SkeletonObject::setMix() - Animation %s does not exist.", pToAnimation);
-        return false;
-    }
-    
-    // Check to see if a valid mix time was passsed
-    if (time < 0.0f)
-    {
-        Con::warnf("SkeletonObject::setMix() - Invalid time set, %f", time);
-        return false;
-    }
-    
-    spAnimationStateData_setMixByName(mSkeletonAsset->mStateData, pFromAnimation, pToAnimation, time);
-    return true;
-}
-
-//-----------------------------------------------------------------------------
-
-bool SkeletonObject::setCurrentSkin( const char* pSkin )
-{
-    if (mSkeletonAsset.isNull() || !mSkeleton)
-    {
-        Con::errorf("SkeletonObject::setCurrentSkin() - Skeleton Asset was null or skeleton was not built");
-        return false;
-    }
-    
-    S32 result = spSkeleton_setSkinByName(mSkeleton, pSkin);
-    
-    if (result)
-    {
-        spSkeleton_setSlotsToSetupPose(mSkeleton);
-        return true;
-    }
-    else
-    {
-        Con::errorf("SkeletonObject::setCurrentSkin() - Skin %s not found", pSkin);
-        return false;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::setRootBoneScale(const Vector2& scale)
-{
-    mSkeletonScale = scale;
-    
-    if (!mSkeleton)
-        return;
-    
-    if (mSkeletonScale.notZero())
-    {
-        spBone* rootBone = mSkeleton->root;
-        rootBone->scaleX = mSkeletonScale.x;
-        rootBone->scaleY = mSkeletonScale.y;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::setRootBoneOffset(const Vector2& offset)
-{
-    mSkeletonOffset = offset;
-    
-    if (!mSkeleton)
-        return;
-    
-    if (mSkeletonOffset.notZero())
-    {
-        spBone* rootBone = mSkeleton->root;
-        rootBone->x = mSkeletonOffset.x;
-        rootBone->y = mSkeletonOffset.y;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::generateComposition( void )
-{
-    // Clear existing visualization
-    clearSprites();
-    mSkeletonSprites.clear();
-    
-    // Finish if skeleton asset isn't available.
-    if ( mSkeletonAsset.isNull() )
-        return;
-    
-    // Generate visualization.
-    if ((*mSkeletonAsset).mImageAsset.isNull())
-    {
-        Con::warnf( "SkeletonObject::generateComposition() - Image asset was NULL, so nothing can be added to the composition.");
-        return;
-    }
-    
-    if (!mSkeleton)
-        mSkeleton = spSkeleton_create(mSkeletonAsset->mSkeletonData);
-    
-    if (!mState)
-        mState = spAnimationState_create(mSkeletonAsset->mStateData);
-    
-    if (mCurrentAnimation != StringTable->EmptyString)
-    {
-        spAnimationState_setAnimationByName(mState, 0, mCurrentAnimation, mAnimationCycle);
-        mAnimationDuration = mState->tracks[0]->animation->duration;
-        mAnimationFinished = false;
-        mTotalAnimationTime = mLastFrameTime + mAnimationDuration;
-    }
-    
-    if (mSkeletonScale.notZero())
-    {
-        spBone* rootBone = mSkeleton->root;
-        rootBone->scaleX = mSkeletonScale.x;
-        rootBone->scaleY = mSkeletonScale.y;
-    }
-    
-    if (mSkeletonOffset.notZero())
-    {
-        spBone* rootBone = mSkeleton->root;
-        rootBone->x = mSkeletonOffset.x;
-        rootBone->y = mSkeletonOffset.y;
-    }
-}
-
-//-----------------------------------------------------------------------------
-
-void SkeletonObject::updateComposition( const F32 time )
-{
-    // Update position/orientation/state of visualization
-    float delta = (time - mLastFrameTime) * mTimeScale;
-    mLastFrameTime = time;
-    
-    spSkeleton_update(mSkeleton, delta);
-    
-    if (!mAnimationFinished)
-    {
-        spAnimationState_update(mState, delta);
-        spAnimationState_apply(mState, mSkeleton);
-    }
-    
-    spSkeleton_updateWorldTransform(mSkeleton);
-    
-    // Get the ImageAsset used by the sprites
-    StringTableEntry assetId = (*mSkeletonAsset).mImageAsset.getAssetId();
-    
-    clearSprites();
-    
-    Vector2 vertices[4];
-    
-    F32 vertexPositions[8];
-    for (int i = 0; i < mSkeleton->slotCount; ++i)
-    {
-        spSlot* slot = mSkeleton->slots[i];
-        spAttachment* attachment = slot->attachment;
-        
-        if (!attachment || attachment->type != ATTACHMENT_REGION)
-            continue;
-        
-        spRegionAttachment* regionAttachment = (spRegionAttachment*)attachment;
-        spRegionAttachment_computeWorldVertices(regionAttachment, slot->skeleton->x, slot->skeleton->y, slot->bone, vertexPositions);
-        
-        SpriteBatchItem* pSprite = SpriteBatch::createSprite();
-
-        pSprite->setDepth(mSceneLayerDepth);
-        
-        pSprite->setSrcBlendFactor(mSrcBlendFactor);
-        pSprite->setDstBlendFactor(mDstBlendFactor);
-        
-        mSkeleton->r = mBlendColor.red;
-        mSkeleton->g = mBlendColor.green;
-        mSkeleton->b = mBlendColor.blue;
-        mSkeleton->a = mBlendColor.alpha;
-        
-        F32 alpha = mSkeleton->a * slot->a;
-        pSprite->setBlendColor(ColorF(
-            mSkeleton->r * slot->r * alpha,
-            mSkeleton->g * slot->g * alpha,
-            mSkeleton->b * slot->b * alpha,
-            alpha
-        ));
-        
-        mSkeleton->flipX = getFlipX();
-        mSkeleton->flipY = getFlipY();
-        
-        vertices[0].x = vertexPositions[VERTEX_X1];
-        vertices[0].y = vertexPositions[VERTEX_Y1];
-        vertices[1].x = vertexPositions[VERTEX_X4];
-        vertices[1].y = vertexPositions[VERTEX_Y4];
-        vertices[2].x = vertexPositions[VERTEX_X3];
-        vertices[2].y = vertexPositions[VERTEX_Y3];
-        vertices[3].x = vertexPositions[VERTEX_X2];
-        vertices[3].y = vertexPositions[VERTEX_Y2];
-        pSprite->setExplicitVertices(vertices);
-        
-        pSprite->setImage(assetId);
-        pSprite->setNamedImageFrame(attachment->name);
-    }
-    
-    if (mLastFrameTime >= mTotalAnimationTime)
-        mAnimationFinished = true;
-    
-    if (mAnimationFinished && !mAnimationCycle)
-    {
-        onAnimationFinished();
-    }
-    else
-    {
-        mAnimationFinished = false;
-    }
-}
-
-void SkeletonObject::onAnimationFinished()
-{
-    // Do script callback.
-    Con::executef( this, 2, "onAnimationFinished", mCurrentAnimation );
-}

+ 0 - 161
engine/source/2d/sceneobject/SkeletonObject.h

@@ -1,161 +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 _SKELETON_OBJECT_H_
-#define _SKELETON_OBJECT_H_
-
-#ifndef _SPRITE_BATCH_H_
-#include "2d/core/SpriteBatch.h"
-#endif
-
-#ifndef _SCENE_OBJECT_H_
-#include "2d/sceneobject/SceneObject.h"
-#endif
-
-#ifndef _SKELETON_ASSET_H_
-#include "2d/assets/SkeletonAsset.h"
-#endif
-
-//------------------------------------------------------------------------------
-
-class SkeletonObject : public SceneObject, public SpriteBatch
-{
-protected:
-    typedef SceneObject Parent;
-    
-private:
-    typedef Vector<SpriteBatchItem*> typeSkeletonSpritesVector;
-    typeSkeletonSpritesVector   mSkeletonSprites;
-    
-    AssetPtr<SkeletonAsset>     mSkeletonAsset;
-    spSkeleton*                 mSkeleton;
-    spAnimationState*           mState;
-    
-    F32                         mPreTickTime;
-    F32                         mPostTickTime;
-    F32                         mTimeScale;
-    F32                         mLastFrameTime;
-    F32                         mAnimationDuration;
-    F32                         mTotalAnimationTime;
-    
-    bool                        mAnimationFinished;
-    bool                        mAnimationCycle;
-    Vector2                     mSkeletonScale;
-    Vector2                     mSkeletonOffset;
-    
-    StringTableEntry            mCurrentAnimation;
-    StringTableEntry            mCurrentSkin;
-    
-    bool                        mFlipX;
-    bool                        mFlipY;
-    
-    
-    
-public:
-    SkeletonObject();
-    virtual ~SkeletonObject();
-    
-    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 mSkeletonAsset.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 );
-    
-    /// Render flipping.
-    void setFlip( const bool flipX, const bool flipY )  { mFlipX = flipX; mFlipY = flipY; }
-    void setFlipX( const bool flipX )                   { setFlip( flipX, mFlipY ); }
-    void setFlipY( const bool flipY )                   { setFlip( mFlipX, flipY ); }
-    inline bool getFlipX( void ) const                  { return mFlipX; }
-    inline bool getFlipY( void ) const                  { return mFlipY; }
-    
-    bool setSkeletonAsset( const char* pSkeletonAssetId );
-    inline StringTableEntry getSkeletonAsset( void ) const { return mSkeletonAsset.getAssetId(); }
-    
-    inline bool setAnimationName( const char* pAnimation ) { return setAnimationName( pAnimation, mAnimationCycle ); }
-    bool setAnimationName( const char* pAnimation, const bool isLooping = false);
-    inline StringTableEntry getAnimationName( void ) const { return mCurrentAnimation; }
-    
-    bool setMix( const char* pFromAnimation, const char* pToAnimation, float time);
-    
-    bool setCurrentSkin( const char* pSkin );
-    inline StringTableEntry getCurrentSkin( void ) const { return mCurrentSkin; }
-    
-    void setRootBoneScale( const Vector2& scale );
-    inline void setRootBoneScale( const F32 x, const F32 y ){ setRootBoneScale( Vector2(x, y) ); }
-    inline Vector2 getRootBoneScale( void ) const { return mSkeletonScale; }
-    
-    void setRootBoneOffset( const Vector2& scale );
-    inline void setRootBoneOffset( const F32 x, const F32 y ){ setRootBoneOffset( Vector2(x, y) ); }
-    inline Vector2 getRootBoneOffset( void ) const { return mSkeletonOffset; }
-    
-    inline F32 getAnimationDuration( void ) const { return mAnimationDuration; }
-    inline bool isAnimationFinished( void ) const { return mAnimationFinished; };
-    
-    inline void setAnimationCycle( const bool isLooping ) { mAnimationCycle = isLooping; }
-    inline bool getAnimationCycle( void ) const {return mAnimationCycle; };
-    
-    void onAnimationFinished();
-    
-    /// Declare Console Object.
-    DECLARE_CONOBJECT( SkeletonObject );
-    
-protected:
-    void generateComposition( void );
-    void updateComposition( const F32 time );
-    
-protected:
-    static bool setSkeletonAsset( void* obj, const char* data )                  { static_cast<SkeletonObject*>(obj)->setSkeletonAsset(data); return false; }
-    static const char* getSkeletonAsset(void* obj, const char* data)             { return static_cast<SkeletonObject*>(obj)->getSkeletonAsset(); }
-    static bool writeSkeletonAsset( void* obj, StringTableEntry pFieldName )     { return static_cast<SkeletonObject*>(obj)->mSkeletonAsset.notNull(); }
-    
-    static bool setAnimationName( void* obj, const char* data )                  { static_cast<SkeletonObject*>(obj)->setAnimationName(data, static_cast<SkeletonObject*>(obj)->getAnimationCycle()); return false; }
-    static const char* getAnimationName(void* obj, const char* data)             { return static_cast<SkeletonObject*>(obj)->getAnimationName(); }
-    static bool writeAnimationName( void*obj, StringTableEntry pAnimation )      { return static_cast<SkeletonObject*>(obj)->getAnimationName() != StringTable->EmptyString; }
-    
-    static bool setCurrentSkin( void* obj, const char* data )                    { static_cast<SkeletonObject*>(obj)->setCurrentSkin(data); return false; }
-    static const char* getCurrentSkin(void* obj, const char* data)               { return static_cast<SkeletonObject*>(obj)->getCurrentSkin(); }
-    static bool writeCurrentSkin( void*obj, StringTableEntry pSkin )             { return static_cast<SkeletonObject*>(obj)->getCurrentSkin() != StringTable->EmptyString; }
-    
-    static bool setRootBoneScale(void* obj, const char* data)                    { static_cast<SkeletonObject*>(obj)->setRootBoneScale(Vector2(data)); return false; }
-    static const char* getRootBoneScale(void* obj, const char* data)             { return static_cast<SkeletonObject*>(obj)->getRootBoneScale().scriptThis(); }
-    static bool writeRootBoneScale( void* obj, StringTableEntry pFieldName )     { return static_cast<SkeletonObject*>(obj)->getRootBoneScale().notZero(); }
-    
-    static bool setRootBoneOffset(void* obj, const char* data)                   { static_cast<SkeletonObject*>(obj)->setRootBoneOffset(Vector2(data)); return false; }
-    static const char* getRootBoneOffset(void* obj, const char* data)            { return static_cast<SkeletonObject*>(obj)->getRootBoneOffset().scriptThis(); }
-    static bool writeRootBoneOffset( void* obj, StringTableEntry pFieldName )    { return static_cast<SkeletonObject*>(obj)->getRootBoneOffset().notZero(); }
-    
-    static bool setAnimationCycle( void* obj, const char* data )                 { static_cast<SkeletonObject*>(obj)->setAnimationCycle( dAtob(data) ); return false; }
-    static bool writeAnimationCycle( void* obj, StringTableEntry pFieldName )    { return static_cast<SkeletonObject*>(obj)->getAnimationCycle() == false; }
-    
-    static bool writeFlipX( void* obj, StringTableEntry pFieldName )             { return static_cast<SkeletonObject*>(obj)->getFlipX() == true; }
-    static bool writeFlipY( void* obj, StringTableEntry pFieldName )             { return static_cast<SkeletonObject*>(obj)->getFlipY() == true; }
-};
-
-#endif // _SKELETON_OBJECT_H_

+ 0 - 311
engine/source/2d/sceneobject/SkeletonObject_ScriptBinding.h

@@ -1,311 +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.
-//-----------------------------------------------------------------------------
-
-ConsoleMethodGroupBeginWithDocs(SkeletonObject, SceneObject)
-
-/*! Sets the skeleton asset Id to use.
-    @param skeletonAssetId The skeleton asset Id to use.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setSkeletonAsset, ConsoleVoid, 3, 3, (skeletonAssetId?))
-{
-    object->setSkeletonAsset( argv[2] );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the skeleton asset Id.
-    @return The skeleton asset Id.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getSkeletonAsset, ConsoleString, 2, 2, ())
-{
-    return object->getSkeletonAsset();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets the animation for the object.
-    @param animationName String containing animation name.
-    @param cycle Optional bool to determine whether the animation should loop.
-    @return Returns true on success."
-*/
-ConsoleMethodWithDocs(SkeletonObject, setAnimationName, ConsoleBool, 3, 4, (animationName, [cycle]))
-{
-    // Determine looping
-    bool shouldLoop = argc >= 4 ? dAtob(argv[3]) : false;
-    
-    return object->setAnimationName(argv[2], shouldLoop);
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the name of the current animation.
-    @return String containing the animation name.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getAnimationName, ConsoleString, 2, 2, ())
-{
-    return object->getAnimationName();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets the skin for the skeleton.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setSkin, ConsoleVoid, 3, 3, (skinName))
-{
-    object->setCurrentSkin(argv[2]);
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the name of the current skin.
-    @return String containing the skin name.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getSkin, ConsoleString, 2, 2, ())
-{
-    return object->getCurrentSkin();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets scaling of the skeleton's root bone.
-    @param scaleX Base x coordinate scale.
-    @param scaleY Base y coordinate scale.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setRootBoneScale, ConsoleVoid, 3, 4, (float scaleX, float scaleY))
-{
-    F32 scaleX, scaleY;
-    
-    const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
-    
-    // ("width height")
-    if ((elementCount == 2) && (argc == 3))
-    {
-        scaleX = dAtof(Utility::mGetStringElement(argv[2], 0));
-        scaleY = dAtof(Utility::mGetStringElement(argv[2], 1));
-    }
-    
-    // (width, [height])
-    else if (elementCount == 1)
-    {
-        scaleX = dAtof(argv[2]);
-        
-        if (argc > 3)
-            scaleY = dAtof(argv[3]);
-        else
-            scaleY = scaleX;
-    }
-    
-    // Invalid
-    else
-    {
-        Con::warnf("SkeletonObject::setRootBoneScale() - Invalid number of parameters!");
-        return;
-    }
-    
-    // Set Scale.
-    object->setRootBoneScale(Vector2(scaleX, scaleY));
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the skeleton's root bone scale.
-    @return (float x/y height) The x and y scale of the object's root bone.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getRootBoneScale, ConsoleString, 2, 2, ())
-{
-    return object->getRootBoneScale().scriptThis();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets local offset of the skeleton's root bone.
-    @param x Base x coordinate.
-    @param y Base y coordinate.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setRootBoneOffset, ConsoleVoid, 3, 4, (float x, float y))
-{
-    F32 x, y;
-    
-    const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
-    
-    // ("x y")
-    if ((elementCount == 2) && (argc == 3))
-    {
-        x = dAtof(Utility::mGetStringElement(argv[2], 0));
-        y = dAtof(Utility::mGetStringElement(argv[2], 1));
-    }
-    
-    // (x, [y])
-    else if (elementCount == 1)
-    {
-        x = dAtof(argv[2]);
-        
-        if (argc > 3)
-            y = dAtof(argv[3]);
-        else
-            y = x;
-    }
-    
-    // Invalid
-    else
-    {
-        Con::warnf("SkeletonObject::setRootBoneOffset() - Invalid number of parameters!");
-        return;
-    }
-    
-    // Set Size.
-    object->setRootBoneOffset(Vector2(x, y));
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the skeleton's root bone offset.
-    @return (float x/y) The x and y offset of the object's root bone.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getRootBoneOffset, ConsoleString, 2, 2, ())
-{
-    return object->getRootBoneOffset().scriptThis();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets whether the animation cycles or not.
-    @param cycle Bool to determine whether the animation should loop.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setAnimationCycle, ConsoleVoid, 3, 3, (bool cycle))
-{
-    object->setAnimationCycle( dAtob(argv[2] ) );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets whether the animation cycles or not.
-    @return Whether the animation cycles or not.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getAnimationCycle, ConsoleBool, 2, 2, ())
-{
-    return object->getAnimationCycle();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets the sprite texture flipping for each axis.
-    @param flipX Whether or not to flip the texture along the x (horizontal) axis.
-    @param flipY Whether or not to flip the texture along the y (vertical) axis.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setFlip, ConsoleVoid, 4, 4, (bool flipX, bool flipY))
-{
-    // Set Flip.
-    object->setFlip( dAtob(argv[2]), dAtob(argv[3]) );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the flip for each axis.
-    @return (bool flipX/bool flipY) Whether or not the texture is flipped along the x and y axis.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getFlip, ConsoleString, 2, 2, ())
-{
-    // Create Returnable Buffer.
-    char* pBuffer = Con::getReturnBuffer(32);
-    
-    // Format Buffer.
-    dSprintf(pBuffer, 32, "%d %d", object->getFlipX(), object->getFlipY());
-    
-    // Return Buffer.
-    return pBuffer;
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets whether or not the texture is flipped horizontally.
-    @param flipX Whether or not to flip the texture along the x (horizontal) axis.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setFlipX, ConsoleVoid, 3, 3, (bool flipX))
-{
-    // Set Flip.
-    object->setFlipX( dAtob(argv[2]) );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Sets whether or not the texture is flipped vertically.
-    @param flipY Whether or not to flip the texture along the y (vertical) axis.
-    @return No return value.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setFlipY, ConsoleVoid, 3, 3, (bool flipY))
-{
-    // Set Flip.
-    object->setFlipY( dAtob(argv[2]) );
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets whether or not the texture is flipped horizontally.
-    @return (bool flipX) Whether or not the texture is flipped along the x axis.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getFlipX, ConsoleBool, 2, 2, ())
-{
-    return object->getFlipX();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets whether or not the texture is flipped vertically.
-    @return (bool flipY) Whether or not the texture is flipped along the y axis.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getFlipY, ConsoleBool, 2, 2, ())
-{
-    return object->getFlipY();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Gets the duration of the current animation.
-    @return Duration of the animation in seconds.
-*/
-ConsoleMethodWithDocs(SkeletonObject, getAnimationDuration, ConsoleFloat, 2, 2, ())
-{
-    return object->getAnimationDuration();
-}
-
-//-----------------------------------------------------------------------------
-
-/*! Mixes the current animation with another.
-    @param animation The name of the animation to mix.
-    @param time The time to start mixing.
-*/
-ConsoleMethodWithDocs(SkeletonObject, setMix, ConsoleBool, 5, 5, (fromAnimation, toAnimation, time))
-{
-    Con::printf("Mixing %s with %s at %f", argv[2], argv[3], dAtof(argv[4]));
-    
-    return object->setMix(argv[2], argv[3], dAtof(argv[4]));
-}
-
-ConsoleMethodGroupEndWithDocs(SkeletonObject)

+ 44 - 0
engine/source/2d/sceneobject/SpineCollisionProxy.cc

@@ -0,0 +1,44 @@
+// Author: Mike Tannel - 7/21/2020
+//
+// 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 _SPINE_COLLISION_PROXY_H_
+#include "SpineCollisionProxy.h"
+#endif
+
+//------------------------------------------------------------------------------
+// Want these proxies usable from torque script
+IMPLEMENT_CONOBJECT(SpineCollisionProxy);
+
+//------------------------------------------------------------------------------
+
+SpineCollisionProxy::SpineCollisionProxy() :
+	mAttachmentName{NULL},
+	mSlotName{NULL},
+	mSkinName{NULL},
+	mWidthSizer{1.0f},
+	mHeightSizer{1.0f},
+	mObjectName{NULL},
+	mActive{true},
+	mRotation{0.0f}
+{}
+
+//------------------------------------------------------------------------------
+
+SpineCollisionProxy::SpineCollisionProxy(const char *name, const char *slot, const char *skin, F32 wSizer, F32 hSizer, const char *objectName) :
+	mAttachmentName{ name },
+	mSlotName{ slot },
+	mSkinName{ skin },
+	mWidthSizer{ wSizer },
+	mHeightSizer{ hSizer },
+	mObjectName{ objectName },
+	mActive{ true },
+	mRotation{ 0.0f }
+{}

+ 53 - 0
engine/source/2d/sceneobject/SpineCollisionProxy.h

@@ -0,0 +1,53 @@
+// Author: Mike Tannel - 7/21/2020
+//
+// 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 _SPINE_COLLISION_PROXY_H_
+#define _SPINE_COLLISION_PROXY_H_
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+#ifndef SPINE_SPINE_H_
+#include "spine/spine.h"
+#endif
+
+class SpineCollisionProxy :
+	public SceneObject
+{
+protected:
+	// For console object
+	typedef SceneObject Parent;
+
+public:
+	SpineCollisionProxy();
+	SpineCollisionProxy(const char *name, const char *slot, const char *skin, F32 wSizer = 1.0f, F32 hSizer = 1.0f, const char *objectName = NULL);
+
+	const char *mAttachmentName;
+	const char *mSlotName;
+	const char *mSkinName;
+	F32			mWidthSizer;
+	F32			mHeightSizer;
+	const char *mObjectName;
+
+	bool mActive;
+
+	F32	 mRotation;
+
+	/// Declare Console Object.
+	DECLARE_CONOBJECT(SpineCollisionProxy);
+
+public:
+	inline void deActivate(void) { if (!mActive) return;  mActive = false; setActive(false); }
+	inline void activate(void) { if (mActive) return;  mActive = true; setActive(true); }
+
+};
+
+#endif // _SPINE_COLLISION_PROXY_H_

+ 1394 - 0
engine/source/2d/sceneobject/SpineObject.cc

@@ -0,0 +1,1394 @@
+//-----------------------------------------------------------------------------
+// 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 _SPINE_OBJECT_H_
+#include "2d/sceneobject/SpineObject.h"
+#endif
+
+// Script bindings.
+#include "2d/sceneobject/SpineObject_ScriptBinding.h"
+
+//------------------------------------------------------------------------------
+
+void spineAnimationEventCallbackHandler(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event) {
+
+	SpineObject *targetSpineObject = (SpineObject *)state->userData;
+	if (!targetSpineObject) {
+		Con::warnf("spineAnimationEventCallbackHandler - Event ('%s') received with no spine object in spAnimationState->userData.  Discarding event.",
+			event->data->name);
+	}
+
+	const char* animationName = StringTable->insert(entry && entry->animation ? entry->animation->name : 0, true);
+
+	switch (type) {
+	case SP_ANIMATION_START:
+		Con::executef(targetSpineObject, 3, "onAnimationStart", animationName, Con::getIntArg(entry->trackIndex));
+		break;
+	case SP_ANIMATION_INTERRUPT:
+		Con::executef(targetSpineObject, 3, "onAnimationInterrupt", animationName, Con::getIntArg(entry->trackIndex));
+		break;
+	case SP_ANIMATION_END:
+		Con::executef(targetSpineObject, 3, "onAnimationEnd", animationName, Con::getIntArg(entry->trackIndex));
+		break;
+	case SP_ANIMATION_COMPLETE:
+		Con::executef(targetSpineObject, 3, "onAnimationComplete", animationName, Con::getIntArg(entry->trackIndex));
+		break;
+	case SP_ANIMATION_DISPOSE:
+		Con::executef(targetSpineObject, 3, "onAnimationDispose", animationName, Con::getIntArg(entry->trackIndex));
+		break;
+	case SP_ANIMATION_EVENT:
+		Con::executef(targetSpineObject, 10
+			, "onAnimationEvent"
+			, animationName
+			, Con::getIntArg(entry->trackIndex)
+			, event->data->name ? event->data->name : ""
+			, Con::getIntArg(event->intValue)
+			, Con::getFloatArg(event->floatValue)
+			, event->stringValue ? event->stringValue : ""
+			, Con::getFloatArg(event->time)
+			, Con::getFloatArg(event->volume)
+			, Con::getFloatArg(event->balance));
+		break;
+	}
+}
+
+//------------------------------------------------------------------------------
+
+IMPLEMENT_CONOBJECT(SpineObject);
+
+//------------------------------------------------------------------------------
+
+// Spine vertex effect support
+static EnumTable::Enums vertexEffectLookup[] =
+{
+	{ SpineObject::NONE,     "None"   },
+	{ SpineObject::JITTER,   "Jitter" },
+	{ SpineObject::SWIRL,    "Swirl"  }
+};
+
+static EnumTable VertexEffectTable(3, &vertexEffectLookup[0]);
+
+//------------------------------------------------------------------------------
+
+SpineObject::VertexEffect SpineObject::getVertexEffectTypeEnum(const char* label)
+{
+	// Search for Mnemonic.
+	for (U32 i = 0; i < (sizeof(vertexEffectLookup) / sizeof(EnumTable::Enums)); i++)
+		if (dStricmp(vertexEffectLookup[i].label, label) == 0)
+			return((SpineObject::VertexEffect)vertexEffectLookup[i].index);
+
+	// Warn.
+	Con::warnf("SpineObject::getVertexEffectTypeEnum() - Invalid vertex effect type '%s'.", label);
+
+	return VertexEffect::INVALID_VERTEX_EFFECT;
+}
+
+//-----------------------------------------------------------------------------
+
+const char* SpineObject::getVertexEffectTypeDescription(const VertexEffect vertexEffectType)
+{
+	// Search for Mnemonic.
+	for (U32 i = 0; i < (sizeof(vertexEffectLookup) / sizeof(EnumTable::Enums)); i++)
+	{
+		if (vertexEffectLookup[i].index == (S32)vertexEffectType)
+			return vertexEffectLookup[i].label;
+	}
+
+	// Warn.
+	Con::warnf("SpineObject::getVertexEffectTypeDescription() - Invalid vertex effect type.");
+
+	return StringTable->EmptyString;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::initPersistFields()
+{
+	// Call parent.
+	Parent::initPersistFields();
+
+	addProtectedField("Asset", TypeSpineAssetPtr, Offset(mSpineAsset, SpineObject), &setSpineAsset, &defaultProtectedGetFn, &writeSpineAsset, "The spine asset ID used for the spine.");
+	addProtectedField("Skin", TypeString, 0, &setSkin, &getSkinName, &writeCurrentSkin, "The skin to use.");
+	addProtectedField("Scale", TypeVector2, 0, &setScale, &getScale, &writeScale, "Scaling of the skeleton geometry.");
+	addProtectedField("AnimationData", TypeString, 0, &setAnimationData, &getAnimationData, &writeAnimationData, "String encoding of the running animations.  It's a tilde separated list of animation entries.  Within each entry, each attribute is separated by a semicolon.  The attributes are, in this order:  1) Name - String: Name of animation as defined in Spine.  2) Track - Integer: Track the animation is running on.  3) Is Looping - Boolean: 1 or 0.  4) Mix Duration - Float: Can be set to -1.0 to request default mix duration.");
+	addProtectedField("TimeScale", TypeF32, 0, &setTimeScale, &getTimeScale, &writeTimeScale, "Time scale (animation speed) adjustment factor.");
+	addProtectedField("FlipX", TypeBool, Offset(mFlipX, SpineObject), &setFlipX, &defaultProtectedGetFn, &writeFlipX, "Whether to invert the image horizontally.");
+	addProtectedField("FlipY", TypeBool, Offset(mFlipY, SpineObject), &setFlipY, &defaultProtectedGetFn, &writeFlipY, "Whether image should be inverted vertically.");
+	addGroup("Vertex Effects");
+	addProtectedField("ActiveEffect", TypeEnum, Offset(mActiveEffect, SpineObject), &setActiveEffectType, &defaultProtectedGetFn, &writeActiveEffectType, 1, &VertexEffectTable, "The name of the vertex effect assigned, or None.");
+	addProtectedField("JitterX", TypeF32, 0, &setJitterX, &getJitterX, &writeJitterEffectValues, "A 'Jitter' vertex special effect setting.  Note: Play around with the various settings.  They can be modified on the fly to vary the effect the displayed item.");
+	addProtectedField("JitterY", TypeF32, 0, &setJitterY, &getJitterY, &writeJitterEffectValues, "A 'Jitter' vertex special effect setting.");
+	addProtectedField("SwirlX", TypeF32, 0, &setSwirlX, &getSwirlX, &writeSwirlEffectValues, "A 'Swirl' vertex special effect setting.");
+	addProtectedField("SwirlY", TypeF32, 0, &setSwirlY, &getSwirlY, &writeSwirlEffectValues, "A 'Swirl' vertex special effect setting.");
+	addProtectedField("SwirlRadius", TypeF32, 0, &setSwirlRadius, &getSwirlRadius, &writeSwirlEffectValues, "A 'Swirl' vertex special effect setting.");
+	addProtectedField("SwirlAngle", TypeF32, 0, &setSwirlAngle, &getSwirlAngle, &writeSwirlEffectValues, "A 'Swirl' vertex special effect setting.");
+	endGroup("Vertex Effects");
+	addProtectedField("EventCallbacksEnabled", TypeBool, 0, &setEventCallbacksEnabled, &defaultProtectedGetFn, &writeEventCallbacksEnabled, "Whether the SpineObject should receive spine animation event callbacks.");
+	addProtectedField("CollisionData", TypeString, 0, &setCollisionData, &getCollisionData, &writeCollisionData, "String encoding of the Spine object's collision boxes.  It's a tilde separated list of collision proxy definitions.  Within each entry, each attribute is separated by a semicolon.  The attributes are, in this order:  1) Attachment Name - String: Name of attachment that box belongs to.  2) Slot Name - String: Slot that owns the attachment.  3) Skin Name - String: Skin that defines the attachment.  4) Width Sizer - Float: Factor useful to tweak the width of the box.  5) Height Sizer - Float: Factor useful to tweak the height of the box.  6) SimObject Name - String: Name assigned to the collision proxy instance.  May be NULL if no name was assigned.");
+
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::resetState() {
+
+	mPreTickTime = 0.0f;
+	mPostTickTime = 0.0f;
+	mLastFrameTime = 0.0f;
+	mFlipX = mFlipY = false;
+
+	mSkeleton.reset();
+	mAnimationState.reset();
+	mSkeletonClipping.reset();
+	mSkeletonBounds.reset();
+
+	mAutoCenterOffset.SetZero();
+
+	// Don't want b2DynamicTree supported search (for culling reasons) being performed 
+	// on our couple-o-sprites lashup.
+	setBatchCulling(false);
+
+	mVertexEffect = NULL;
+	mActiveEffect = VertexEffect::NONE;
+
+	mPriorRootBoneWorldX = 0.0f;
+	mPriorRootBoneWorldY = 0.0f;
+	mPriorFlipX = mFlipX;
+	mPriorFlipY = mFlipY;
+
+	mCollisionProxies.clear();
+}
+
+//------------------------------------------------------------------------------
+
+// NOTE: Update this if new state members are added to the object.
+void SpineObject::copyTo(SimObject* object)
+{
+	// Call to parent.
+	Parent::copyTo(object);
+
+	// Fetch object.
+	SpineObject* pSpine = dynamic_cast<SpineObject*>(object);
+
+	// Sanity!
+	AssertFatal(pSpine != NULL, "SpineObject::copyTo() - Object is not the correct type.");
+
+	// Copy state.
+	pSpine->setSpineAsset(getSpineAsset());
+	pSpine->setFlipX(getFlipX());
+	pSpine->setFlipY(getFlipY());
+	pSpine->setPosition(getPosition());
+	pSpine->setAngle(getAngle());
+	pSpine->setAnimation(getAnimationName(), getIsLooping());
+	pSpine->setSkin(getSkinName());
+	pSpine->setScale(getScale());
+	pSpine->mAutoCenterOffset = mAutoCenterOffset;
+
+	copyCollisionShapes(pSpine);
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::setSpineAsset(const char* pSpineAssetId)
+{
+	// Sanity!
+	if (pSpineAssetId == NULL)
+	{
+		Con::errorf("SpineObject::setSpineAsset() - Cannot use a NULL asset Id.");
+		return false;
+	}
+
+	// Fetch the asset.
+	AssetPtr<SpineAsset> temp = StringTable->insert(pSpineAssetId, true);
+
+	if (temp->mImageAsset.isNull())
+	{
+		Con::errorf("SpineObject::setSpineAsset() - Image asset is undefined.");
+		return false;
+	}
+
+	// Clear away existing. 
+	clearSprites();
+	resetState();
+
+	// Reflect asset definition
+	mSpineAsset = std::move(temp);
+	mSkeleton = skeleton_ptr(spSkeleton_create(mSpineAsset->mSkeletonData));
+	mAnimationState = animationState_ptr(spAnimationState_create(mSpineAsset->mAnimationStateData));
+	mSkeletonBounds = skeletonBounds_ptr(spSkeletonBounds_create());
+	mSkeletonClipping = skeletonClipping_ptr(spSkeletonClipping_create());
+
+	spSkeleton_setToSetupPose(mSkeleton.get());
+
+	// Needed by the events system to route callbacks.
+	mAnimationState->userData = this;
+
+	// Prepare for animation.
+	updateSpine(0.0f);
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::setFlip(const bool flipX, const bool flipY) {
+
+	mFlipX = flipX;
+	mSkeleton->scaleX = flipX
+		? mSkeleton->scaleX < 0 ? mSkeleton->scaleX : -mSkeleton->scaleX
+		: mSkeleton->scaleX >= 0 ? mSkeleton->scaleX : -mSkeleton->scaleX;
+
+	mFlipY = flipY;
+	mSkeleton->scaleY = flipY
+		? mSkeleton->scaleY < 0 ? mSkeleton->scaleY : -mSkeleton->scaleY
+		: mSkeleton->scaleY >= 0 ? mSkeleton->scaleY : -mSkeleton->scaleY;
+}
+
+//-----------------------------------------------------------------------------
+
+F32 SpineObject::setTimeScale(const F32 timeScale) {
+	if (!mAnimationState)
+		return 0.0f;
+
+	F32 previousValue = mAnimationState->timeScale;
+
+	mAnimationState->timeScale = timeScale;
+
+	return previousValue;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::setAnimation(const char* pName, const int track, const bool shouldLoop, const F32 mixDuration)
+{
+	if (!mAnimationState)
+		return false;
+
+	// Check to see if the requested animation is valid
+	auto animation = spSkeletonData_findAnimation(mSkeleton->data, StringTable->insert(pName, true));
+
+	if (!animation)
+	{
+		Con::warnf("SpineObject::setAnimation() - Animation '%s' does not exist.", StringTable->insert(pName, true));
+		return false;
+	}
+
+	// Set the animation.
+	spTrackEntry* entry = spAnimationState_setAnimation(mAnimationState.get(), track, animation, shouldLoop);
+
+	if (mixDuration < 0.0f) {
+		// Use default mix duration
+		return entry != NULL;
+	}
+	else {
+		// Use given mix duration.
+		entry->mixDuration = mixDuration;
+		return true;
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::setEmptyAnimation(const int track, const F32 mixDuration) {
+	if (!mAnimationState)
+		return false;
+
+	return spAnimationState_setEmptyAnimation(mAnimationState.get(), track, mixDuration) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::queueAnimation(const char* pName, const int track, const bool shouldLoop, const F32 mixDuration, const F32 delay)
+{
+	if (!mAnimationState)
+		return false;
+
+	// Check to see if the requested animation is valid
+	auto animation = spSkeletonData_findAnimation(mSkeleton->data, StringTable->insert(pName, true));
+
+	if (!animation)
+	{
+		Con::warnf("SpineObject::queueAnimation() - Animation '%s' does not exist.", StringTable->insert(pName, true));
+		return false;
+	}
+
+	// Set the animation.
+	spTrackEntry* entry = spAnimationState_addAnimation(mAnimationState.get(), track, animation, shouldLoop, delay);
+
+	if (mixDuration < 0.0f) {
+		// Use default mix duration
+		return entry != NULL;
+	}
+	else {
+		// Use given mix duration.
+		entry->mixDuration = mixDuration;
+		return true;
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::queueEmptyAnimation(const int track, const F32 mixDuration, const F32 delay) {
+	if (!mAnimationState)
+		return false;
+
+	return spAnimationState_addEmptyAnimation(mAnimationState.get(), track, mixDuration, delay) != NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::clearAnimations(const int track, const bool mixToSetupPose, const F32 mixDuration) {
+	if (!mAnimationState)
+		return;
+
+	spAnimationState_clearTrack(mAnimationState.get(), track);
+
+	if (mixToSetupPose)
+		setEmptyAnimation(track, mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::clearAllAnimations(const bool mixToSetupPose, const F32 mixDuration) {
+	if (!mAnimationState)
+		return;
+
+	spAnimationState_clearTracks(mAnimationState.get());
+
+	if (mixToSetupPose)
+		spAnimationState_setEmptyAnimations(mAnimationState.get(), mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+StringTableEntry SpineObject::getAnimationName(const int track) const {
+	if (!mAnimationState)
+		return StringTable->EmptyString;
+
+	spTrackEntry* entry = spAnimationState_getCurrent(mAnimationState.get(), track);
+
+	if (!entry)
+		return StringTable->EmptyString;
+
+	return StringTable->insert(entry->animation->name, true);
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::getIsLooping(const int track) const {
+	if (!mAnimationState)
+		return StringTable->EmptyString;
+
+	spTrackEntry* entry = spAnimationState_getCurrent(mAnimationState.get(), track);
+
+	if (!entry)
+		return StringTable->EmptyString;
+
+	return entry->loop;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::setMix(const char* pFromAnimation, const char* pToAnimation, const F32 time)
+{
+	if (mSpineAsset.isNull())
+	{
+		Con::warnf("SpineObject::setMix() - Cannot mix. No asset assigned");
+		return false;
+	}
+
+	// Check for valid animation state data
+	AssertFatal(mSpineAsset->mAnimationStateData != NULL, "SpineObject::setMix() - Animation state data invalid");
+
+	// Check to see if the "from animation" is valid
+	auto from = spSkeletonData_findAnimation(mSkeleton->data, StringTable->insert(pFromAnimation, true));
+
+	if (!from)
+	{
+		Con::warnf("SpineObject::setMix() - Animation '%s' does not exist.", StringTable->insert(pFromAnimation, true));
+		return false;
+	}
+
+	// Check to see if the "to animation" is valid
+	auto to = spSkeletonData_findAnimation(mSkeleton->data, StringTable->insert(pToAnimation, true));
+
+	if (!to)
+	{
+		Con::warnf("SpineObject::setMix() - Animation '%s' does not exist.", StringTable->insert(pToAnimation, true));
+		return false;
+	}
+
+	// Check to see if a valid mix time was passsed
+	if (time < 0.0f)
+	{
+		Con::warnf("SpineObject::setMix() - Invalid time set, '%f'", time);
+		return false;
+	}
+
+	spAnimationStateData_setMix(mSpineAsset->mAnimationStateData, from, to, time);
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::setSkin(const char* pSkin)
+{
+	if (mSpineAsset.isNull() || !mSkeleton)
+	{
+		Con::errorf("SpineObject::setSkin() - Spine asset was null or skeleton was not built.");
+		return false;
+	}
+
+	auto to = spSkeletonData_findSkin(mSkeleton->data, StringTable->insert(pSkin, true));
+	if (!to)
+	{
+		Con::warnf("SpineObject::setSkin() - Skin '%s' does not exist.", StringTable->insert(pSkin, true));
+		return false;
+	}
+
+	spSkeleton_setSkin(mSkeleton.get(), to);
+	spSkeleton_setSlotsToSetupPose(mSkeleton.get());
+	spAnimationState_apply(mAnimationState.get(), mSkeleton.get());
+
+	return true;
+}
+
+//-----------------------------------------------------------------------------
+
+inline StringTableEntry SpineObject::getSkinName(void) const {
+	if (!mAnimationState || !mSkeleton)
+		return StringTable->EmptyString;
+
+	spSkin* pSkin = mSkeleton->skin;
+
+	if (!pSkin) {
+		AssertFatal(mSkeleton->data->defaultSkin, avar("SpineObject::getSkinName() - Skin name is undefined in '%s'.  Is file valid?", mSpineAsset->mSpineFile));
+
+		// Using default skin.
+		return StringTable->insert(mSkeleton->data->defaultSkin->name, true);
+	}
+	else {
+		return StringTable->insert(pSkin->name, true);
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::setScale(const Vector2& scale)
+{
+	if (!mSkeleton)
+		return;
+
+	// Set scale, but keep orientation.  This is used by spine to flip the character
+	// as well as set its size.
+	mSkeleton->scaleX = mSkeleton->scaleX < 0.0f ? -scale.x : scale.x;
+	mSkeleton->scaleY = mSkeleton->scaleY < 0.0f ? -scale.y : scale.y;
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::setActiveEffect(const VertexEffect requestedEffect) {
+	if (mActiveEffect == requestedEffect)
+		return;
+
+	switch (requestedEffect) {
+	case VertexEffect::JITTER:
+		if (!mJitterControl) {
+			mJitterControl = jitterEffect_ptr(spJitterVertexEffect_create(0, 0));
+		}
+		mVertexEffect = &mJitterControl->super;
+		mActiveEffect = VertexEffect::JITTER;
+		break;
+	case VertexEffect::SWIRL:
+		if (!mSwirlControl) {
+			mSwirlControl = swirlEffect_ptr(spSwirlVertexEffect_create(0));
+		}
+		mVertexEffect = &mSwirlControl->super;
+		mActiveEffect = VertexEffect::SWIRL;
+		break;
+	default:
+		Con::warnf("SpineObject::setActiveEffect - Unrecognized vertex special effect requested: '%s'.",
+			getVertexEffectTypeDescription(requestedEffect));
+	}
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::enableJitter(const F32 x, const F32 y) {
+	if (mJitterControl) {
+		mJitterControl->jitterX = x;
+		mJitterControl->jitterY = y;
+	}
+	else {
+		mJitterControl = jitterEffect_ptr(spJitterVertexEffect_create(x, y));
+	}
+	mVertexEffect = &mJitterControl->super;
+	mActiveEffect = VertexEffect::JITTER;
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::disableJitter() {
+	if (mActiveEffect == VertexEffect::JITTER) {
+		mVertexEffect = NULL;
+		mActiveEffect = VertexEffect::NONE;
+	}
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::enableSwirl(const F32 radius) {
+	if (mSwirlControl) {
+		mSwirlControl->radius = radius;
+	}
+	else {
+		mSwirlControl = swirlEffect_ptr(spSwirlVertexEffect_create(radius));
+	}
+	mVertexEffect = &mSwirlControl->super;
+	mActiveEffect = VertexEffect::SWIRL;
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::disableSwirl() {
+	if (mActiveEffect == VertexEffect::SWIRL) {
+		mVertexEffect = NULL;
+		mActiveEffect = VertexEffect::NONE;
+	}
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::enableEventCallbacks(void) {
+	// No animation state
+	if (!mAnimationState)
+		return;
+
+	// Already listening
+	if (mAnimationState->listener)
+		return;
+
+	mAnimationState->listener = spineAnimationEventCallbackHandler;
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::disableEventCallbacks(void) {
+	// No animation state
+	if (!mAnimationState)
+		return;
+
+	// Not listening anyway.
+	if (!mAnimationState->listener)
+		return;
+
+	mAnimationState->listener = NULL;
+}
+
+//------------------------------------------------------------------------------
+
+void SpineObject::preIntegrate(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats)
+{
+	Parent::preIntegrate(totalTime, elapsedTime, pDebugStats);
+
+	// Note tick times.
+	mPreTickTime = mPostTickTime;
+	mPostTickTime = totalTime;
+
+	// Update at pre-tick time.
+	updateSpine(mPreTickTime);
+	prepareSpineForRender();
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::interpolateObject(const F32 timeDelta)
+{
+	Parent::interpolateObject(timeDelta);
+
+	// Update time (interpolated).
+	F32 timeInterp = (timeDelta * mPreTickTime) + ((1.0f - timeDelta) * mPostTickTime);
+	updateSpine(timeInterp);
+	prepareSpineForRender();
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::scenePrepareRender(const SceneRenderState* pSceneRenderState, SceneRenderQueue* pSceneRenderQueue)
+{
+	// Set batch transform to identity because the skeleton is responsible for 
+	// its geometry's position
+	setBatchTransform(B2_IDENTITY_TRANSFORM);
+
+	SpriteBatch::prepareRender(this, pSceneRenderState, pSceneRenderQueue);
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::sceneRender(const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer)
+{
+	// Render.
+	SpriteBatch::render(pSceneRenderState, pSceneRenderRequest, pBatchRenderer);
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::updateSpine(const F32 time)
+{
+	// Update the skeleton's position/rotation.
+	Vector2 p = getPosition();
+	mSkeleton->x = p.x - mAutoCenterOffset.x;
+	mSkeleton->y = p.y - mAutoCenterOffset.y;
+	mSkeleton->root->rotation = setPerFlipState(mRadToDeg(getAngle()));
+
+	// Advance time
+	F32 delta = (time - mLastFrameTime);
+	mLastFrameTime = time;
+
+	spSkeleton_update(mSkeleton.get(), delta);
+	spAnimationState_update(mAnimationState.get(), delta);
+	spAnimationState_apply(mAnimationState.get(), mSkeleton.get());
+	spSkeleton_updateWorldTransform(mSkeleton.get());
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::prepareSpineForRender()
+{
+	// Early out if skeleton is invisible
+	if (mSkeleton->color.a == 0) {
+		for (const auto& i : mCollisionProxies) {
+			i.value->deActivate();
+		}
+		return;
+	}
+
+	if (mVertexEffect)
+		mVertexEffect->begin(mVertexEffect, mSkeleton.get());
+
+	// Get the ImageAsset used by the sprites
+	StringTableEntry assetId = mSpineAsset->mImageAsset.getAssetId();
+
+	clearSprites();
+
+	b2AABB spriteAABB;
+	U16 quadIndices[6] = { 0, 1, 2, 2, 3, 0 };
+	FrameTemp<F32> VertexBuffer(BatchRender::maxVertexCount);
+
+	vector<Vector2> pointSoup;
+
+	for (int i = 0; i < mSkeleton->slotsCount; ++i)
+	{
+		auto slot = mSkeleton->drawOrder[i];
+		if (!slot)
+			continue;
+
+		auto attachment = slot->attachment;
+		if (!attachment)
+			continue;
+
+		SpineCollisionProxy* pCollisionProxy = NULL;
+		auto itr = mCollisionProxies.find(attachment);
+		if (itr != mCollisionProxies.end()) {
+			pCollisionProxy = itr->value;
+		}
+
+		if (slot->color.a == 0 || !slot->bone->active) {
+			spSkeletonClipping_clipEnd(mSkeletonClipping.get(), slot);
+
+			if (pCollisionProxy && pCollisionProxy->mActive) {
+				pCollisionProxy->deActivate();
+			}
+			continue;
+		}
+
+		F32	*uvs = 0;
+		U16	*indices = 0;
+		int	indicesCount = 0;
+		F32 *vertices = VertexBuffer; // It will be redirected to a different buffer if clipping is performed.
+		int	verticesCount = 0;
+		spColor* attachmentColor = NULL;
+		string attachmentName;
+
+		if (attachment->type == SP_ATTACHMENT_REGION) {
+			auto regionAttachment = (spRegionAttachment*)attachment;
+			attachmentName = StringTable->insert(regionAttachment->path ? regionAttachment->path : attachment->name, true);
+			attachmentColor = &regionAttachment->color;
+
+			// Is slot invisible?
+			if (attachmentColor->a == 0) {
+				spSkeletonClipping_clipEnd(mSkeletonClipping.get(), slot);
+
+				if (pCollisionProxy && pCollisionProxy->mActive) {
+					pCollisionProxy->deActivate();
+				}
+				continue;
+			}
+
+			if (pCollisionProxy && !pCollisionProxy->mActive) {
+				pCollisionProxy->activate();
+			}
+
+			auto currentRegion = (spAtlasRegion *)regionAttachment->rendererObject;
+
+			spRegionAttachment_updateOffset(regionAttachment);
+			spRegionAttachment_setUVs(regionAttachment, currentRegion->u, currentRegion->v, currentRegion->u2, currentRegion->v2, currentRegion->rotate);
+			spRegionAttachment_computeWorldVertices(regionAttachment, slot->bone, vertices, 0, 2);
+
+			verticesCount = 4;
+			uvs = regionAttachment->uvs;
+			indices = quadIndices;
+			indicesCount = 6;
+		}
+		else if (attachment->type == SP_ATTACHMENT_MESH) {
+			auto meshAttachment = (spMeshAttachment*)attachment;
+			attachmentName = StringTable->insert(meshAttachment->path ? meshAttachment->path : attachment->name, true);
+
+			attachmentColor = &meshAttachment->color;
+
+			// Is slot invisible?
+			if (attachmentColor->a == 0) {
+				spSkeletonClipping_clipEnd(mSkeletonClipping.get(), slot);
+
+				if (pCollisionProxy && pCollisionProxy->mActive) {
+					pCollisionProxy->deActivate();
+				}
+				continue;
+			}
+
+			// Vertex buffer overrun?
+			if (meshAttachment->super.worldVerticesLength > BatchRender::maxVertexCount) {
+				Con::warnf("Mesh attachment '%s' exceeded vertex buffer size. Mesh count was %d. Buffer size is %d.\n",
+					attachmentName, meshAttachment->super.worldVerticesLength, BatchRender::maxVertexCount);
+				continue;
+			}
+
+			if (pCollisionProxy && !pCollisionProxy->mActive) {
+				pCollisionProxy->activate();
+			}
+
+			// Compute updated render info.
+			spVertexAttachment_computeWorldVertices(&meshAttachment->super, slot, 0, meshAttachment->super.worldVerticesLength, vertices, 0, 2);
+
+			verticesCount = meshAttachment->super.worldVerticesLength >> 1;
+			uvs = meshAttachment->uvs;
+			indices = meshAttachment->triangles;
+			indicesCount = meshAttachment->trianglesCount;
+		}
+		else if (attachment->type == SP_ATTACHMENT_CLIPPING) {
+			auto clippingAttachment = (spClippingAttachment*)attachment;
+			spSkeletonClipping_clipStart(mSkeletonClipping.get(), slot, clippingAttachment);
+			continue;
+		}
+		else continue;
+
+		// Perform clipping if active
+		if (spSkeletonClipping_isClipping(mSkeletonClipping.get())) {
+			spSkeletonClipping_clipTriangles(mSkeletonClipping.get(), vertices, verticesCount << 1, indices, indicesCount, uvs, 2);
+			vertices = mSkeletonClipping->clippedVertices->items;
+			verticesCount = mSkeletonClipping->clippedVertices->size >> 1;
+			uvs = mSkeletonClipping->clippedUVs->items;
+			indices = mSkeletonClipping->clippedTriangles->items;
+			indicesCount = mSkeletonClipping->clippedTriangles->size;
+		}
+
+		if (!verticesCount) {
+			// No geometry to display.
+			if (pCollisionProxy && pCollisionProxy->mActive) {
+				pCollisionProxy->deActivate();
+			}
+			continue;
+		}
+
+		if (!mSpineAsset->getPreMultipliedAlpha()) {
+			// Not using Premultiplied Alpha
+			switch (slot->data->blendMode) {
+			case SP_BLEND_MODE_ADDITIVE:
+				setSrcBlendFactor(GL_SRC_ALPHA);
+				setDstBlendFactor(GL_ONE);
+				break;
+			case SP_BLEND_MODE_MULTIPLY:
+				setSrcBlendFactor(GL_DST_COLOR);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_ALPHA);
+				break;
+			case SP_BLEND_MODE_SCREEN:
+				setSrcBlendFactor(GL_ONE);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_COLOR);
+				break;
+			case SP_BLEND_MODE_NORMAL:
+			default:
+				setSrcBlendFactor(GL_SRC_ALPHA);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_ALPHA);
+				break;
+			}
+		}
+		else {
+			// Setup for Premultiplied Alpha
+			switch (slot->data->blendMode) {
+			case SP_BLEND_MODE_ADDITIVE:
+				setSrcBlendFactor(GL_ONE);
+				setDstBlendFactor(GL_ONE);
+				break;
+			case SP_BLEND_MODE_MULTIPLY:
+				setSrcBlendFactor(GL_DST_COLOR);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_ALPHA);
+				break;
+			case SP_BLEND_MODE_SCREEN:
+				setSrcBlendFactor(GL_ONE);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_COLOR);
+				break;
+			case SP_BLEND_MODE_NORMAL:
+			default:
+				setSrcBlendFactor(GL_ONE);
+				setDstBlendFactor(GL_ONE_MINUS_SRC_ALPHA);
+				break;
+			}
+		}
+
+		// Define sprite carrier object.  NOTE: This isn't a Sprite. It's a SpriteBatchItem, which is completely different
+		// than a Sprite.  It's more like a render request headed for the batch renderer.
+		SpriteBatchItem* pSprite = SpriteBatch::createSprite();
+
+		pSprite->setDepth(mSceneLayerDepth);
+
+		pSprite->setSrcBlendFactor(mSrcBlendFactor);
+		pSprite->setDstBlendFactor(mDstBlendFactor);
+
+		F32 r = mSkeleton->color.r * slot->color.r * attachmentColor->r;
+		F32 g = mSkeleton->color.g * slot->color.g * attachmentColor->g;
+		F32 b = mSkeleton->color.b * slot->color.b * attachmentColor->b;
+		F32 a = mSkeleton->color.a * slot->color.a * attachmentColor->a;
+
+		spColor light;
+		light.r = r; light.g = g; light.b = b; light.a = a;
+
+		SpriteBatchItem::drawData *pDrawData = pSprite->getDrawData();
+		pDrawData->size(indicesCount);
+
+		spriteAABB.lowerBound.x = spriteAABB.upperBound.x = vertices[0];
+		spriteAABB.lowerBound.y = spriteAABB.upperBound.y = vertices[1];
+		if (mVertexEffect != NULL) {
+			vector<F32> vertexEffectUVs;
+			vector<spColor> vertexEffectColors;
+			for (int j = 0; j < verticesCount; j++) {
+				spColor vertexColor = light;
+				spColor dark;
+				dark.r = dark.g = dark.b = dark.a = 0;
+				int index = j << 1;
+				float x = vertices[index];
+				float y = vertices[index + 1];
+				float u = uvs[index];
+				float v = uvs[index + 1];
+				mVertexEffect->transform(mVertexEffect, &x, &y, &u, &v, &vertexColor, &dark);
+				vertices[index] = x;
+				vertices[index + 1] = y;
+				vertexEffectUVs.push_back(u);
+				vertexEffectUVs.push_back(v);
+				vertexEffectColors.push_back(vertexColor);
+			}
+
+			for (int j = 0; j < indicesCount; ++j) {
+				int index = indices[j] << 1;
+				F32 x = vertices[index];
+				F32 y = vertices[index + 1];
+				spColor vertexColor = vertexEffectColors[index >> 1];
+
+				pDrawData->vertexArray[j].Set(x, y);
+				pDrawData->textureArray[j].Set(vertexEffectUVs[index], vertexEffectUVs[index + 1]);
+				pDrawData->colorArray[j].red = vertexColor.r;
+				pDrawData->colorArray[j].green = vertexColor.g;
+				pDrawData->colorArray[j].blue = vertexColor.b;
+				pDrawData->colorArray[j].alpha = vertexColor.a;
+
+				spriteAABB.lowerBound.x = x < spriteAABB.lowerBound.x ? x : spriteAABB.lowerBound.x;
+				spriteAABB.lowerBound.y = y < spriteAABB.lowerBound.y ? y : spriteAABB.lowerBound.y;
+				spriteAABB.upperBound.x = x > spriteAABB.upperBound.x ? x : spriteAABB.upperBound.x;
+				spriteAABB.upperBound.y = y > spriteAABB.upperBound.y ? y : spriteAABB.upperBound.y;
+			}
+		}
+		else {
+			for (int j = 0; j < indicesCount; ++j) {
+				int index = indices[j] << 1;
+				F32 x = vertices[index];
+				F32 y = vertices[index + 1];
+
+				pDrawData->vertexArray[j].Set(vertices[index], vertices[index + 1]);
+				pDrawData->textureArray[j].Set(uvs[index], uvs[index + 1]);
+				pDrawData->colorArray[j].red = r;
+				pDrawData->colorArray[j].green = g;
+				pDrawData->colorArray[j].blue = b;
+				pDrawData->colorArray[j].alpha = a;
+
+				spriteAABB.lowerBound.x = x < spriteAABB.lowerBound.x ? x : spriteAABB.lowerBound.x;
+				spriteAABB.lowerBound.y = y < spriteAABB.lowerBound.y ? y : spriteAABB.lowerBound.y;
+				spriteAABB.upperBound.x = x > spriteAABB.upperBound.x ? x : spriteAABB.upperBound.x;
+				spriteAABB.upperBound.y = y > spriteAABB.upperBound.y ? y : spriteAABB.upperBound.y;
+			}
+		}
+
+		// Save the sprite's aabb on the sprite.
+		F32 ev[]{
+			spriteAABB.upperBound.x, spriteAABB.upperBound.y,	//LL
+			spriteAABB.lowerBound.x, spriteAABB.upperBound.y,	//LR
+			spriteAABB.lowerBound.x, spriteAABB.lowerBound.y,	//UR
+			spriteAABB.upperBound.x, spriteAABB.lowerBound.y };	//UL
+		pSprite->setExplicitVertices(ev);
+
+		pSprite->setTriangleRun(true);
+		pSprite->setImage(assetId, attachmentName.c_str());
+
+		spSkeletonClipping_clipEnd(mSkeletonClipping.get(), slot);
+
+		if (pCollisionProxy) {
+			// Center collision box on attachment.
+			pCollisionProxy->setPosition(
+				Vector2((spriteAABB.lowerBound.x + spriteAABB.upperBound.x) * 0.5f,
+				(spriteAABB.lowerBound.y + spriteAABB.upperBound.y) * 0.5f)
+			);
+			pCollisionProxy->setAngle(
+				mDegToRad(spBone_localToWorldRotation(slot->bone, slot->bone->rotation + pCollisionProxy->mRotation))
+			);
+		}
+
+		// Capture this sprite's vertices for OOBB calculation later.
+		pointSoup.insert(pointSoup.end(), pDrawData->vertexArray.begin(), pDrawData->vertexArray.end());
+	}
+
+	spSkeletonClipping_clipEnd2(mSkeletonClipping.get());
+
+	if (mVertexEffect)
+		mVertexEffect->end(mVertexEffect);
+
+	calculateSpineOOBB(pointSoup);
+}
+
+
+//-----------------------------------------------------------------------------
+// This spins through all of the spine object's drawn points and calculates its OOBB.
+// It then updates the location of the SceneObject to center it over the spine object.
+void SpineObject::calculateSpineOOBB(const vector<Vector2> pointSoup) {
+
+	if (!pointSoup.size()) {
+		setSize(Vector2(0.0f, 0.0f));
+		setLocalExtentsDirty();
+		updateLocalExtents();
+		return;
+	}
+
+	// First step is to get the AABB.
+	b2AABB oobb = getLocalAABB();
+
+	if (getAngle() == 0.0f) {
+		// The OOBB coincides with the AABB so we are done.
+		setSize(oobb.upperBound - oobb.lowerBound);
+	}
+	else {
+		// Second step is to rotate the soup about its center to axis align it and
+		// grab its AABB.
+		b2Rot rotation(-getAngle());
+		b2Transform t(oobb.GetCenter(), rotation);
+
+		b2Vec2 pp = CoreMath::mRotateAboutArbitraryPoint(t, pointSoup[0]);
+		oobb.lowerBound.Set(pp.x, pp.y);
+		oobb.upperBound.Set(pp.x, pp.y);
+		for (const auto& p : pointSoup) {
+			pp = CoreMath::mRotateAboutArbitraryPoint(t, p);
+			oobb.lowerBound.x = pp.x < oobb.lowerBound.x ? pp.x : oobb.lowerBound.x;
+			oobb.lowerBound.y = pp.y < oobb.lowerBound.y ? pp.y : oobb.lowerBound.y;
+			oobb.upperBound.x = pp.x > oobb.upperBound.x ? pp.x : oobb.upperBound.x;
+			oobb.upperBound.y = pp.y > oobb.upperBound.y ? pp.y : oobb.upperBound.y;
+		}
+
+		// We now have the updated AABB.  This is what the SceneObject needs, so 
+		// pass it in.
+		updateLocalExtents(&oobb);
+		setSize(oobb.upperBound - oobb.lowerBound);
+
+		// Third step is to complete calculation of the OOBB by aligning it back to 
+		// the spine object.
+		t.q.Set(getAngle());
+		oobb.lowerBound = CoreMath::mRotateAboutArbitraryPoint(t, oobb.lowerBound);
+		oobb.upperBound = CoreMath::mRotateAboutArbitraryPoint(t, oobb.upperBound);
+	}
+
+	// Reposition the SceneObject so that it is centered over the spine object.
+	Vector2 actualCenter = oobb.GetCenter();
+	Vector2 sceneObjectCenter = getPosition();
+
+	Vector2 delta = actualCenter - sceneObjectCenter;
+
+	// Nullify the reposition of the SceneObject by incorporating its inverse 
+	// into the spine object's position.
+	mAutoCenterOffset.x += delta.x;
+	mAutoCenterOffset.y += delta.y;
+
+	// Handle special case of the spine object being 'flipped' in either axis.  When
+	// that happens, we want to keep the location of the root bone at roughly the
+	// same position on screen as it was prior to the flip.  This helps to reduce 
+	// a jarring reposition of the root bone.
+	bool doFlipRecurse = false;
+
+	if (mPriorFlipX == mFlipX) {
+		mPriorRootBoneWorldX = mSkeleton->root->worldX;
+	}
+	else {
+		// Compensate for the flip in X (about the y axis).  This is an approximation
+		// that will fail if the velocity of the spine object is large.  If that 
+		// becomes a problem, incorporate the velocity delta into the 'prior world x'
+		// to have the compensated position reflect the underlying movement.
+		mPriorFlipX = mFlipX;
+		doFlipRecurse = true;
+
+		delta.x += mPriorRootBoneWorldX - mSkeleton->root->worldX;
+	}
+	if (mPriorFlipY == mFlipY) {
+		mPriorRootBoneWorldY = mSkeleton->root->worldY;
+	}
+	else {
+		mPriorFlipY = mFlipY;
+		doFlipRecurse = true;
+
+		delta.y += mPriorRootBoneWorldY - mSkeleton->root->worldY;
+	}
+
+	setPosition(sceneObjectCenter + delta);
+
+	if (doFlipRecurse) {
+		// Trash the current render data and recalculate it.  This avoids a flash
+		// artifact due to possibly large changes coming from the flip.
+		this->clearSprites();
+		updateSpine(mLastFrameTime);
+		prepareSpineForRender();
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+const SpineCollisionProxy* SpineObject::getCollisionProxy(
+	const char* anAttachmentName,
+	const char* aSlotName,
+	const char* aSkinName,
+	const F32 sizerWidth,
+	const F32 sizerHeight,
+	const char* anObjectName) {
+
+	// First, locate the requested attachment.
+	spAttachment* pAttachment = NULL;
+	auto attachmentName = StringTable->insert(anAttachmentName, true);
+
+	auto slotName = StringTable->insert(aSlotName, true);
+	auto pSlotData = spSkeletonData_findSlot(mSkeleton->data, slotName);
+	if (!pSlotData) {
+		Con::warnf("SpineObject::getCollisionProxy - Slot not found: '%s'.", slotName);
+		return NULL;
+	}
+
+	auto skinName = StringTable->insert(aSkinName, true);
+	if (skinName == StringTable->EmptyString || dStricmp(skinName, "default") == 0) {
+		// Look in the currently active skin and then the default skin if needed.
+		pAttachment = spSkeleton_getAttachmentForSlotIndex(mSkeleton.get(), pSlotData->index, attachmentName);
+		if (!pAttachment) {
+			Con::warnf("SpineObject::getCollisionProxy - Attachment not found: '%s'.", attachmentName);
+			return NULL;
+		}
+	}
+	else {
+		// Attachment must exist in the skin name given or else it's an error.
+		auto pSkin = spSkeletonData_findSkin(mSkeleton->data, skinName);
+		if (!pSkin) {
+			Con::warnf("SpineObject::getCollisionProxy - Skin not found: '%s'.", skinName);
+			return NULL;
+		}
+
+		pAttachment = spSkin_getAttachment(pSkin, pSlotData->index, attachmentName);
+		if (!pAttachment) {
+			Con::warnf("SpineObject::getCollisionProxy - Attachment not found in requested skin.\nskin: '%s'.  attachment: '%s'.", skinName, attachmentName);
+			return NULL;
+		}
+	}
+
+	// Check that the attachment is a supported type.
+	if (pAttachment->type != spAttachmentType::SP_ATTACHMENT_REGION && pAttachment->type != spAttachmentType::SP_ATTACHMENT_MESH) {
+		Con::warnf("SpineObject::getCollisionProxy - Attachment requested is of an unsupported type.  Only Region and Mesh attachments are supported.");
+		return NULL;
+	}
+
+	// objectName is not considered here.  Multiple proxies for the same attachment is 
+	// not supported.
+	auto itr = mCollisionProxies.find(pAttachment);
+	if (itr != mCollisionProxies.end()) {
+		return itr->value;
+	}
+
+	auto pBone = spSkeleton_findBone(mSkeleton.get(), pSlotData->boneData->name);
+	if (!pBone) {
+		Con::warnf("SpineObject::getCollisionProxy - Unable to find bone required by slot data: '%s'.", pSlotData->boneData->name);
+		return NULL;
+	}
+
+	// Create new proxy object.
+	const char *objectName = anObjectName ? StringTable->insert(anObjectName, true) : NULL;
+	auto pProxy = new SpineCollisionProxy(attachmentName, slotName, skinName, sizerWidth, sizerHeight, objectName);
+
+	// Add to the internal collection
+	mCollisionProxies.insert(pAttachment, pProxy);
+
+	// Initialize the proxy
+	F32 width, height = 0.0f;
+	if (pAttachment->type == SP_ATTACHMENT_REGION) {
+		auto regionAttachment = (spRegionAttachment*)pAttachment;
+
+		width = regionAttachment->width * regionAttachment->scaleX * spBone_getWorldScaleX(pBone) * sizerWidth;
+		height = regionAttachment->height * regionAttachment->scaleY * spBone_getWorldScaleY(pBone) * sizerHeight;
+
+		pProxy->mRotation = regionAttachment->rotation;
+	}
+	else {
+		auto meshAttachment = (spMeshAttachment*)pAttachment;
+
+		width = meshAttachment->width * spBone_getWorldScaleX(pBone) * sizerWidth;
+		height = meshAttachment->height * spBone_getWorldScaleY(pBone) * sizerHeight;
+
+		auto currentRegion = (spAtlasRegion *)meshAttachment->rendererObject;
+		pProxy->mRotation = currentRegion->rotate ? 90.0f : 0.0f;
+	}
+
+	// Set box location to a galaxy far far away... 
+	// NOTE: The box is auto-centered over the attachment at render.  
+	pProxy->setPosition(Vector2(5000, CoreMath::mGetRandomF(-5000.0, 5000.0)));
+
+	// Set layer and group membership to that of the owning spine object.
+	pProxy->setSceneGroup(getSceneGroup());
+	pProxy->setSceneLayer(getSceneLayer());
+
+	// Register the proxy object.  This adds it to the runtime environment.
+	if (objectName) {
+		if (!pProxy->registerObject(objectName)) {
+			return NULL;
+		}
+	}
+	else {
+		if (!pProxy->registerObject()) {
+			return NULL;
+		}
+	}
+
+	// Create collision fixture and enable collision callback support.
+	auto fixtureIndex = pProxy->createPolygonBoxCollisionShape(width * abs(mSkeleton->scaleX), height * abs(mSkeleton->scaleY));
+	pProxy->setCollisionShapeIsSensor(fixtureIndex, true);
+	pProxy->setCollisionCallback(true);
+
+	pProxy->setSleepingAllowed(false);
+
+	// Disable collision box from colliding against other collision boxes in the spine object's scene group.
+	// The intent is to stop a character's own collision boxes from setting each other off.  Different characters
+	// should be in different groups.  That's the idea.  Maybe, should just let all the contacts go through and let
+	// them be handled/ignored on the script side.
+	auto groupMask = pProxy->getCollisionGroupMask();
+	groupMask &= ~(1 << getSceneGroup()); // Clears bit in mask corresponding to the spine object's group.
+	pProxy->setCollisionGroupMask(groupMask);
+
+	// Deactivate.  If should be active, it will be made so at render time.
+	pProxy->deActivate();
+
+	// If Spine object is already in the scene, add the proxy too.
+	if (getScene()) {
+		getScene()->addToScene(pProxy);
+	}
+
+	return pProxy;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::deleteCollisionProxy(const char *proxyId) {
+
+	AssertFatal(proxyId != NULL, "SpineObject::deleteCollisionProxy() - Recieved NULL collision proxy object id.");
+
+	SimObjectId idToDelete = dAtoi(proxyId);
+
+	// Locate the requested object
+	for (const auto& i : mCollisionProxies) {
+		if (i.value->getId() == idToDelete) {
+			// Delete it
+			getScene()->removeFromScene(i.value);
+			i.value->deleteObject();
+
+			mCollisionProxies.erase(i.key);
+			return true;
+		}
+	}
+
+	Con::warnf("SpineObject::deleteCollisionProxy() - Unable to locate proxy with given id: '%s'.", proxyId);
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::writeAnimationData(void) const {
+	// According to the API, a track entry might be null.  So we need to make sure there is at least
+	// one valid entry before returning true.
+	for (auto i = 0; i < mAnimationState->tracksCount; ++i) {
+		if (mAnimationState->tracks[i] != NULL) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+
+const char *SpineObject::getAnimationData(void) const {
+	string result;
+	
+	for (auto i = 0; i < mAnimationState->tracksCount; ++i) {
+		spTrackEntry *track = mAnimationState->tracks[i];
+		if (track) {
+			// Encode the track entry.
+			result
+				.append(track->animation->name).append(";")
+				.append(Con::getIntArg(track->trackIndex)).append(";")
+				.append(Con::getBoolArg(track->loop)).append(";")
+				.append(Con::getFloatArg(track->mixDuration)).append(";~");
+		}
+	}
+
+	// Could throw it in the StringTable, but don't want to pollute that with this crud.
+	unique_ptr<char> retVal = unique_ptr<char>(new char[result.size() + 1]);
+	dStrcpy(retVal.get(), result.c_str());
+
+	return retVal.get();
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::setAnimationData(const char *animationData) {
+	if (!animationData) {
+		Con::warnf("SpineObject::setAnimationData() - Ignoring empty animation data string.");
+		return;
+	}
+
+	// Break into list of entries.
+	vector<char *> entries;
+	char *entry = dStrtok(const_cast<char *>(animationData), "~");
+	while (entry) {
+		entries.push_back(entry);
+		entry = dStrtok(NULL, "~");
+	}
+
+	// Process each entry
+	for (auto entry : entries) {
+		const char *name = dStrtok(entry, ";");
+		int track = dAtoi(dStrtok(NULL, ";"));
+		bool loop = dAtob(dStrtok(NULL, ";"));
+		F32 mixDuration = dAtof(dStrtok(NULL, ";"));
+
+		setAnimation(name, track, loop, mixDuration);
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+bool SpineObject::writeCollisionData(void) const {
+	return mCollisionProxies.size() > 0;
+}
+
+//-----------------------------------------------------------------------------
+
+const char *SpineObject::getCollisionData(void) const {
+	string result;
+
+	for (auto pair : mCollisionProxies) {
+		auto proxy = pair.value;
+
+		// Encode the proxy.
+		result
+			.append(proxy->mAttachmentName).append(";")
+			.append(proxy->mSlotName).append(";")
+			.append(proxy->mSkinName).append(";")
+			.append(Con::getFloatArg(proxy->mWidthSizer)).append(";")
+			.append(Con::getFloatArg(proxy->mHeightSizer)).append(";");
+
+		if (proxy->mObjectName) {
+			result.append(proxy->mObjectName).append(";~");
+		}
+		else {
+			result.append("~");
+		}
+	}
+
+	unique_ptr<char> retVal = unique_ptr<char>(new char[result.size() + 1]);
+	dStrcpy(retVal.get(), result.c_str());
+
+	return retVal.get();
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::setCollisionData(const char *collisionData) {
+	if (!collisionData) {
+		Con::warnf("SpineObject::setCollisionData() - Ignoring empty collision setup string.");
+		return;
+	}
+
+	// Break into list of entries.
+	vector<char *> entries;
+	char *entry = dStrtok(const_cast<char *>(collisionData), "~");
+	while (entry) {
+		entries.push_back(entry);
+		entry = dStrtok(NULL, "~");
+	}
+	
+	// Process each entry
+	for (auto entry : entries) {
+		const char *attachmentName = dStrtok(entry, ";");
+		const char *slotName = dStrtok(NULL, ";");
+		const char *skinName = dStrtok(NULL, ";");
+		F32 wSizer = dAtof(dStrtok(NULL, ";"));
+		F32 hSizer = dAtof(dStrtok(NULL, ";"));
+		const char *objectName = dStrtok(NULL, ";");
+
+		getCollisionProxy(attachmentName, slotName, skinName, wSizer, hSizer, objectName);
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::OnRegisterScene(Scene *scene) {
+	Parent::OnRegisterScene(scene);
+
+	for (auto i : mCollisionProxies) {
+		scene->addToScene(i.value);
+	}
+}
+
+//-----------------------------------------------------------------------------
+
+void SpineObject::OnUnregisterScene(Scene *scene) {
+	Parent::OnUnregisterScene(scene);
+
+	for (auto i : mCollisionProxies) {
+		if(i.value->getScene())
+			i.value->getScene()->removeFromScene(i.value);
+	}
+}

+ 315 - 0
engine/source/2d/sceneobject/SpineObject.h

@@ -0,0 +1,315 @@
+//-----------------------------------------------------------------------------
+// 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 _SPINE_OBJECT_H_
+#define _SPINE_OBJECT_H_
+
+#ifndef _FRAMEALLOCATOR_H_
+#include "memory/frameAllocator.h"
+#endif
+
+#ifndef _SPRITE_BATCH_H_
+#include "2d/core/SpriteBatch.h"
+#endif
+
+#ifndef _SCENE_OBJECT_H_
+#include "2d/sceneobject/SceneObject.h"
+#endif
+
+#ifndef _SPINE_ASSET_H_
+#include "2d/assets/SpineAsset.h"
+#endif
+
+#ifndef _SPINE_COLLISION_PROXY_H_
+#include "2d/sceneobject/SpineCollisionProxy.h"
+#endif
+
+//------------------------------------------------------------------------------
+// Spine events support
+static void spineAnimationEventCallbackHandler(spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event);
+
+//------------------------------------------------------------------------------
+
+static const b2Transform B2_IDENTITY_TRANSFORM = b2Transform(b2Vec2(0.0f, 0.0f), b2Rot(0.0f));
+
+class SpineObject : public SceneObject, public SpriteBatch
+{
+protected:
+	typedef SceneObject Parent;
+
+public:
+	// Smart pointer support
+	struct SkeletonDeleter { void operator()(spSkeleton* p) { spSkeleton_dispose(p); } };
+	struct AnimationStateDeleter { void operator()(spAnimationState* p) { p->listener = NULL; spAnimationState_disposeStatics(); spAnimationState_dispose(p); } };
+	struct SkeletonClippingDeleter { void operator()(spSkeletonClipping* p) { spSkeletonClipping_dispose(p); } };
+	struct SkeletonBoundsDeleter { void operator()(spSkeletonBounds* p) { spSkeletonBounds_dispose(p); } };
+	struct JitterVertexDeleter { void operator()(spJitterVertexEffect* p) { spJitterVertexEffect_dispose(p); } };
+	struct SwirlVertexDeleter { void operator()(spSwirlVertexEffect* p) { spSwirlVertexEffect_dispose(p); } };
+
+	using skeleton_ptr = unique_ptr<spSkeleton, SkeletonDeleter>;
+	using animationState_ptr = unique_ptr<spAnimationState, AnimationStateDeleter>;
+	using skeletonClipping_ptr = unique_ptr<spSkeletonClipping, SkeletonClippingDeleter>;
+	using skeletonBounds_ptr = unique_ptr<spSkeletonBounds, SkeletonBoundsDeleter>;
+	using jitterEffect_ptr = unique_ptr<spJitterVertexEffect, JitterVertexDeleter>;
+	using swirlEffect_ptr = unique_ptr<spSwirlVertexEffect, SwirlVertexDeleter>;
+
+	// Can't use smart pointers for this because HashTable calls delete on the value members in its destructor.
+	using SpineCollisionProxyMapType = HashMap<spAttachment*, SpineCollisionProxy*>;
+
+	enum VertexEffect {
+		INVALID_VERTEX_EFFECT,
+
+		NONE,
+		JITTER,
+		SWIRL
+	};
+private:
+	AssetPtr<SpineAsset>			mSpineAsset; /* SpineObject holds instance data, SpineAsset holds template data. */
+
+	skeleton_ptr					mSkeleton;
+	animationState_ptr				mAnimationState;
+	skeletonClipping_ptr			mSkeletonClipping;
+	skeletonBounds_ptr				mSkeletonBounds;
+
+	// Special vertex effects provided by Spine
+	spVertexEffect					*mVertexEffect;  // Only one effect can be active at a time. This points to it. Null if none active.
+	VertexEffect					mActiveEffect;
+	jitterEffect_ptr				mJitterControl;
+	swirlEffect_ptr					mSwirlControl;
+
+	F32               mPreTickTime;
+	F32               mPostTickTime;
+	F32               mLastFrameTime;
+
+	bool              mFlipX;
+	bool              mFlipY;
+
+	// OOBB calculation support
+	F32				  mPriorRootBoneWorldX;
+	F32				  mPriorRootBoneWorldY;
+	bool			  mPriorFlipX;
+	bool			  mPriorFlipY;
+
+	// Auto-Center support
+	Vector2			  mAutoCenterOffset;
+
+	// Collision support
+	SpineCollisionProxyMapType mCollisionProxies;
+
+public:
+	SpineObject() { resetState(); };
+
+	// Use CopyTo() if need to replicate.
+	SpineObject(const SpineObject&) = delete;
+	SpineObject& SpineObject::operator=(const SpineObject&) = delete;
+
+	// Add 'move' support if/when needed.
+	SpineObject(SpineObject&& other) = delete;
+	SpineObject& SpineObject::operator=(SpineObject&&) = delete;
+
+	virtual void copyTo(SimObject* object);
+
+	bool setSpineAsset(const char* pSpineAssetId);
+	inline StringTableEntry getSpineAsset(void) const { return mSpineAsset.getAssetId(); }
+
+	// Render flipping.
+	void setFlip(const bool flipX, const bool flipY);
+	void setFlipX(const bool flipX) { setFlip(flipX, mFlipY); }
+	void setFlipY(const bool flipY) { setFlip(mFlipX, flipY); }
+	inline bool getFlipX(void) const { return mFlipX; }
+	inline bool getFlipY(void) const { return mFlipY; }
+
+	// Render special effects
+	inline VertexEffect getActiveEffect(void) const { return mActiveEffect; }
+
+	// -- Jitter
+	void enableJitter(const F32 x, const F32 y);
+	void disableJitter(void);
+	// -- These can be used by script at run time to vary the effect.
+	inline F32 getJitterX(void) const { return mJitterControl ? mJitterControl->jitterX : 0.0f; }
+	inline void setJitterX(const F32 x) { if (mJitterControl) mJitterControl->jitterX = x; }
+	inline F32 getJitterY(void) const { return mJitterControl ? mJitterControl->jitterY : 0.0f; }
+	inline void setJitterY(const F32 y) { if (mJitterControl) mJitterControl->jitterY = y; }
+
+	// -- Swirl
+	void enableSwirl(const F32 radius);
+	void disableSwirl(void);
+	// -- These can be used by script at run time to vary the effect.
+	inline F32 getSwirlX(void) const { return mSwirlControl ? mSwirlControl->centerX : 0.0f; }
+	inline void setSwirlX(const F32 x) { if (mSwirlControl) mSwirlControl->centerX = x; }
+	inline F32 getSwirlY(void) const { return mSwirlControl ? mSwirlControl->centerY : 0.0f; }
+	inline void setSwirlY(const F32 y) { if (mSwirlControl) mSwirlControl->centerY = y; }
+	inline F32 getSwirlRadius(void) const { return mSwirlControl ? mSwirlControl->radius : 0.0f; }
+	inline void setSwirlRadius(const F32 r) { if (mSwirlControl) mSwirlControl->radius = r; }
+	inline F32 getSwirlAngle(void) const { return mSwirlControl ? mSwirlControl->angle : 0.0f; }
+	inline void setSwirlAngle(const F32 a) { if (mSwirlControl) mSwirlControl->angle = a; }
+
+	// Appearance
+	void setScale(const Vector2& scale);
+	inline void setScale(const F32 x, const F32 y) { setScale(Vector2(x, y)); }
+	inline Vector2 getScale(void) const { return mSkeleton ? Vector2(mSkeleton->scaleX, mSkeleton->scaleY) : Vector2(0.0f, 0.0f); }
+
+	bool setSkin(const char* pSkin);
+	inline StringTableEntry getSkinName(void) const;
+
+	// Animation
+	inline F32 setTimeScale(const F32 timeScale);
+	inline F32 getTimeScale(void) const { return mAnimationState ? mAnimationState->timeScale : 0.0f; }
+
+	bool setAnimation(const char* pName, const int track = 0, const bool shouldLoop = false, const F32 mixDuration = -1.0f);
+	bool setEmptyAnimation(const int track = 0, const F32 mixDuration = 0.0f);
+	bool queueAnimation(const char* pName, const int track = 0, const bool shouldLoop = false, const F32 mixDuration = -1.0f, const F32 delay = 0.0f);
+	bool queueEmptyAnimation(const int track = 0, const F32 mixDuration = 0.0f, const F32 delay = 0.0f);
+	void clearAnimations(const int track, const bool mixToSetupPose = false, const F32 mixDuration = 0.0f);
+	void clearAllAnimations(const bool mixToSetupPose = false, const F32 mixDuration = 0.0f);
+	StringTableEntry getAnimationName(const int track = 0) const;
+	bool getIsLooping(const int track = 0) const;
+	bool setMix(const char* pFromName, const char* pToName, const F32 mixDuration);
+
+	// Events
+	void SpineObject::enableEventCallbacks(void);
+	void SpineObject::disableEventCallbacks(void);
+
+	// Collision Support
+	const SpineCollisionProxy* getCollisionProxy(
+		const char* anAttachmentName,
+		const char* aSlotName,
+		const char* aSkinName = "default",
+		const F32 sizerWidth = 1.0f,
+		const F32 sizerHeight = 1.0f,
+		const char* objectName = NULL);
+	bool deleteCollisionProxy(const char *proxyId);
+
+	// This needs to be available to the Console for use during object instantiation.
+	static void initPersistFields();
+
+	/// Declare Console Object.
+	DECLARE_CONOBJECT(SpineObject);
+
+protected:
+	// Render suport
+	void updateSpine(const F32 time);
+	void prepareSpineForRender();
+	void calculateSpineOOBB(const vector<Vector2> pointSoup);
+
+	virtual void preIntegrate(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats);
+	virtual void interpolateObject(const F32 timeDelta);
+
+	virtual bool canPrepareRender(void) const { return true; }
+	virtual bool validRender(void) const { return mSpineAsset.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);
+
+	// Render special effects - support
+	// Set indirectly via enable methods.  However, need this to support TAML reading of object.
+	void setActiveEffect(const VertexEffect e);
+
+	static VertexEffect getVertexEffectTypeEnum(const char* label);
+	static const char* getVertexEffectTypeDescription(const VertexEffect vertexEffectType);
+
+	// Internal management
+	void SpineObject::resetState();
+
+	virtual void OnRegisterScene(Scene *scene);
+	virtual void OnUnregisterScene(Scene *scene);
+
+private:
+	// Utility 
+
+	// Cope with spine reflecting about an axis to accomplish a flip, while the SceneObject doesn't support such flipping.
+	inline F32 setPerFlipState(const F32 value) { return mFlipY ? (mFlipX ? value : -value) : (mFlipX ? -value : value); }
+
+	// Object Persistence Support
+	//
+	// This determines if there is any animation data to write and returns true if there is.
+	bool writeAnimationData(void) const;
+	bool writeCollisionData(void) const;
+
+	// This encodes and returns the information required to restart the currently running animations.  It is returned
+	// in a string for writing to the TAML file.
+	const char *getAnimationData(void) const;
+
+	// This encodes and returns the information required to recreate the Spine object's collision boxes.  
+	const char *getCollisionData(void) const;
+
+	// This attempts to start the animation(s) defined in the animation data string passed in.
+	void setAnimationData(const char *animationData);
+
+	// This attempts to create the collision boxes defined in the data passed in.
+	void setCollisionData(const char *collisionData);
+
+protected:
+	static bool setSpineAsset(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSpineAsset(data); return false; }
+	static bool writeSpineAsset(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->mSpineAsset.notNull(); }
+
+	static bool setAnimationData(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setAnimationData(data); return false; }
+	static const char* getAnimationData(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getAnimationData(); }
+	static bool writeAnimationData(void*obj, const char* data) { return static_cast<SpineObject*>(obj)->writeAnimationData(); }
+
+	static bool setCollisionData(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setCollisionData(data); return false; }
+	static const char* getCollisionData(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getCollisionData(); }
+	static bool writeCollisionData(void*obj, const char* data) { return static_cast<SpineObject*>(obj)->writeCollisionData(); }
+
+	static bool setSkin(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSkin(data); return false; }
+	static const char* getSkinName(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getSkinName(); }
+	static bool writeCurrentSkin(void*obj, StringTableEntry pSkin) { return true; }
+
+	static bool setScale(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setScale(Vector2(data)); return false; }
+	static const char* getScale(void* obj, const char* data) { return static_cast<SpineObject*>(obj)->getScale().scriptThis(); }
+	static bool writeScale(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getScale().notZero(); }
+
+	static bool setFlipX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setFlipX(dAtob(data)); return false; }
+	static bool writeFlipX(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getFlipX() == true; }
+
+	static bool setFlipY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setFlipY(dAtob(data)); return false; }
+	static bool writeFlipY(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getFlipY() == true; }
+
+	static bool setTimeScale(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setTimeScale(dAtof(data)); return false; }
+	static const char* getTimeScale(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getTimeScale()); }
+	static bool writeTimeScale(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getTimeScale() != 1.0f; }
+
+	static bool setActiveEffectType(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setActiveEffect(getVertexEffectTypeEnum(data)); return false; }
+	static bool writeActiveEffectType(void* obj, StringTableEntry pFieldName) { VertexEffect ve = static_cast<SpineObject*>(obj)->getActiveEffect(); return ve != NONE && ve != INVALID_VERTEX_EFFECT; }
+
+	static bool setJitterX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setJitterX(dAtof(data)); return false; }
+	static const char* getJitterX(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getJitterX()); }
+	static bool setJitterY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setJitterY(dAtof(data)); return false; }
+	static const char* getJitterY(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getJitterY()); }
+	static bool writeJitterEffectValues(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getActiveEffect() == VertexEffect::JITTER; }
+
+	static bool setSwirlX(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlX(dAtof(data)); return false; }
+	static const char* getSwirlX(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlX()); }
+	static bool setSwirlY(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlY(dAtof(data)); return false; }
+	static const char* getSwirlY(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlY()); }
+	static bool setSwirlRadius(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlRadius(dAtof(data)); return false; }
+	static const char* getSwirlRadius(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlRadius()); }
+	static bool setSwirlAngle(void* obj, const char* data) { static_cast<SpineObject*>(obj)->setSwirlAngle(dAtof(data)); return false; }
+	static const char* getSwirlAngle(void* obj, const char* data) { return Con::getFloatArg(static_cast<SpineObject*>(obj)->getSwirlAngle()); }
+	static bool writeSwirlEffectValues(void* obj, StringTableEntry pFieldName) { return static_cast<SpineObject*>(obj)->getActiveEffect() == VertexEffect::SWIRL; }
+
+	static bool setEventCallbacksEnabled(void* obj, const char* data) { if (dAtob(data)) { static_cast<SpineObject*>(obj)->enableEventCallbacks(); } else { static_cast<SpineObject*>(obj)->disableEventCallbacks(); } return false; }
+	static bool writeEventCallbacksEnabled(void* obj, StringTableEntry pFieldName) { SpineObject *me = static_cast<SpineObject*>(obj); return me->mAnimationState && me->mAnimationState->listener; }
+
+};
+
+#endif // _SPINE_OBJECT_H_

+ 682 - 0
engine/source/2d/sceneobject/SpineObject_ScriptBinding.h

@@ -0,0 +1,682 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(SpineObject, SceneObject)
+
+/*! Sets the spine asset Id to use.
+	@param spineAssetId Integer - The spine asset Id to use.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSpineAsset, ConsoleVoid, 3, 3, (int spineAssetId))
+{
+	object->setSpineAsset(argv[2]);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the spine asset Id.
+	@return Integer - The spine asset Id.
+*/
+ConsoleMethodWithDocs(SpineObject, getSpineAsset, ConsoleString, 2, 2, ())
+{
+	return object->getSpineAsset();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the animation time scale factor.
+	@param timeScale Float - The factor by which to multiply the base time scale as
+	set in the animation.
+	@return Float - The previous value of the time scale.
+*/
+ConsoleMethodWithDocs(SpineObject, setTimeScale, ConsoleFloat, 3, 3, (float timeScale))
+{
+	return object->setTimeScale(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the animation time scale.
+	@return Float - The current animation time factor.
+*/
+ConsoleMethodWithDocs(SpineObject, getTimeScale, ConsoleFloat, 2, 2, ())
+{
+	return object->getTimeScale();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the animation for the object.
+	@param animationName String - containing animation name to run.
+	@param track Int - Optional. Track to run animation in.  Defaults to zero.
+	@param loop Bool - Optional.  Determines whether the animation should loop. Defaults to false.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition (or mix) from the
+	previously running animation to this one being set.  If not set, it defaults to the value set
+	using the setMix() method.  If nothing was defined via setMix, then it defaults to zero, which means
+	no transition, an abrupt change.
+	@return Return Bool - True on success.
+*/
+ConsoleMethodWithDocs(SpineObject, setAnimation, ConsoleBool, 3, 6, (char *animationName, [int track, bool loop, float mixDuration]))
+{
+	// Determine looping
+	int track = argc >= 4 ? dAtoi(argv[3]) : 0;
+	bool shouldLoop = argc >= 5 ? dAtob(argv[4]) : false;
+	F32 mixDuration = argc >= 6 ? dAtof(argv[5]) : -1.0f;
+	return object->setAnimation(argv[2], track, shouldLoop, mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the empty animation on the object.  This is mainly used to fade into and out of the pose
+	position, but can be used for whatever.
+	@param track Int - Optional. Track to run animation in.  Defaults to zero.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition from the
+	currently running animation to this one.
+	@return Return Bool - True on success.
+*/
+ConsoleMethodWithDocs(SpineObject, setEmptyAnimation, ConsoleBool, 2, 4, ([int track, float mixDuration]))
+{
+	int track = argc >= 3 ? dAtoi(argv[2]) : 0;
+	F32 mixDuration = argc >= 4 ? dAtof(argv[3]) : 0.0f;
+	return object->setEmptyAnimation(track, mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Queues the animation for the object.  The queued animation will play after the currently
+	playing	animation completes.
+	@param animationName String - Contains the name of the animation to queue.
+	@param track Int - Optional. Track to run in.  Defaults to zero.  Animations can be layered in
+	different tracks.
+	@param loop Boolean - Optional. Indicates if animation should loop once it's processed.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition from the
+	currently running animation to this one.
+	@param delay Float - Optional.  Indicates a lag (leading or trailing) between this and
+	the currently running animation.  In seconds.
+	@return Returns Bool - True on success.
+*/
+ConsoleMethodWithDocs(SpineObject, queueAnimation, ConsoleBool, 3, 7, (char *animationName, [int track, bool loop, float mixDuration, float delay]))
+{
+	int track = argc >= 4 ? dAtoi(argv[3]) : 0;
+	bool shouldLoop = argc >= 5 ? dAtob(argv[4]) : false;
+	F32 mixDuration = argc >= 6 ? dAtof(argv[5]) : -1.0f;
+	F32 delay = argc >= 7 ? dAtof(argv[6]) : 0.0f;
+	return object->queueAnimation(argv[2], track, shouldLoop, mixDuration, delay);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Queues the empty animation on the object.  Useful for fading and transitions.
+	@param track Int - Optional. Track to run animation in.  Defaults to zero.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition from the
+	currently running animation to this one.
+	@param delay Float - Optional.  Indicates a lag (leading or trailing) between this and
+	the currently running animation.  In seconds.  Defaults to zero.
+	@return Return Bool - True on success.
+*/
+ConsoleMethodWithDocs(SpineObject, queueEmptyAnimation, ConsoleBool, 2, 5, ([int track, float mixDuration, float delay]))
+{
+	int track = argc >= 3 ? dAtoi(argv[2]) : 0;
+	F32 mixDuration = argc >= 4 ? dAtof(argv[3]) : 0.0f;
+	F32 delay = argc >= 5 ? dAtof(argv[4]) : 0.0f;
+	return object->queueEmptyAnimation(track, mixDuration, delay);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Clears animations (running and queued) from the given track.
+	@param track Int - Optional. Track to clear animations from.  Defaults to zero.
+	@param mixToSetup Bool - Optional. If true the track will fade back to the setup pose
+	over the number of seconds specified in the mixDuration argument.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition back to
+	the setup pose.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, clearAnimations, ConsoleVoid, 2, 5, ([int track, bool mixToSetup, float mixDuration]))
+{
+	int track = argc >= 3 ? dAtoi(argv[2]) : 0;
+	bool mixToSetup = argc >= 4 ? dAtob(argv[3]) : false;
+	F32 mixDuration = argc >= 5 ? dAtof(argv[4]) : 0.0f;
+	object->clearAnimations(track, mixToSetup, mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Clears animations (running and queued) from all tracks.
+	@param mixToSetup Bool - Optional. If true the character will fade back to the setup pose
+	over the number of seconds specified in the mixDuration argument.
+	@param mixDuration Float - Optional.  The amount of time in seconds to transition back to
+	the setup pose.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, clearAllAnimations, ConsoleVoid, 2, 4, ([bool mixToSetup, float mixDuration]))
+{
+	bool mixToSetup = argc >= 3 ? dAtob(argv[2]) : false;
+	F32 mixDuration = argc >= 4 ? dAtof(argv[3]) : 0.0f;
+	object->clearAllAnimations(mixToSetup, mixDuration);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the name of the animation currently running in the given track.
+	@param track Int - Optional. Track to get name from.  Defaults to zero.
+	@return String - Contains the animation name.
+*/
+ConsoleMethodWithDocs(SpineObject, getAnimationName, ConsoleString, 2, 3, ([int track]))
+{
+	int track = argc >= 3 ? dAtoi(argv[2]) : 0;
+	return object->getAnimationName(track);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Check if the animation currently running on the given track is looping.
+	@param track Int - Optional. Track to check.  Defaults to zero.
+	@return Bool - True if current animation is looping.  False if there is no animation
+	running or there is but it is not looping.
+*/
+ConsoleMethodWithDocs(SpineObject, getIsLooping, ConsoleBool, 2, 3, ([int track]))
+{
+	int track = argc >= 3 ? dAtoi(argv[2]) : 0;
+	return object->getIsLooping(track);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the animation mix time to be used when transitioning between two
+	animations.  This is the amount of time that will be spent morphing
+	between the from and to animations.
+	@param fromAnimation String - The name of the animation transitioning from.
+	@param toAnimation String - The name of the animation transitioning to.
+	@param mixDuration Float - The number of seconds to spend in the transition.
+	@return Returns Bool - True on success.
+*/
+ConsoleMethodWithDocs(SpineObject, setMix, ConsoleBool, 5, 5, (char *fromAnimation, char *toAnimation, float mixDuration))
+{
+	Con::printf("Mixing %s with %s at %f", argv[2], argv[3], dAtof(argv[4]));
+
+	return object->setMix(argv[2], argv[3], dAtof(argv[4]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the skin for the spine object.
+	@param skinName String - Name of the skin (as defined in the animation data) to apply.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSkin, ConsoleVoid, 3, 3, (char *skinName))
+{
+	object->setSkin(argv[2]);
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the name of the skin currently applied to the spine object.
+	@return String - The currently applied skin name.
+*/
+ConsoleMethodWithDocs(SpineObject, getSkinName, ConsoleString, 2, 2, ())
+{
+	return object->getSkinName();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets scaling of the spine object's skeleton.
+	@param scaleX Float - X factor.
+	@param scaleY Float - Y factor.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setScale, ConsoleVoid, 3, 4, (float scaleX, float scaleY))
+{
+	F32 scaleX, scaleY;
+
+	const U32 elementCount = Utility::mGetStringElementCount(argv[2]);
+
+	// ("width height")
+	if ((elementCount == 2) && (argc == 3))
+	{
+		scaleX = dAtof(Utility::mGetStringElement(argv[2], 0));
+		scaleY = dAtof(Utility::mGetStringElement(argv[2], 1));
+	}
+
+	// (width, [height])
+	else if (elementCount == 1)
+	{
+		scaleX = dAtof(argv[2]);
+
+		if (argc > 3)
+			scaleY = dAtof(argv[3]);
+		else
+			scaleY = scaleX;
+	}
+
+	// Invalid
+	else
+	{
+		Con::warnf("SpineObject::setScale() - Invalid number of parameters!");
+		return;
+	}
+
+	// Set Scale.
+	object->setScale(Vector2(scaleX, scaleY));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the spine object's skeleton scale.
+	@return (float x/y height) The x and y scale of the object's root bone.
+*/
+ConsoleMethodWithDocs(SpineObject, getScale, ConsoleString, 2, 2, ())
+{
+	return object->getScale().scriptThis();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets the sprite texture flipping for each axis.
+	@param flipX Bool - Whether or not to flip the texture along the x (horizontal) axis.
+	@param flipY Bool - Whether or not to flip the texture along the y (vertical) axis.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setFlip, ConsoleVoid, 4, 4, (bool flipX, bool flipY))
+{
+	// Set Flip.
+	object->setFlip(dAtob(argv[2]), dAtob(argv[3]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets the flip for each axis.
+	@return (bool flipX/bool flipY) Whether or not the texture is flipped along the x and y axes.
+*/
+ConsoleMethodWithDocs(SpineObject, getFlip, ConsoleString, 2, 2, ())
+{
+	// Create Returnable Buffer.
+	char* pBuffer = Con::getReturnBuffer(32);
+
+	// Format Buffer.
+	dSprintf(pBuffer, 32, "%d %d", object->getFlipX(), object->getFlipY());
+
+	// Return Buffer.
+	return pBuffer;
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets whether or not the texture is flipped horizontally.
+	@param flipX Bool - Whether or not to flip the texture along the x (horizontal) axis.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setFlipX, ConsoleVoid, 3, 3, (bool flipX))
+{
+	// Set Flip.
+	object->setFlipX(dAtob(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Sets whether or not the texture is flipped vertically.
+	@param flipY Bool - Whether or not to flip the texture along the y (vertical) axis.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setFlipY, ConsoleVoid, 3, 3, (bool flipY))
+{
+	// Set Flip.
+	object->setFlipY(dAtob(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets whether or not the texture is flipped horizontally.
+	@return (bool flipX) Whether or not the texture is flipped along the x axis.
+*/
+ConsoleMethodWithDocs(SpineObject, getFlipX, ConsoleBool, 2, 2, ())
+{
+	return object->getFlipX();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Gets whether or not the texture is flipped vertically.
+	@return (bool flipY) Whether or not the texture is flipped along the y axis.
+*/
+ConsoleMethodWithDocs(SpineObject, getFlipY, ConsoleBool, 2, 2, ())
+{
+	return object->getFlipY();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Enables the Jitter special effect
+	@param JitterX Float - A special effect control parameter.
+	@param JitterY Float - A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, enableJitter, ConsoleVoid, 4, 4, (float x, float y))
+{
+	// Enable the special effect
+	object->enableJitter(dAtof(argv[2]), dAtof(argv[3]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Jitter X control value.
+	@param X - Float A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setJitterX, ConsoleVoid, 3, 3, (float x))
+{
+	// Enable the special effect
+	object->setJitterX(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Jitter X control value.
+	@return The current Jitter effect X control value.  If the Jitter effect is not or
+	has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getJitterX, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getJitterX();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Jitter Y control value.
+	@param Y Float - A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setJitterY, ConsoleVoid, 3, 3, (float y))
+{
+	// Enable the special effect
+	object->setJitterY(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Jitter Y control value.
+	@return The current Jitter effect Y control value.  If the Jitter effect is not
+	or has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getJitterY, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getJitterY();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Disables the Jitter special effect.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, disableJitter, ConsoleVoid, 2, 2, ())
+{
+	return object->disableJitter();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Enables the Swirl special effect
+	@param Radius Float - In degrees.  A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, enableSwirl, ConsoleVoid, 3, 3, (float radius))
+{
+	// Enable the special effect
+	object->enableSwirl(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Swirl X control value.
+	@param X Float - A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSwirlX, ConsoleVoid, 3, 3, (float x))
+{
+	// Enable the special effect
+	object->setSwirlX(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Swirl X control value.
+	@return The current Swirl effect X control value.  If the Swirl effect is not
+	or has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getSwirlX, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getSwirlX();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Swirl Y control value.
+	@param Y Float - A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSwirlY, ConsoleVoid, 3, 3, (float y))
+{
+	// Enable the special effect
+	object->setSwirlY(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Swirl Y control value.
+	@return The current Swirl effect Y control value.  If the Swirl effect is not
+	or has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getSwirlY, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getSwirlY();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Swirl Radius control value.
+	@param Radius Float - A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSwirlRadius, ConsoleVoid, 3, 3, (float radius))
+{
+	// Enable the special effect
+	object->setSwirlRadius(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Swirl Radius control value.
+	@return The current Swirl effect Radius control value.  If the Swirl effect is not
+	or has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getSwirlRadius, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getSwirlRadius();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Set the Swirl Angle control value.
+	@param Angle Float - In degrees.  A special effect control parameter.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, setSwirlAngle, ConsoleVoid, 3, 3, (float radius))
+{
+	// Enable the special effect
+	object->setSwirlAngle(dAtof(argv[2]));
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Get the Swirl Angle control value.
+	@return The current Swirl effect Angle control value.  If the Swirl effect is not
+	or has not been enabled, it will return zero.
+*/
+ConsoleMethodWithDocs(SpineObject, getSwirlAngle, ConsoleFloat, 2, 2, ())
+{
+	// Enable the special effect
+	return object->getSwirlAngle();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Disables the Swirl special effect.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, disableSwirl, ConsoleVoid, 2, 2, ())
+{
+	return object->disableSwirl();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Enables animation event callbacks.
+	After calling this method, your SpineObject instance will begin to receive animation lifecycle callbacks.
+	This includes events defined within the animation when it was created.  Those embedded events will arrive
+	in the 'onAnimationEvent' callback, where '%eventName' will indicate which particular event occurred.
+
+@note The onAnimationEvent callback comes with a large number of arguments.  These correspond in large part to
+	  the attributes that can be defined for the event inside Spine's animation editor.  It is safe to ignore
+	  them if not needed.
+
+	The following code block shows every available event callback method.  It is okay to define handlers for only
+	those events of interest, though enabling callbacks and not defining any would just be a waste.  More likely
+	would be to remove the last callback at some future time and forget to disable them.
+
+	@code
+	function SpineObject::onAnimationStart(%this, %animationName, %animationTrack){
+		echo("SpineObject received onAnimationStart: "@%animationName);
+	}
+
+	function SpineObject::onAnimationInterrupt(%this, %animationName, %animationTrack){
+		echo("SpineObject received onAnimationInterrupt: "@%animationName);
+	}
+
+	function SpineObject::onAnimationEnd(%this, %animationName, %animationTrack){
+		echo("SpineObject received onAnimationEnd: "@%animationName);
+	}
+
+	function SpineObject::onAnimationComplete(%this, %animationName, %animationTrack){
+		echo("SpineObject received onAnimationComplete: "@%animationName);
+	}
+
+	function SpineObject::onAnimationDispose(%this, %animationName, %animationTrack){
+		echo("SpineObject received onAnimationDispose: "@%animationName);
+	}
+
+	function SpineObject::onAnimationEvent(%this, %animationName, %animationTrack, %eventName, %intArg, %floatArg, %stringArg, %time, %volume, %balance){
+		echo("SpineObject received onAnimationEvent:" SPC %animationName SPC %eventName);
+		if(%eventName $= "footstep"){
+			alxPlay("GameAssets:KnightFootstep");
+		}
+	}
+	@endcode
+
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, enableAnimationEventCallbacks, ConsoleVoid, 2, 2, ())
+{
+	object->enableEventCallbacks();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Disables animation event callbacks.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(SpineObject, disableAnimationEventCallbacks, ConsoleVoid, 2, 2, ())
+{
+	object->disableEventCallbacks();
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Retrieve a collision proxy object.  This is a scene object that wraps a collsion box centered on
+	a spine attachment.  Since it's a SceneObject, it can then be manipulated/used for collision
+	processing in onCollision etc... This first checks if the attachment requested already has a proxy
+	and returns that if so.  If not, a new proxy is created and returned.
+	@note
+	The collision objects never have any velocity.  They are continually positioned (warped) to match
+	the location of the attachment they were created on.  This means that they are only useful as
+	sensors.  Even if they are not explicitly set to be sensors, since they have no velocity, they
+	don't trigger an impulse or other response.
+
+	@note
+	The generated collision proxy is assigned to the same group and layer as the parent spine object.
+	In addition, its collision mask is configured to disable collisions with all other collision boxes
+	in that same group.  The intent is to prevent collisions between attachements on the same spine
+	object.  Therefore, for different spine objects to collide, they should be assigned to different
+	scene groups.  However, if needed, the settings on the returned proxy may be changed by making the
+	appropriate	calls.
+
+	@param AttachmentName String - The spine attachment name that the new proxy should wrap.
+	@param SlotName String - The slot name that the new proxy should wrap.  The slot and attachment
+	names form a compound key.  Both are required to identify the attachment to get a collision
+	box for.
+	@param SkinName String Optional - The skin in which to search for the specified attachment name.
+	If given, then only that skin will be searched for the attachment, and creation will fail if it is not
+	found.  If this parameter is not given (or is set to "default"), then the current skin will be searched
+	first and if not found, the default skin will be searched.  Use "default" if you want the default
+	behavior while needing to define further optional parameters.
+	@param SizerWidth Float Optional - A factor that can be used to arbitrarily shrink or grow the generated
+	box's width.  The box remains centered on the attachment.
+	@param SizerHeight Float Optional - A factor that can be used to arbitrarily shrink or grow the generated
+	box's height.
+	@param ObjectName String Optional - Used to set the name of the object returned to the caller.
+
+	@return The requested SpineCollisionProxy object, or nothing if creation failed.
+*/
+ConsoleMethodWithDocs(SpineObject, getCollisionProxy, ConsoleString, 4, 8, (char *attachmentName, char *slotName, [char *skinName, float sizerWidth, float sizerHeight, char *objectName]))
+{
+	const char* skinName = argc >= 5 ? argv[4] : "default";
+	const F32 sizerWidth = argc >= 6 ? dAtof(argv[5]) : 1.0f;
+	const F32 sizerHeight = argc >= 7 ? dAtof(argv[6]) : 1.0f;
+	const char* objectName = argc >= 8 ? argv[7] : NULL;
+
+	// Get the collision proxy for the requested spine attachment.
+	const SceneObject* pProxy = object->getCollisionProxy(argv[2], argv[3], skinName, sizerWidth, sizerHeight, objectName);
+
+	return pProxy ? pProxy->getIdString() : StringTable->EmptyString;
+}
+
+//-----------------------------------------------------------------------------
+
+/*! Delete the given collision proxy.
+	Proxies will be deleted automatically at cleanup.  However, this can be used
+	to delete one sooner.
+	@param proxy SpineCollisionProxy - The proxy to delete.
+	@return bool - True if the object was deleted, false otherwise.
+*/
+ConsoleMethodWithDocs(SpineObject, deleteCollisionProxy, ConsoleBool, 3, 3, (SpineCollsionProxy proxy))
+{
+	// Enable the special effect
+	return object->deleteCollisionProxy(argv[2]);
+}
+
+
+ConsoleMethodGroupEndWithDocs(SpineObject)

+ 68 - 68
engine/source/Box2D/Box2D.h

@@ -1,68 +1,68 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef BOX2D_H
-#define BOX2D_H
-
-/**
-\mainpage Box2D API Documentation
-
-\section intro_sec Getting Started
-
-For documentation please see http://box2d.org/documentation.html
-
-For discussion please visit http://box2d.org/forum
-*/
-
-// These include files constitute the main Box2D API
-
-#include <Box2D/Common/b2Settings.h>
-#include <Box2D/Common/b2Draw.h>
-#include <Box2D/Common/b2Timer.h>
-
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <Box2D/Collision/Shapes/b2EdgeShape.h>
-#include <Box2D/Collision/Shapes/b2ChainShape.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-#include <Box2D/Collision/b2BroadPhase.h>
-#include <Box2D/Collision/b2Distance.h>
-#include <Box2D/Collision/b2DynamicTree.h>
-#include <Box2D/Collision/b2TimeOfImpact.h>
-
-#include <Box2D/Dynamics/b2Body.h>
-#include <Box2D/Dynamics/b2Fixture.h>
-#include <Box2D/Dynamics/b2WorldCallbacks.h>
-#include <Box2D/Dynamics/b2TimeStep.h>
-#include <Box2D/Dynamics/b2World.h>
-
-#include <Box2D/Dynamics/Contacts/b2Contact.h>
-
-#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
-#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
-#include <Box2D/Dynamics/Joints/b2GearJoint.h>
-#include <Box2D/Dynamics/Joints/b2MotorJoint.h>
-#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
-#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
-#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
-#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
-#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
-#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
-#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BOX2D_H
+#define BOX2D_H
+
+/**
+\mainpage LiquidFun API Documentation
+
+*/
+
+// These include files constitute the main Box2D API
+
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Common/b2Draw.h>
+#include <Box2D/Common/b2Stat.h>
+#include <Box2D/Common/b2Timer.h>
+
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+#include <Box2D/Collision/b2BroadPhase.h>
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+
+#include <Box2D/Dynamics/b2Body.h>
+#include <Box2D/Dynamics/b2Fixture.h>
+#include <Box2D/Dynamics/b2WorldCallbacks.h>
+#include <Box2D/Dynamics/b2TimeStep.h>
+#include <Box2D/Dynamics/b2World.h>
+
+#include <Box2D/Dynamics/Contacts/b2Contact.h>
+
+#include <Box2D/Dynamics/Joints/b2DistanceJoint.h>
+#include <Box2D/Dynamics/Joints/b2FrictionJoint.h>
+#include <Box2D/Dynamics/Joints/b2GearJoint.h>
+#include <Box2D/Dynamics/Joints/b2MotorJoint.h>
+#include <Box2D/Dynamics/Joints/b2MouseJoint.h>
+#include <Box2D/Dynamics/Joints/b2PrismaticJoint.h>
+#include <Box2D/Dynamics/Joints/b2PulleyJoint.h>
+#include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
+#include <Box2D/Dynamics/Joints/b2RopeJoint.h>
+#include <Box2D/Dynamics/Joints/b2WeldJoint.h>
+#include <Box2D/Dynamics/Joints/b2WheelJoint.h>
+
+#include <Box2D/Particle/b2Particle.h>
+#include <Box2D/Particle/b2ParticleGroup.h>
+
+#endif

+ 203 - 188
engine/source/Box2D/Collision/Shapes/b2ChainShape.cpp

@@ -1,188 +1,203 @@
-/*
-* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/Shapes/b2ChainShape.h>
-#include <Box2D/Collision/Shapes/b2EdgeShape.h>
-#include <new>
-#include <cstring>
-using namespace std;
-
-b2ChainShape::~b2ChainShape()
-{
-	b2Free(m_vertices);
-	m_vertices = NULL;
-	m_count = 0;
-}
-
-void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
-{
-	b2Assert(m_vertices == NULL && m_count == 0);
-	b2Assert(count >= 3);
-	for (int32 i = 1; i < count; ++i)
-	{
-		b2Vec2 v1 = vertices[i-1];
-		b2Vec2 v2 = vertices[i];
-		// If the code crashes here, it means your vertices are too close together.
-		b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
-	}
-
-	m_count = count + 1;
-	m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
-	memcpy(m_vertices, vertices, count * sizeof(b2Vec2));
-	m_vertices[count] = m_vertices[0];
-	m_prevVertex = m_vertices[m_count - 2];
-	m_nextVertex = m_vertices[1];
-	m_hasPrevVertex = true;
-	m_hasNextVertex = true;
-}
-
-void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
-{
-	b2Assert(m_vertices == NULL && m_count == 0);
-	b2Assert(count >= 2);
-	for (int32 i = 1; i < count; ++i)
-	{
-		b2Vec2 v1 = vertices[i-1];
-		b2Vec2 v2 = vertices[i];
-		// If the code crashes here, it means your vertices are too close together.
-		b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
-	}
-
-	m_count = count;
-	m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
-	memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
-
-	m_hasPrevVertex = false;
-	m_hasNextVertex = false;
-}
-
-void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
-{
-	m_prevVertex = prevVertex;
-	m_hasPrevVertex = true;
-}
-
-void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
-{
-	m_nextVertex = nextVertex;
-	m_hasNextVertex = true;
-}
-
-b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
-{
-	void* mem = allocator->Allocate(sizeof(b2ChainShape));
-	b2ChainShape* clone = new (mem) b2ChainShape;
-	clone->CreateChain(m_vertices, m_count);
-	clone->m_prevVertex = m_prevVertex;
-	clone->m_nextVertex = m_nextVertex;
-	clone->m_hasPrevVertex = m_hasPrevVertex;
-	clone->m_hasNextVertex = m_hasNextVertex;
-	return clone;
-}
-
-int32 b2ChainShape::GetChildCount() const
-{
-	// edge count = vertex count - 1
-	return m_count - 1;
-}
-
-void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const
-{
-	b2Assert(0 <= index && index < m_count - 1);
-	edge->m_type = b2Shape::e_edge;
-	edge->m_radius = m_radius;
-
-	edge->m_vertex1 = m_vertices[index + 0];
-	edge->m_vertex2 = m_vertices[index + 1];
-
-	if (index > 0)
-	{
-		edge->m_vertex0 = m_vertices[index - 1];
-		edge->m_hasVertex0 = true;
-	}
-	else
-	{
-		edge->m_vertex0 = m_prevVertex;
-		edge->m_hasVertex0 = m_hasPrevVertex;
-	}
-
-	if (index < m_count - 2)
-	{
-		edge->m_vertex3 = m_vertices[index + 2];
-		edge->m_hasVertex3 = true;
-	}
-	else
-	{
-		edge->m_vertex3 = m_nextVertex;
-		edge->m_hasVertex3 = m_hasNextVertex;
-	}
-}
-
-bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
-{
-	B2_NOT_USED(xf);
-	B2_NOT_USED(p);
-	return false;
-}
-
-bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-							const b2Transform& xf, int32 childIndex) const
-{
-	b2Assert(childIndex < m_count);
-
-	b2EdgeShape edgeShape;
-
-	int32 i1 = childIndex;
-	int32 i2 = childIndex + 1;
-	if (i2 == m_count)
-	{
-		i2 = 0;
-	}
-
-	edgeShape.m_vertex1 = m_vertices[i1];
-	edgeShape.m_vertex2 = m_vertices[i2];
-
-	return edgeShape.RayCast(output, input, xf, 0);
-}
-
-void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
-{
-	b2Assert(childIndex < m_count);
-
-	int32 i1 = childIndex;
-	int32 i2 = childIndex + 1;
-	if (i2 == m_count)
-	{
-		i2 = 0;
-	}
-
-	b2Vec2 v1 = b2Mul(xf, m_vertices[i1]);
-	b2Vec2 v2 = b2Mul(xf, m_vertices[i2]);
-
-	aabb->lowerBound = b2Min(v1, v2);
-	aabb->upperBound = b2Max(v1, v2);
-}
-
-void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const
-{
-	B2_NOT_USED(density);
-
-	massData->mass = 0.0f;
-	massData->center.SetZero();
-	massData->I = 0.0f;
-}
+/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <new>
+#include <memory.h>
+#include <string.h>
+
+b2ChainShape::~b2ChainShape()
+{
+	b2Free(m_vertices);
+	m_vertices = NULL;
+	m_count = 0;
+}
+
+void b2ChainShape::CreateLoop(const b2Vec2* vertices, int32 count)
+{
+	b2Assert(m_vertices == NULL && m_count == 0);
+	b2Assert(count >= 3);
+	for (int32 i = 1; i < count; ++i)
+	{
+#if B2_ASSERT_ENABLED
+		b2Vec2 v1 = vertices[i-1];
+		b2Vec2 v2 = vertices[i];
+		// If the code crashes here, it means your vertices are too close together.
+		b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
+#endif // B2_ASSERT_ENABLED
+	}
+
+	m_count = count + 1;
+	m_vertices = (b2Vec2*)b2Alloc(m_count * sizeof(b2Vec2));
+	memcpy(m_vertices, vertices, count * sizeof(b2Vec2));
+	m_vertices[count] = m_vertices[0];
+	m_prevVertex = m_vertices[m_count - 2];
+	m_nextVertex = m_vertices[1];
+	m_hasPrevVertex = true;
+	m_hasNextVertex = true;
+}
+
+void b2ChainShape::CreateChain(const b2Vec2* vertices, int32 count)
+{
+	b2Assert(m_vertices == NULL && m_count == 0);
+	b2Assert(count >= 2);
+	for (int32 i = 1; i < count; ++i)
+	{
+#if B2_ASSERT_ENABLED
+		b2Vec2 v1 = vertices[i-1];
+		b2Vec2 v2 = vertices[i];
+		// If the code crashes here, it means your vertices are too close together.
+		b2Assert(b2DistanceSquared(v1, v2) > b2_linearSlop * b2_linearSlop);
+#endif // B2_ASSERT_ENABLED
+	}
+
+	m_count = count;
+	m_vertices = (b2Vec2*)b2Alloc(count * sizeof(b2Vec2));
+	memcpy(m_vertices, vertices, m_count * sizeof(b2Vec2));
+
+	m_hasPrevVertex = false;
+	m_hasNextVertex = false;
+
+	m_prevVertex.SetZero();
+	m_nextVertex.SetZero();
+}
+
+void b2ChainShape::SetPrevVertex(const b2Vec2& prevVertex)
+{
+	m_prevVertex = prevVertex;
+	m_hasPrevVertex = true;
+}
+
+void b2ChainShape::SetNextVertex(const b2Vec2& nextVertex)
+{
+	m_nextVertex = nextVertex;
+	m_hasNextVertex = true;
+}
+
+b2Shape* b2ChainShape::Clone(b2BlockAllocator* allocator) const
+{
+	void* mem = allocator->Allocate(sizeof(b2ChainShape));
+	b2ChainShape* clone = new (mem) b2ChainShape;
+	clone->CreateChain(m_vertices, m_count);
+	clone->m_prevVertex = m_prevVertex;
+	clone->m_nextVertex = m_nextVertex;
+	clone->m_hasPrevVertex = m_hasPrevVertex;
+	clone->m_hasNextVertex = m_hasNextVertex;
+	return clone;
+}
+
+int32 b2ChainShape::GetChildCount() const
+{
+	// edge count = vertex count - 1
+	return m_count - 1;
+}
+
+void b2ChainShape::GetChildEdge(b2EdgeShape* edge, int32 index) const
+{
+	b2Assert(0 <= index && index < m_count - 1);
+	edge->m_type = b2Shape::e_edge;
+	edge->m_radius = m_radius;
+
+	edge->m_vertex1 = m_vertices[index + 0];
+	edge->m_vertex2 = m_vertices[index + 1];
+
+	if (index > 0)
+	{
+		edge->m_vertex0 = m_vertices[index - 1];
+		edge->m_hasVertex0 = true;
+	}
+	else
+	{
+		edge->m_vertex0 = m_prevVertex;
+		edge->m_hasVertex0 = m_hasPrevVertex;
+	}
+
+	if (index < m_count - 2)
+	{
+		edge->m_vertex3 = m_vertices[index + 2];
+		edge->m_hasVertex3 = true;
+	}
+	else
+	{
+		edge->m_vertex3 = m_nextVertex;
+		edge->m_hasVertex3 = m_hasNextVertex;
+	}
+}
+
+void b2ChainShape::ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const
+{
+	b2EdgeShape edge;
+	GetChildEdge(&edge, childIndex);
+	edge.ComputeDistance(xf, p, distance, normal, 0);
+}
+
+bool b2ChainShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+	B2_NOT_USED(xf);
+	B2_NOT_USED(p);
+	return false;
+}
+
+bool b2ChainShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+							const b2Transform& xf, int32 childIndex) const
+{
+	b2Assert(childIndex < m_count);
+
+	b2EdgeShape edgeShape;
+
+	int32 i1 = childIndex;
+	int32 i2 = childIndex + 1;
+	if (i2 == m_count)
+	{
+		i2 = 0;
+	}
+
+	edgeShape.m_vertex1 = m_vertices[i1];
+	edgeShape.m_vertex2 = m_vertices[i2];
+
+	return edgeShape.RayCast(output, input, xf, 0);
+}
+
+void b2ChainShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+	b2Assert(childIndex < m_count);
+
+	int32 i1 = childIndex;
+	int32 i2 = childIndex + 1;
+	if (i2 == m_count)
+	{
+		i2 = 0;
+	}
+
+	b2Vec2 v1 = b2Mul(xf, m_vertices[i1]);
+	b2Vec2 v2 = b2Mul(xf, m_vertices[i2]);
+
+	aabb->lowerBound = b2Min(v1, v2);
+	aabb->upperBound = b2Max(v1, v2);
+}
+
+void b2ChainShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+	B2_NOT_USED(density);
+
+	massData->mass = 0.0f;
+	massData->center.SetZero();
+	massData->I = 0.0f;
+}

+ 106 - 102
engine/source/Box2D/Collision/Shapes/b2ChainShape.h

@@ -1,102 +1,106 @@
-/*
-* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_CHAIN_SHAPE_H
-#define B2_CHAIN_SHAPE_H
-
-#include <Box2D/Collision/Shapes/b2Shape.h>
-
-class b2EdgeShape;
-
-/// A chain shape is a free form sequence of line segments.
-/// The chain has two-sided collision, so you can use inside and outside collision.
-/// Therefore, you may use any winding order.
-/// Since there may be many vertices, they are allocated using b2Alloc.
-/// Connectivity information is used to create smooth collisions.
-/// WARNING: The chain will not collide properly if there are self-intersections.
-class b2ChainShape : public b2Shape
-{
-public:
-	b2ChainShape();
-
-	/// The destructor frees the vertices using b2Free.
-	~b2ChainShape();
-
-	/// Create a loop. This automatically adjusts connectivity.
-	/// @param vertices an array of vertices, these are copied
-	/// @param count the vertex count
-	void CreateLoop(const b2Vec2* vertices, int32 count);
-
-	/// Create a chain with isolated end vertices.
-	/// @param vertices an array of vertices, these are copied
-	/// @param count the vertex count
-	void CreateChain(const b2Vec2* vertices, int32 count);
-
-	/// Establish connectivity to a vertex that precedes the first vertex.
-	/// Don't call this for loops.
-	void SetPrevVertex(const b2Vec2& prevVertex);
-
-	/// Establish connectivity to a vertex that follows the last vertex.
-	/// Don't call this for loops.
-	void SetNextVertex(const b2Vec2& nextVertex);
-
-	/// Implement b2Shape. Vertices are cloned using b2Alloc.
-	b2Shape* Clone(b2BlockAllocator* allocator) const;
-
-	/// @see b2Shape::GetChildCount
-	int32 GetChildCount() const;
-
-	/// Get a child edge.
-	void GetChildEdge(b2EdgeShape* edge, int32 index) const;
-
-	/// This always return false.
-	/// @see b2Shape::TestPoint
-	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
-
-	/// Implement b2Shape.
-	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-					const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeAABB
-	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
-
-	/// Chains have zero mass.
-	/// @see b2Shape::ComputeMass
-	void ComputeMass(b2MassData* massData, float32 density) const;
-
-	/// The vertices. Owned by this class.
-	b2Vec2* m_vertices;
-
-	/// The vertex count.
-	int32 m_count;
-
-	b2Vec2 m_prevVertex, m_nextVertex;
-	bool m_hasPrevVertex, m_hasNextVertex;
-};
-
-inline b2ChainShape::b2ChainShape()
-{
-	m_type = e_chain;
-	m_radius = b2_polygonRadius;
-	m_vertices = NULL;
-	m_count = 0;
-	m_hasPrevVertex = false;
-	m_hasNextVertex = false;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CHAIN_SHAPE_H
+#define B2_CHAIN_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+class b2EdgeShape;
+
+/// A chain shape is a free form sequence of line segments.
+/// The chain has two-sided collision, so you can use inside and outside collision.
+/// Therefore, you may use any winding order.
+/// Since there may be many vertices, they are allocated using b2Alloc.
+/// Connectivity information is used to create smooth collisions.
+/// WARNING: The chain will not collide properly if there are self-intersections.
+class b2ChainShape : public b2Shape
+{
+public:
+	b2ChainShape();
+
+	/// The destructor frees the vertices using b2Free.
+	~b2ChainShape();
+
+	/// Create a loop. This automatically adjusts connectivity.
+	/// @param vertices an array of vertices, these are copied
+	/// @param count the vertex count
+	void CreateLoop(const b2Vec2* vertices, int32 count);
+
+	/// Create a chain with isolated end vertices.
+	/// @param vertices an array of vertices, these are copied
+	/// @param count the vertex count
+	void CreateChain(const b2Vec2* vertices, int32 count);
+
+	/// Establish connectivity to a vertex that precedes the first vertex.
+	/// Don't call this for loops.
+	void SetPrevVertex(const b2Vec2& prevVertex);
+
+	/// Establish connectivity to a vertex that follows the last vertex.
+	/// Don't call this for loops.
+	void SetNextVertex(const b2Vec2& nextVertex);
+
+	/// Implement b2Shape. Vertices are cloned using b2Alloc.
+	b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+	/// @see b2Shape::GetChildCount
+	int32 GetChildCount() const;
+
+	/// Get a child edge.
+	void GetChildEdge(b2EdgeShape* edge, int32 index) const;
+
+	/// This always return false.
+	/// @see b2Shape::TestPoint
+	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+	// @see b2Shape::ComputeDistance
+	void ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const;
+
+	/// Implement b2Shape.
+	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+					const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeAABB
+	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+	/// Chains have zero mass.
+	/// @see b2Shape::ComputeMass
+	void ComputeMass(b2MassData* massData, float32 density) const;
+
+	/// The vertices. Owned by this class.
+	b2Vec2* m_vertices;
+
+	/// The vertex count.
+	int32 m_count;
+
+	b2Vec2 m_prevVertex, m_nextVertex;
+	bool m_hasPrevVertex, m_hasNextVertex;
+};
+
+inline b2ChainShape::b2ChainShape()
+{
+	m_type = e_chain;
+	m_radius = b2_polygonRadius;
+	m_vertices = NULL;
+	m_count = 0;
+	m_hasPrevVertex = false;
+	m_hasNextVertex = false;
+}
+
+#endif

+ 111 - 100
engine/source/Box2D/Collision/Shapes/b2CircleShape.cpp

@@ -1,100 +1,111 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <new>
-using namespace std;
-
-b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
-{
-	void* mem = allocator->Allocate(sizeof(b2CircleShape));
-	b2CircleShape* clone = new (mem) b2CircleShape;
-	*clone = *this;
-	return clone;
-}
-
-int32 b2CircleShape::GetChildCount() const
-{
-	return 1;
-}
-
-bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const
-{
-	b2Vec2 center = transform.p + b2Mul(transform.q, m_p);
-	b2Vec2 d = p - center;
-	return b2Dot(d, d) <= m_radius * m_radius;
-}
-
-// Collision Detection in Interactive 3D Environments by Gino van den Bergen
-// From Section 3.1.2
-// x = s + a * r
-// norm(x) = radius
-bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-							const b2Transform& transform, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	b2Vec2 position = transform.p + b2Mul(transform.q, m_p);
-	b2Vec2 s = input.p1 - position;
-	float32 b = b2Dot(s, s) - m_radius * m_radius;
-
-	// Solve quadratic equation.
-	b2Vec2 r = input.p2 - input.p1;
-	float32 c =  b2Dot(s, r);
-	float32 rr = b2Dot(r, r);
-	float32 sigma = c * c - rr * b;
-
-	// Check for negative discriminant and short segment.
-	if (sigma < 0.0f || rr < b2_epsilon)
-	{
-		return false;
-	}
-
-	// Find the point of intersection of the line with the circle.
-	float32 a = -(c + b2Sqrt(sigma));
-
-	// Is the intersection point on the segment?
-	if (0.0f <= a && a <= input.maxFraction * rr)
-	{
-		a /= rr;
-		output->fraction = a;
-		output->normal = s + a * r;
-		output->normal.Normalize();
-		return true;
-	}
-
-	return false;
-}
-
-void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	b2Vec2 p = transform.p + b2Mul(transform.q, m_p);
-	aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
-	aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
-}
-
-void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const
-{
-	massData->mass = density * b2_pi * m_radius * m_radius;
-	massData->center = m_p;
-
-	// inertia about the local origin
-	massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <new>
+
+b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
+{
+	void* mem = allocator->Allocate(sizeof(b2CircleShape));
+	b2CircleShape* clone = new (mem) b2CircleShape;
+	*clone = *this;
+	return clone;
+}
+
+int32 b2CircleShape::GetChildCount() const
+{
+	return 1;
+}
+
+bool b2CircleShape::TestPoint(const b2Transform& transform, const b2Vec2& p) const
+{
+	b2Vec2 center = transform.p + b2Mul(transform.q, m_p);
+	b2Vec2 d = p - center;
+	return b2Dot(d, d) <= m_radius * m_radius;
+}
+
+void b2CircleShape::ComputeDistance(const b2Transform& transform, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 center = transform.p + b2Mul(transform.q, m_p);
+	b2Vec2 d = p - center;
+	float32 d1 = d.Length();
+	*distance = d1 - m_radius;
+	*normal = 1 / d1 * d;
+}
+
+// Collision Detection in Interactive 3D Environments by Gino van den Bergen
+// From Section 3.1.2
+// x = s + a * r
+// norm(x) = radius
+bool b2CircleShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+							const b2Transform& transform, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 position = transform.p + b2Mul(transform.q, m_p);
+	b2Vec2 s = input.p1 - position;
+	float32 b = b2Dot(s, s) - m_radius * m_radius;
+
+	// Solve quadratic equation.
+	b2Vec2 r = input.p2 - input.p1;
+	float32 c =  b2Dot(s, r);
+	float32 rr = b2Dot(r, r);
+	float32 sigma = c * c - rr * b;
+
+	// Check for negative discriminant and short segment.
+	if (sigma < 0.0f || rr < b2_epsilon)
+	{
+		return false;
+	}
+
+	// Find the point of intersection of the line with the circle.
+	float32 a = -(c + b2Sqrt(sigma));
+
+	// Is the intersection point on the segment?
+	if (0.0f <= a && a <= input.maxFraction * rr)
+	{
+		a /= rr;
+		output->fraction = a;
+		output->normal = s + a * r;
+		output->normal.Normalize();
+		return true;
+	}
+
+	return false;
+}
+
+void b2CircleShape::ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 p = transform.p + b2Mul(transform.q, m_p);
+	aabb->lowerBound.Set(p.x - m_radius, p.y - m_radius);
+	aabb->upperBound.Set(p.x + m_radius, p.y + m_radius);
+}
+
+void b2CircleShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+	massData->mass = density * b2_pi * m_radius * m_radius;
+	massData->center = m_p;
+
+	// inertia about the local origin
+	massData->I = massData->mass * (0.5f * m_radius * m_radius + b2Dot(m_p, m_p));
+}

+ 107 - 91
engine/source/Box2D/Collision/Shapes/b2CircleShape.h

@@ -1,91 +1,107 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_CIRCLE_SHAPE_H
-#define B2_CIRCLE_SHAPE_H
-
-#include <Box2D/Collision/Shapes/b2Shape.h>
-
-/// A circle shape.
-class b2CircleShape : public b2Shape
-{
-public:
-	b2CircleShape();
-
-	/// Implement b2Shape.
-	b2Shape* Clone(b2BlockAllocator* allocator) const;
-
-	/// @see b2Shape::GetChildCount
-	int32 GetChildCount() const;
-
-	/// Implement b2Shape.
-	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
-
-	/// Implement b2Shape.
-	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-				const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeAABB
-	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeMass
-	void ComputeMass(b2MassData* massData, float32 density) const;
-
-	/// Get the supporting vertex index in the given direction.
-	int32 GetSupport(const b2Vec2& d) const;
-
-	/// Get the supporting vertex in the given direction.
-	const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
-
-	/// Get the vertex count.
-	int32 GetVertexCount() const { return 1; }
-
-	/// Get a vertex by index. Used by b2Distance.
-	const b2Vec2& GetVertex(int32 index) const;
-
-	/// Position
-	b2Vec2 m_p;
-};
-
-inline b2CircleShape::b2CircleShape()
-{
-	m_type = e_circle;
-	m_radius = 0.0f;
-	m_p.SetZero();
-}
-
-inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
-{
-	B2_NOT_USED(d);
-	return 0;
-}
-
-inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
-{
-	B2_NOT_USED(d);
-	return m_p;
-}
-
-inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
-{
-	B2_NOT_USED(index);
-	b2Assert(index == 0);
-	return m_p;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_CIRCLE_SHAPE_H
+#define B2_CIRCLE_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A circle shape.
+class b2CircleShape : public b2Shape
+{
+public:
+	b2CircleShape();
+
+	/// Implement b2Shape.
+	b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+	/// @see b2Shape::GetChildCount
+	int32 GetChildCount() const;
+
+	/// Implement b2Shape.
+	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+	// @see b2Shape::ComputeDistance
+	void ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const;
+
+	/// Implement b2Shape.
+	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+				const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeAABB
+	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeMass
+	void ComputeMass(b2MassData* massData, float32 density) const;
+
+	/// Get the supporting vertex index in the given direction.
+	int32 GetSupport(const b2Vec2& d) const;
+
+	/// Get the supporting vertex in the given direction.
+	const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
+
+	/// Get the vertex count.
+	int32 GetVertexCount() const { return 1; }
+
+	/// Get a vertex by index. Used by b2Distance.
+	const b2Vec2& GetVertex(int32 index) const;
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+public:
+	/// Set position with direct floats.
+	void SetPosition(float32 x, float32 y) { m_p.Set(x, y); }
+
+	/// Get x-coordinate of position.
+	float32 GetPositionX() const { return m_p.x; }
+
+	/// Get y-coordinate of position.
+	float32 GetPositionY() const { return m_p.y; }
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+	/// Position
+	b2Vec2 m_p;
+};
+
+inline b2CircleShape::b2CircleShape()
+{
+	m_type = e_circle;
+	m_radius = 0.0f;
+	m_p.SetZero();
+}
+
+inline int32 b2CircleShape::GetSupport(const b2Vec2 &d) const
+{
+	B2_NOT_USED(d);
+	return 0;
+}
+
+inline const b2Vec2& b2CircleShape::GetSupportVertex(const b2Vec2 &d) const
+{
+	B2_NOT_USED(d);
+	return m_p;
+}
+
+inline const b2Vec2& b2CircleShape::GetVertex(int32 index) const
+{
+	B2_NOT_USED(index);
+	b2Assert(index == 0);
+	return m_p;
+}
+
+#endif

+ 168 - 139
engine/source/Box2D/Collision/Shapes/b2EdgeShape.cpp

@@ -1,139 +1,168 @@
-/*
-* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/Shapes/b2EdgeShape.h>
-#include <new>
-using namespace std;
-
-void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2)
-{
-	m_vertex1 = v1;
-	m_vertex2 = v2;
-	m_hasVertex0 = false;
-	m_hasVertex3 = false;
-}
-
-b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const
-{
-	void* mem = allocator->Allocate(sizeof(b2EdgeShape));
-	b2EdgeShape* clone = new (mem) b2EdgeShape;
-	*clone = *this;
-	return clone;
-}
-
-int32 b2EdgeShape::GetChildCount() const
-{
-	return 1;
-}
-
-bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
-{
-	B2_NOT_USED(xf);
-	B2_NOT_USED(p);
-	return false;
-}
-
-// p = p1 + t * d
-// v = v1 + s * e
-// p1 + t * d = v1 + s * e
-// s * e - t * d = p1 - v1
-bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-							const b2Transform& xf, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	// Put the ray into the edge's frame of reference.
-	b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
-	b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
-	b2Vec2 d = p2 - p1;
-
-	b2Vec2 v1 = m_vertex1;
-	b2Vec2 v2 = m_vertex2;
-	b2Vec2 e = v2 - v1;
-	b2Vec2 normal(e.y, -e.x);
-	normal.Normalize();
-
-	// q = p1 + t * d
-	// dot(normal, q - v1) = 0
-	// dot(normal, p1 - v1) + t * dot(normal, d) = 0
-	float32 numerator = b2Dot(normal, v1 - p1);
-	float32 denominator = b2Dot(normal, d);
-
-	if (denominator == 0.0f)
-	{
-		return false;
-	}
-
-	float32 t = numerator / denominator;
-	if (t < 0.0f || input.maxFraction < t)
-	{
-		return false;
-	}
-
-	b2Vec2 q = p1 + t * d;
-
-	// q = v1 + s * r
-	// s = dot(q - v1, r) / dot(r, r)
-	b2Vec2 r = v2 - v1;
-	float32 rr = b2Dot(r, r);
-	if (rr == 0.0f)
-	{
-		return false;
-	}
-
-	float32 s = b2Dot(q - v1, r) / rr;
-	if (s < 0.0f || 1.0f < s)
-	{
-		return false;
-	}
-
-	output->fraction = t;
-	if (numerator > 0.0f)
-	{
-		output->normal = -normal;
-	}
-	else
-	{
-		output->normal = normal;
-	}
-	return true;
-}
-
-void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	b2Vec2 v1 = b2Mul(xf, m_vertex1);
-	b2Vec2 v2 = b2Mul(xf, m_vertex2);
-
-	b2Vec2 lower = b2Min(v1, v2);
-	b2Vec2 upper = b2Max(v1, v2);
-
-	b2Vec2 r(m_radius, m_radius);
-	aabb->lowerBound = lower - r;
-	aabb->upperBound = upper + r;
-}
-
-void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const
-{
-	B2_NOT_USED(density);
-
-	massData->mass = 0.0f;
-	massData->center = 0.5f * (m_vertex1 + m_vertex2);
-	massData->I = 0.0f;
-}
+/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <new>
+
+void b2EdgeShape::Set(const b2Vec2& v1, const b2Vec2& v2)
+{
+	m_vertex1 = v1;
+	m_vertex2 = v2;
+	m_hasVertex0 = false;
+	m_hasVertex3 = false;
+}
+
+b2Shape* b2EdgeShape::Clone(b2BlockAllocator* allocator) const
+{
+	void* mem = allocator->Allocate(sizeof(b2EdgeShape));
+	b2EdgeShape* clone = new (mem) b2EdgeShape;
+	*clone = *this;
+	return clone;
+}
+
+int32 b2EdgeShape::GetChildCount() const
+{
+	return 1;
+}
+
+bool b2EdgeShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+	B2_NOT_USED(xf);
+	B2_NOT_USED(p);
+	return false;
+}
+
+void b2EdgeShape::ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 v1 = b2Mul(xf, m_vertex1);
+	b2Vec2 v2 = b2Mul(xf, m_vertex2);
+
+	b2Vec2 d = p - v1;
+	b2Vec2 s = v2 - v1;
+	float32 ds = b2Dot(d, s);
+	if (ds > 0)
+	{
+		float32 s2 = b2Dot(s, s);
+		if (ds > s2)
+		{
+			d = p - v2;
+		}
+		else
+		{
+			d -= ds / s2 * s;
+		}
+	}
+
+	float32 d1 = d.Length();
+	*distance = d1;
+	*normal = d1 > 0 ? 1 / d1 * d : b2Vec2_zero;
+
+}
+
+// p = p1 + t * d
+// v = v1 + s * e
+// p1 + t * d = v1 + s * e
+// s * e - t * d = p1 - v1
+bool b2EdgeShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+							const b2Transform& xf, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	// Put the ray into the edge's frame of reference.
+	b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
+	b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
+	b2Vec2 d = p2 - p1;
+
+	b2Vec2 v1 = m_vertex1;
+	b2Vec2 v2 = m_vertex2;
+	b2Vec2 e = v2 - v1;
+	b2Vec2 normal(e.y, -e.x);
+	normal.Normalize();
+
+	// q = p1 + t * d
+	// dot(normal, q - v1) = 0
+	// dot(normal, p1 - v1) + t * dot(normal, d) = 0
+	float32 numerator = b2Dot(normal, v1 - p1);
+	float32 denominator = b2Dot(normal, d);
+
+	if (denominator == 0.0f)
+	{
+		return false;
+	}
+
+	float32 t = numerator / denominator;
+	if (t < 0.0f || input.maxFraction < t)
+	{
+		return false;
+	}
+
+	b2Vec2 q = p1 + t * d;
+
+	// q = v1 + s * r
+	// s = dot(q - v1, r) / dot(r, r)
+	b2Vec2 r = v2 - v1;
+	float32 rr = b2Dot(r, r);
+	if (rr == 0.0f)
+	{
+		return false;
+	}
+
+	float32 s = b2Dot(q - v1, r) / rr;
+	if (s < 0.0f || 1.0f < s)
+	{
+		return false;
+	}
+
+	output->fraction = t;
+	if (numerator > 0.0f)
+	{
+		output->normal = -b2Mul(xf.q, normal);
+	}
+	else
+	{
+		output->normal = b2Mul(xf.q, normal);
+	}
+	return true;
+}
+
+void b2EdgeShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 v1 = b2Mul(xf, m_vertex1);
+	b2Vec2 v2 = b2Mul(xf, m_vertex2);
+
+	b2Vec2 lower = b2Min(v1, v2);
+	b2Vec2 upper = b2Max(v1, v2);
+
+	b2Vec2 r(m_radius, m_radius);
+	aabb->lowerBound = lower - r;
+	aabb->upperBound = upper + r;
+}
+
+void b2EdgeShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+	B2_NOT_USED(density);
+
+	massData->mass = 0.0f;
+	massData->center = 0.5f * (m_vertex1 + m_vertex2);
+	massData->I = 0.0f;
+}

+ 94 - 74
engine/source/Box2D/Collision/Shapes/b2EdgeShape.h

@@ -1,74 +1,94 @@
-/*
-* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_EDGE_SHAPE_H
-#define B2_EDGE_SHAPE_H
-
-#include <Box2D/Collision/Shapes/b2Shape.h>
-
-/// A line segment (edge) shape. These can be connected in chains or loops
-/// to other edge shapes. The connectivity information is used to ensure
-/// correct contact normals.
-class b2EdgeShape : public b2Shape
-{
-public:
-	b2EdgeShape();
-
-	/// Set this as an isolated edge.
-	void Set(const b2Vec2& v1, const b2Vec2& v2);
-
-	/// Implement b2Shape.
-	b2Shape* Clone(b2BlockAllocator* allocator) const;
-
-	/// @see b2Shape::GetChildCount
-	int32 GetChildCount() const;
-
-	/// @see b2Shape::TestPoint
-	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
-
-	/// Implement b2Shape.
-	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-				const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeAABB
-	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeMass
-	void ComputeMass(b2MassData* massData, float32 density) const;
-	
-	/// These are the edge vertices
-	b2Vec2 m_vertex1, m_vertex2;
-
-	/// Optional adjacent vertices. These are used for smooth collision.
-	b2Vec2 m_vertex0, m_vertex3;
-	bool m_hasVertex0, m_hasVertex3;
-};
-
-inline b2EdgeShape::b2EdgeShape()
-{
-	m_type = e_edge;
-	m_radius = b2_polygonRadius;
-	m_vertex0.x = 0.0f;
-	m_vertex0.y = 0.0f;
-	m_vertex3.x = 0.0f;
-	m_vertex3.y = 0.0f;
-	m_hasVertex0 = false;
-	m_hasVertex3 = false;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2010 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_EDGE_SHAPE_H
+#define B2_EDGE_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A line segment (edge) shape. These can be connected in chains or loops
+/// to other edge shapes. The connectivity information is used to ensure
+/// correct contact normals.
+class b2EdgeShape : public b2Shape
+{
+public:
+	b2EdgeShape();
+
+	/// Set this as an isolated edge.
+	void Set(const b2Vec2& v1, const b2Vec2& v2);
+
+	/// Implement b2Shape.
+	b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+	/// @see b2Shape::GetChildCount
+	int32 GetChildCount() const;
+
+	/// @see b2Shape::TestPoint
+	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+	// @see b2Shape::ComputeDistance
+	void ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const;
+
+	/// Implement b2Shape.
+	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+				const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeAABB
+	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeMass
+	void ComputeMass(b2MassData* massData, float32 density) const;
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+public:
+	/// Set this as an isolated edge, with direct floats.
+	void Set(float32 vx1, float32 vy1, float32 vx2, float32 vy2);
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+	/// These are the edge vertices
+	b2Vec2 m_vertex1, m_vertex2;
+
+	/// Optional adjacent vertices. These are used for smooth collision.
+	b2Vec2 m_vertex0, m_vertex3;
+	bool m_hasVertex0, m_hasVertex3;
+};
+
+inline b2EdgeShape::b2EdgeShape()
+{
+	m_type = e_edge;
+	m_radius = b2_polygonRadius;
+	m_vertex0.x = 0.0f;
+	m_vertex0.y = 0.0f;
+	m_vertex3.x = 0.0f;
+	m_vertex3.y = 0.0f;
+	m_hasVertex0 = false;
+	m_hasVertex3 = false;
+}
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+inline void b2EdgeShape::Set(float32 vx1,
+														 float32 vy1,
+														 float32 vx2,
+														 float32 vy2) {
+	Set(b2Vec2(vx1, vy1), b2Vec2(vx2, vy2));
+}
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+
+#endif

+ 504 - 434
engine/source/Box2D/Collision/Shapes/b2PolygonShape.cpp

@@ -1,434 +1,504 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-#include <new>
-
-b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
-{
-	void* mem = allocator->Allocate(sizeof(b2PolygonShape));
-	b2PolygonShape* clone = new (mem) b2PolygonShape;
-	*clone = *this;
-	return clone;
-}
-
-void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
-{
-	m_count = 4;
-	m_vertices[0].Set(-hx, -hy);
-	m_vertices[1].Set( hx, -hy);
-	m_vertices[2].Set( hx,  hy);
-	m_vertices[3].Set(-hx,  hy);
-	m_normals[0].Set(0.0f, -1.0f);
-	m_normals[1].Set(1.0f, 0.0f);
-	m_normals[2].Set(0.0f, 1.0f);
-	m_normals[3].Set(-1.0f, 0.0f);
-	m_centroid.SetZero();
-}
-
-void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
-{
-	m_count = 4;
-	m_vertices[0].Set(-hx, -hy);
-	m_vertices[1].Set( hx, -hy);
-	m_vertices[2].Set( hx,  hy);
-	m_vertices[3].Set(-hx,  hy);
-	m_normals[0].Set(0.0f, -1.0f);
-	m_normals[1].Set(1.0f, 0.0f);
-	m_normals[2].Set(0.0f, 1.0f);
-	m_normals[3].Set(-1.0f, 0.0f);
-	m_centroid = center;
-
-	b2Transform xf;
-	xf.p = center;
-	xf.q.Set(angle);
-
-	// Transform vertices and normals.
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		m_vertices[i] = b2Mul(xf, m_vertices[i]);
-		m_normals[i] = b2Mul(xf.q, m_normals[i]);
-	}
-}
-
-int32 b2PolygonShape::GetChildCount() const
-{
-	return 1;
-}
-
-static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
-{
-	b2Assert(count >= 3);
-
-	b2Vec2 c; c.Set(0.0f, 0.0f);
-	float32 area = 0.0f;
-
-	// pRef is the reference point for forming triangles.
-	// It's location doesn't change the result (except for rounding error).
-	b2Vec2 pRef(0.0f, 0.0f);
-#if 0
-	// This code would put the reference point inside the polygon.
-	for (int32 i = 0; i < count; ++i)
-	{
-		pRef += vs[i];
-	}
-	pRef *= 1.0f / count;
-#endif
-
-	const float32 inv3 = 1.0f / 3.0f;
-
-	for (int32 i = 0; i < count; ++i)
-	{
-		// Triangle vertices.
-		b2Vec2 p1 = pRef;
-		b2Vec2 p2 = vs[i];
-		b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
-
-		b2Vec2 e1 = p2 - p1;
-		b2Vec2 e2 = p3 - p1;
-
-		float32 D = b2Cross(e1, e2);
-
-		float32 triangleArea = 0.5f * D;
-		area += triangleArea;
-
-		// Area weighted centroid
-		c += triangleArea * inv3 * (p1 + p2 + p3);
-	}
-
-	// Centroid
-	b2Assert(area > b2_epsilon);
-	c *= 1.0f / area;
-	return c;
-}
-
-void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
-{
-	b2Assert(3 <= count && count <= b2_maxPolygonVertices);
-	if (count < 3)
-	{
-		SetAsBox(1.0f, 1.0f);
-		return;
-	}
-	
-	int32 n = b2Min(count, b2_maxPolygonVertices);
-
-	// Copy vertices into local buffer
-	b2Vec2 ps[b2_maxPolygonVertices];
-	for (int32 i = 0; i < n; ++i)
-	{
-		ps[i] = vertices[i];
-	}
-
-	// Create the convex hull using the Gift wrapping algorithm
-	// http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
-
-	// Find the right most point on the hull
-	int32 i0 = 0;
-	float32 x0 = ps[0].x;
-	for (int32 i = 1; i < count; ++i)
-	{
-		float32 x = ps[i].x;
-		if (x > x0 || (x == x0 && ps[i].y < ps[i0].y))
-		{
-			i0 = i;
-			x0 = x;
-		}
-	}
-
-	int32 hull[b2_maxPolygonVertices];
-	int32 m = 0;
-	int32 ih = i0;
-
-	for (;;)
-	{
-		hull[m] = ih;
-
-		int32 ie = 0;
-		for (int32 j = 1; j < n; ++j)
-		{
-			if (ie == ih)
-			{
-				ie = j;
-				continue;
-			}
-
-			b2Vec2 r = ps[ie] - ps[hull[m]];
-			b2Vec2 v = ps[j] - ps[hull[m]];
-			float32 c = b2Cross(r, v);
-			if (c < 0.0f)
-			{
-				ie = j;
-			}
-
-			// Collinearity check
-			if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
-			{
-				ie = j;
-			}
-		}
-
-		++m;
-		ih = ie;
-
-		if (ie == i0)
-		{
-			break;
-		}
-	}
-	
-	m_count = m;
-
-	// Copy vertices.
-	for (int32 i = 0; i < m; ++i)
-	{
-		m_vertices[i] = ps[hull[i]];
-	}
-
-	// Compute normals. Ensure the edges have non-zero length.
-	for (int32 i = 0; i < m; ++i)
-	{
-		int32 i1 = i;
-		int32 i2 = i + 1 < m ? i + 1 : 0;
-		b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
-		b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);
-		m_normals[i] = b2Cross(edge, 1.0f);
-		m_normals[i].Normalize();
-	}
-
-	// Compute the polygon centroid.
-	m_centroid = ComputeCentroid(m_vertices, m);
-}
-
-bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
-{
-	b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
-
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
-		if (dot > 0.0f)
-		{
-			return false;
-		}
-	}
-
-	return true;
-}
-
-bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-								const b2Transform& xf, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	// Put the ray into the polygon's frame of reference.
-	b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
-	b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
-	b2Vec2 d = p2 - p1;
-
-	float32 lower = 0.0f, upper = input.maxFraction;
-
-	int32 index = -1;
-
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		// p = p1 + a * d
-		// dot(normal, p - v) = 0
-		// dot(normal, p1 - v) + a * dot(normal, d) = 0
-		float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
-		float32 denominator = b2Dot(m_normals[i], d);
-
-		if (denominator == 0.0f)
-		{	
-			if (numerator < 0.0f)
-			{
-				return false;
-			}
-		}
-		else
-		{
-			// Note: we want this predicate without division:
-			// lower < numerator / denominator, where denominator < 0
-			// Since denominator < 0, we have to flip the inequality:
-			// lower < numerator / denominator <==> denominator * lower > numerator.
-			if (denominator < 0.0f && numerator < lower * denominator)
-			{
-				// Increase lower.
-				// The segment enters this half-space.
-				lower = numerator / denominator;
-				index = i;
-			}
-			else if (denominator > 0.0f && numerator < upper * denominator)
-			{
-				// Decrease upper.
-				// The segment exits this half-space.
-				upper = numerator / denominator;
-			}
-		}
-
-		// The use of epsilon here causes the assert on lower to trip
-		// in some cases. Apparently the use of epsilon was to make edge
-		// shapes work, but now those are handled separately.
-		//if (upper < lower - b2_epsilon)
-		if (upper < lower)
-		{
-			return false;
-		}
-	}
-
-	b2Assert(0.0f <= lower && lower <= input.maxFraction);
-
-	if (index >= 0)
-	{
-		output->fraction = lower;
-		output->normal = b2Mul(xf.q, m_normals[index]);
-		return true;
-	}
-
-	return false;
-}
-
-void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
-{
-	B2_NOT_USED(childIndex);
-
-	b2Vec2 lower = b2Mul(xf, m_vertices[0]);
-	b2Vec2 upper = lower;
-
-	for (int32 i = 1; i < m_count; ++i)
-	{
-		b2Vec2 v = b2Mul(xf, m_vertices[i]);
-		lower = b2Min(lower, v);
-		upper = b2Max(upper, v);
-	}
-
-	b2Vec2 r(m_radius, m_radius);
-	aabb->lowerBound = lower - r;
-	aabb->upperBound = upper + r;
-}
-
-void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const
-{
-	// Polygon mass, centroid, and inertia.
-	// Let rho be the polygon density in mass per unit area.
-	// Then:
-	// mass = rho * int(dA)
-	// centroid.x = (1/mass) * rho * int(x * dA)
-	// centroid.y = (1/mass) * rho * int(y * dA)
-	// I = rho * int((x*x + y*y) * dA)
-	//
-	// We can compute these integrals by summing all the integrals
-	// for each triangle of the polygon. To evaluate the integral
-	// for a single triangle, we make a change of variables to
-	// the (u,v) coordinates of the triangle:
-	// x = x0 + e1x * u + e2x * v
-	// y = y0 + e1y * u + e2y * v
-	// where 0 <= u && 0 <= v && u + v <= 1.
-	//
-	// We integrate u from [0,1-v] and then v from [0,1].
-	// We also need to use the Jacobian of the transformation:
-	// D = cross(e1, e2)
-	//
-	// Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
-	//
-	// The rest of the derivation is handled by computer algebra.
-
-	b2Assert(m_count >= 3);
-
-	b2Vec2 center; center.Set(0.0f, 0.0f);
-	float32 area = 0.0f;
-	float32 I = 0.0f;
-
-	// s is the reference point for forming triangles.
-	// It's location doesn't change the result (except for rounding error).
-	b2Vec2 s(0.0f, 0.0f);
-
-	// This code would put the reference point inside the polygon.
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		s += m_vertices[i];
-	}
-	s *= 1.0f / m_count;
-
-	const float32 k_inv3 = 1.0f / 3.0f;
-
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		// Triangle vertices.
-		b2Vec2 e1 = m_vertices[i] - s;
-		b2Vec2 e2 = i + 1 < m_count ? m_vertices[i+1] - s : m_vertices[0] - s;
-
-		float32 D = b2Cross(e1, e2);
-
-		float32 triangleArea = 0.5f * D;
-		area += triangleArea;
-
-		// Area weighted centroid
-		center += triangleArea * k_inv3 * (e1 + e2);
-
-		float32 ex1 = e1.x, ey1 = e1.y;
-		float32 ex2 = e2.x, ey2 = e2.y;
-
-		float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2;
-		float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2;
-
-		I += (0.25f * k_inv3 * D) * (intx2 + inty2);
-	}
-
-	// Total mass
-	massData->mass = density * area;
-
-	// Center of mass
-	b2Assert(area > b2_epsilon);
-	center *= 1.0f / area;
-	massData->center = center + s;
-
-	// Inertia tensor relative to the local origin (point s).
-	massData->I = density * I;
-	
-	// Shift to center of mass then to original body origin.
-	massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center));
-}
-
-bool b2PolygonShape::Validate() const
-{
-	for (int32 i = 0; i < m_count; ++i)
-	{
-		int32 i1 = i;
-		int32 i2 = i < m_count - 1 ? i1 + 1 : 0;
-		b2Vec2 p = m_vertices[i1];
-		b2Vec2 e = m_vertices[i2] - p;
-
-		for (int32 j = 0; j < m_count; ++j)
-		{
-			if (j == i1 || j == i2)
-			{
-				continue;
-			}
-
-			b2Vec2 v = m_vertices[j] - p;
-			float32 c = b2Cross(e, v);
-			if (c < 0.0f)
-			{
-				return false;
-			}
-		}
-	}
-
-	return true;
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <new>
+
+b2Shape* b2PolygonShape::Clone(b2BlockAllocator* allocator) const
+{
+	void* mem = allocator->Allocate(sizeof(b2PolygonShape));
+	b2PolygonShape* clone = new (mem) b2PolygonShape;
+	*clone = *this;
+	return clone;
+}
+
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy)
+{
+	m_count = 4;
+	m_vertices[0].Set(-hx, -hy);
+	m_vertices[1].Set( hx, -hy);
+	m_vertices[2].Set( hx,  hy);
+	m_vertices[3].Set(-hx,  hy);
+	m_normals[0].Set(0.0f, -1.0f);
+	m_normals[1].Set(1.0f, 0.0f);
+	m_normals[2].Set(0.0f, 1.0f);
+	m_normals[3].Set(-1.0f, 0.0f);
+	m_centroid.SetZero();
+}
+
+void b2PolygonShape::SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle)
+{
+	m_count = 4;
+	m_vertices[0].Set(-hx, -hy);
+	m_vertices[1].Set( hx, -hy);
+	m_vertices[2].Set( hx,  hy);
+	m_vertices[3].Set(-hx,  hy);
+	m_normals[0].Set(0.0f, -1.0f);
+	m_normals[1].Set(1.0f, 0.0f);
+	m_normals[2].Set(0.0f, 1.0f);
+	m_normals[3].Set(-1.0f, 0.0f);
+	m_centroid = center;
+
+	b2Transform xf;
+	xf.p = center;
+	xf.q.Set(angle);
+
+	// Transform vertices and normals.
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		m_vertices[i] = b2Mul(xf, m_vertices[i]);
+		m_normals[i] = b2Mul(xf.q, m_normals[i]);
+	}
+}
+
+int32 b2PolygonShape::GetChildCount() const
+{
+	return 1;
+}
+
+static b2Vec2 ComputeCentroid(const b2Vec2* vs, int32 count)
+{
+	b2Assert(count >= 3);
+
+	b2Vec2 c; c.Set(0.0f, 0.0f);
+	float32 area = 0.0f;
+
+	// pRef is the reference point for forming triangles.
+	// It's location doesn't change the result (except for rounding error).
+	b2Vec2 pRef(0.0f, 0.0f);
+#if 0
+	// This code would put the reference point inside the polygon.
+	for (int32 i = 0; i < count; ++i)
+	{
+		pRef += vs[i];
+	}
+	pRef *= 1.0f / count;
+#endif
+
+	const float32 inv3 = 1.0f / 3.0f;
+
+	for (int32 i = 0; i < count; ++i)
+	{
+		// Triangle vertices.
+		b2Vec2 p1 = pRef;
+		b2Vec2 p2 = vs[i];
+		b2Vec2 p3 = i + 1 < count ? vs[i+1] : vs[0];
+
+		b2Vec2 e1 = p2 - p1;
+		b2Vec2 e2 = p3 - p1;
+
+		float32 D = b2Cross(e1, e2);
+
+		float32 triangleArea = 0.5f * D;
+		area += triangleArea;
+
+		// Area weighted centroid
+		c += triangleArea * inv3 * (p1 + p2 + p3);
+	}
+
+	// Centroid
+	b2Assert(area > b2_epsilon);
+	c *= 1.0f / area;
+	return c;
+}
+
+void b2PolygonShape::Set(const b2Vec2* vertices, int32 count)
+{
+	b2Assert(3 <= count && count <= b2_maxPolygonVertices);
+	if (count < 3)
+	{
+		SetAsBox(1.0f, 1.0f);
+		return;
+	}
+	
+	int32 n = b2Min(count, b2_maxPolygonVertices);
+
+	// Perform welding and copy vertices into local buffer.
+	b2Vec2 ps[b2_maxPolygonVertices];
+	int32 tempCount = 0;
+	for (int32 i = 0; i < n; ++i)
+	{
+		b2Vec2 v = vertices[i];
+
+		bool unique = true;
+		for (int32 j = 0; j < tempCount; ++j)
+		{
+			if (b2DistanceSquared(v, ps[j]) < 0.5f * b2_linearSlop)
+			{
+				unique = false;
+				break;
+			}
+		}
+
+		if (unique)
+		{
+			ps[tempCount++] = v;
+		}
+	}
+
+	n = tempCount;
+	if (n < 3)
+	{
+		// Polygon is degenerate.
+		b2Assert(false);
+		SetAsBox(1.0f, 1.0f);
+		return;
+	}
+
+	// Create the convex hull using the Gift wrapping algorithm
+	// http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
+
+	// Find the right most point on the hull
+	int32 i0 = 0;
+	float32 x0 = ps[0].x;
+	for (int32 i = 1; i < n; ++i)
+	{
+		float32 x = ps[i].x;
+		if (x > x0 || (x == x0 && ps[i].y < ps[i0].y))
+		{
+			i0 = i;
+			x0 = x;
+		}
+	}
+
+	int32 hull[b2_maxPolygonVertices];
+	int32 m = 0;
+	int32 ih = i0;
+
+	for (;;)
+	{
+		hull[m] = ih;
+
+		int32 ie = 0;
+		for (int32 j = 1; j < n; ++j)
+		{
+			if (ie == ih)
+			{
+				ie = j;
+				continue;
+			}
+
+			b2Vec2 r = ps[ie] - ps[hull[m]];
+			b2Vec2 v = ps[j] - ps[hull[m]];
+			float32 c = b2Cross(r, v);
+			if (c < 0.0f)
+			{
+				ie = j;
+			}
+
+			// Collinearity check
+			if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
+			{
+				ie = j;
+			}
+		}
+
+		++m;
+		ih = ie;
+
+		if (ie == i0)
+		{
+			break;
+		}
+	}
+	
+	m_count = m;
+
+	// Copy vertices.
+	for (int32 i = 0; i < m; ++i)
+	{
+		m_vertices[i] = ps[hull[i]];
+	}
+
+	// Compute normals. Ensure the edges have non-zero length.
+	for (int32 i = 0; i < m; ++i)
+	{
+		int32 i1 = i;
+		int32 i2 = i + 1 < m ? i + 1 : 0;
+		b2Vec2 edge = m_vertices[i2] - m_vertices[i1];
+		b2Assert(edge.LengthSquared() > b2_epsilon * b2_epsilon);
+		m_normals[i] = b2Cross(edge, 1.0f);
+		m_normals[i].Normalize();
+	}
+
+	// Compute the polygon centroid.
+	m_centroid = ComputeCentroid(m_vertices, m);
+}
+
+bool b2PolygonShape::TestPoint(const b2Transform& xf, const b2Vec2& p) const
+{
+	b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
+
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
+		if (dot > 0.0f)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+void b2PolygonShape::ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 pLocal = b2MulT(xf.q, p - xf.p);
+	float32 maxDistance = -FLT_MAX;
+	b2Vec2 normalForMaxDistance = pLocal;
+
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
+		if (dot > maxDistance)
+		{
+			maxDistance = dot;
+			normalForMaxDistance = m_normals[i];
+		}
+	}
+
+	if (maxDistance > 0)
+	{
+		b2Vec2 minDistance = normalForMaxDistance;
+		float32 minDistance2 = maxDistance * maxDistance;
+		for (int32 i = 0; i < m_count; ++i)
+		{
+			b2Vec2 distance = pLocal - m_vertices[i];
+			float32 distance2 = distance.LengthSquared();
+			if (minDistance2 > distance2)
+			{
+				minDistance = distance;
+				minDistance2 = distance2;
+			}
+		}
+
+		*distance = b2Sqrt(minDistance2);
+		*normal = b2Mul(xf.q, minDistance);
+		normal->Normalize();
+	}
+	else
+	{
+		*distance = maxDistance;
+		*normal = b2Mul(xf.q, normalForMaxDistance);
+	}
+}
+
+bool b2PolygonShape::RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+								const b2Transform& xf, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	// Put the ray into the polygon's frame of reference.
+	b2Vec2 p1 = b2MulT(xf.q, input.p1 - xf.p);
+	b2Vec2 p2 = b2MulT(xf.q, input.p2 - xf.p);
+	b2Vec2 d = p2 - p1;
+
+	float32 lower = 0.0f, upper = input.maxFraction;
+
+	int32 index = -1;
+
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		// p = p1 + a * d
+		// dot(normal, p - v) = 0
+		// dot(normal, p1 - v) + a * dot(normal, d) = 0
+		float32 numerator = b2Dot(m_normals[i], m_vertices[i] - p1);
+		float32 denominator = b2Dot(m_normals[i], d);
+
+		if (denominator == 0.0f)
+		{	
+			if (numerator < 0.0f)
+			{
+				return false;
+			}
+		}
+		else
+		{
+			// Note: we want this predicate without division:
+			// lower < numerator / denominator, where denominator < 0
+			// Since denominator < 0, we have to flip the inequality:
+			// lower < numerator / denominator <==> denominator * lower > numerator.
+			if (denominator < 0.0f && numerator < lower * denominator)
+			{
+				// Increase lower.
+				// The segment enters this half-space.
+				lower = numerator / denominator;
+				index = i;
+			}
+			else if (denominator > 0.0f && numerator < upper * denominator)
+			{
+				// Decrease upper.
+				// The segment exits this half-space.
+				upper = numerator / denominator;
+			}
+		}
+
+		// The use of epsilon here causes the assert on lower to trip
+		// in some cases. Apparently the use of epsilon was to make edge
+		// shapes work, but now those are handled separately.
+		//if (upper < lower - b2_epsilon)
+		if (upper < lower)
+		{
+			return false;
+		}
+	}
+
+	b2Assert(0.0f <= lower && lower <= input.maxFraction);
+
+	if (index >= 0)
+	{
+		output->fraction = lower;
+		output->normal = b2Mul(xf.q, m_normals[index]);
+		return true;
+	}
+
+	return false;
+}
+
+void b2PolygonShape::ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const
+{
+	B2_NOT_USED(childIndex);
+
+	b2Vec2 lower = b2Mul(xf, m_vertices[0]);
+	b2Vec2 upper = lower;
+
+	for (int32 i = 1; i < m_count; ++i)
+	{
+		b2Vec2 v = b2Mul(xf, m_vertices[i]);
+		lower = b2Min(lower, v);
+		upper = b2Max(upper, v);
+	}
+
+	b2Vec2 r(m_radius, m_radius);
+	aabb->lowerBound = lower - r;
+	aabb->upperBound = upper + r;
+}
+
+void b2PolygonShape::ComputeMass(b2MassData* massData, float32 density) const
+{
+	// Polygon mass, centroid, and inertia.
+	// Let rho be the polygon density in mass per unit area.
+	// Then:
+	// mass = rho * int(dA)
+	// centroid.x = (1/mass) * rho * int(x * dA)
+	// centroid.y = (1/mass) * rho * int(y * dA)
+	// I = rho * int((x*x + y*y) * dA)
+	//
+	// We can compute these integrals by summing all the integrals
+	// for each triangle of the polygon. To evaluate the integral
+	// for a single triangle, we make a change of variables to
+	// the (u,v) coordinates of the triangle:
+	// x = x0 + e1x * u + e2x * v
+	// y = y0 + e1y * u + e2y * v
+	// where 0 <= u && 0 <= v && u + v <= 1.
+	//
+	// We integrate u from [0,1-v] and then v from [0,1].
+	// We also need to use the Jacobian of the transformation:
+	// D = cross(e1, e2)
+	//
+	// Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
+	//
+	// The rest of the derivation is handled by computer algebra.
+
+	b2Assert(m_count >= 3);
+
+	b2Vec2 center; center.Set(0.0f, 0.0f);
+	float32 area = 0.0f;
+	float32 I = 0.0f;
+
+	// s is the reference point for forming triangles.
+	// It's location doesn't change the result (except for rounding error).
+	b2Vec2 s(0.0f, 0.0f);
+
+	// This code would put the reference point inside the polygon.
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		s += m_vertices[i];
+	}
+	s *= 1.0f / m_count;
+
+	const float32 k_inv3 = 1.0f / 3.0f;
+
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		// Triangle vertices.
+		b2Vec2 e1 = m_vertices[i] - s;
+		b2Vec2 e2 = i + 1 < m_count ? m_vertices[i+1] - s : m_vertices[0] - s;
+
+		float32 D = b2Cross(e1, e2);
+
+		float32 triangleArea = 0.5f * D;
+		area += triangleArea;
+
+		// Area weighted centroid
+		center += triangleArea * k_inv3 * (e1 + e2);
+
+		float32 ex1 = e1.x, ey1 = e1.y;
+		float32 ex2 = e2.x, ey2 = e2.y;
+
+		float32 intx2 = ex1*ex1 + ex2*ex1 + ex2*ex2;
+		float32 inty2 = ey1*ey1 + ey2*ey1 + ey2*ey2;
+
+		I += (0.25f * k_inv3 * D) * (intx2 + inty2);
+	}
+
+	// Total mass
+	massData->mass = density * area;
+
+	// Center of mass
+	b2Assert(area > b2_epsilon);
+	center *= 1.0f / area;
+	massData->center = center + s;
+
+	// Inertia tensor relative to the local origin (point s).
+	massData->I = density * I;
+	
+	// Shift to center of mass then to original body origin.
+	massData->I += massData->mass * (b2Dot(massData->center, massData->center) - b2Dot(center, center));
+}
+
+bool b2PolygonShape::Validate() const
+{
+	for (int32 i = 0; i < m_count; ++i)
+	{
+		int32 i1 = i;
+		int32 i2 = i < m_count - 1 ? i1 + 1 : 0;
+		b2Vec2 p = m_vertices[i1];
+		b2Vec2 e = m_vertices[i2] - p;
+
+		for (int32 j = 0; j < m_count; ++j)
+		{
+			if (j == i1 || j == i2)
+			{
+				continue;
+			}
+
+			b2Vec2 v = m_vertices[j] - p;
+			float32 c = b2Cross(e, v);
+			if (c < 0.0f)
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}

+ 134 - 101
engine/source/Box2D/Collision/Shapes/b2PolygonShape.h

@@ -1,101 +1,134 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_POLYGON_SHAPE_H
-#define B2_POLYGON_SHAPE_H
-
-#include <Box2D/Collision/Shapes/b2Shape.h>
-
-/// A convex polygon. It is assumed that the interior of the polygon is to
-/// the left of each edge.
-/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
-/// In most cases you should not need many vertices for a convex polygon.
-class b2PolygonShape : public b2Shape
-{
-public:
-	b2PolygonShape();
-
-	/// Implement b2Shape.
-	b2Shape* Clone(b2BlockAllocator* allocator) const;
-
-	/// @see b2Shape::GetChildCount
-	int32 GetChildCount() const;
-
-	/// Create a convex hull from the given array of local points.
-	/// The count must be in the range [3, b2_maxPolygonVertices].
-	/// @warning the points may be re-ordered, even if they form a convex polygon
-	/// @warning collinear points are handled but not removed. Collinear points
-	/// may lead to poor stacking behavior.
-	void Set(const b2Vec2* points, int32 count);
-
-	/// Build vertices to represent an axis-aligned box centered on the local origin.
-	/// @param hx the half-width.
-	/// @param hy the half-height.
-	void SetAsBox(float32 hx, float32 hy);
-
-	/// Build vertices to represent an oriented box.
-	/// @param hx the half-width.
-	/// @param hy the half-height.
-	/// @param center the center of the box in local coordinates.
-	/// @param angle the rotation of the box in local coordinates.
-	void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
-
-	/// @see b2Shape::TestPoint
-	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
-
-	/// Implement b2Shape.
-	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-					const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeAABB
-	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
-
-	/// @see b2Shape::ComputeMass
-	void ComputeMass(b2MassData* massData, float32 density) const;
-
-	/// Get the vertex count.
-	int32 GetVertexCount() const { return m_count; }
-
-	/// Get a vertex by index.
-	const b2Vec2& GetVertex(int32 index) const;
-
-	/// Validate convexity. This is a very time consuming operation.
-	/// @returns true if valid
-	bool Validate() const;
-
-	b2Vec2 m_centroid;
-	b2Vec2 m_vertices[b2_maxPolygonVertices];
-	b2Vec2 m_normals[b2_maxPolygonVertices];
-	int32 m_count;
-};
-
-inline b2PolygonShape::b2PolygonShape()
-{
-	m_type = e_polygon;
-	m_radius = b2_polygonRadius;
-	m_count = 0;
-	m_centroid.SetZero();
-}
-
-inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
-{
-	b2Assert(0 <= index && index < m_count);
-	return m_vertices[index];
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_POLYGON_SHAPE_H
+#define B2_POLYGON_SHAPE_H
+
+#include <Box2D/Collision/Shapes/b2Shape.h>
+
+/// A convex polygon. It is assumed that the interior of the polygon is to
+/// the left of each edge.
+/// Polygons have a maximum number of vertices equal to b2_maxPolygonVertices.
+/// In most cases you should not need many vertices for a convex polygon.
+class b2PolygonShape : public b2Shape
+{
+public:
+	b2PolygonShape();
+
+	/// Implement b2Shape.
+	b2Shape* Clone(b2BlockAllocator* allocator) const;
+
+	/// @see b2Shape::GetChildCount
+	int32 GetChildCount() const;
+
+	/// Create a convex hull from the given array of local points.
+	/// The count must be in the range [3, b2_maxPolygonVertices].
+	/// @warning the points may be re-ordered, even if they form a convex polygon
+	/// @warning collinear points are handled but not removed. Collinear points
+	/// may lead to poor stacking behavior.
+	void Set(const b2Vec2* points, int32 count);
+
+	/// Build vertices to represent an axis-aligned box centered on the local origin.
+	/// @param hx the half-width.
+	/// @param hy the half-height.
+	void SetAsBox(float32 hx, float32 hy);
+
+	/// Build vertices to represent an oriented box.
+	/// @param hx the half-width.
+	/// @param hy the half-height.
+	/// @param center the center of the box in local coordinates.
+	/// @param angle the rotation of the box in local coordinates.
+	void SetAsBox(float32 hx, float32 hy, const b2Vec2& center, float32 angle);
+
+	/// @see b2Shape::TestPoint
+	bool TestPoint(const b2Transform& transform, const b2Vec2& p) const;
+
+	// @see b2Shape::ComputeDistance
+	void ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const;
+
+	/// Implement b2Shape.
+	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+					const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeAABB
+	void ComputeAABB(b2AABB* aabb, const b2Transform& transform, int32 childIndex) const;
+
+	/// @see b2Shape::ComputeMass
+	void ComputeMass(b2MassData* massData, float32 density) const;
+
+	/// Get the vertex count.
+	int32 GetVertexCount() const { return m_count; }
+
+	/// Get a vertex by index.
+	const b2Vec2& GetVertex(int32 index) const;
+
+	/// Validate convexity. This is a very time consuming operation.
+	/// @returns true if valid
+	bool Validate() const;
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+public:
+	/// Set centroid with direct floats.
+	void SetCentroid(float32 x, float32 y);
+
+	/// SetAsBox with direct floats for center.
+	/// @see b2Shape::SetAsBox
+	void SetAsBox(float32 hx,
+								float32 hy,
+								float32 centerX,
+								float32 centerY,
+								float32 angle);
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+	b2Vec2 m_centroid;
+	b2Vec2 m_vertices[b2_maxPolygonVertices];
+	b2Vec2 m_normals[b2_maxPolygonVertices];
+	int32 m_count;
+};
+
+inline b2PolygonShape::b2PolygonShape()
+{
+	m_type = e_polygon;
+	m_radius = b2_polygonRadius;
+	m_count = 0;
+	m_centroid.SetZero();
+}
+
+inline const b2Vec2& b2PolygonShape::GetVertex(int32 index) const
+{
+	b2Assert(0 <= index && index < m_count);
+	return m_vertices[index];
+}
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+inline void b2PolygonShape::SetCentroid(float32 x, float32 y)
+{
+	m_centroid.Set(x, y);
+}
+
+inline void b2PolygonShape::SetAsBox(float32 hx,
+										 float32 hy,
+										 float32 centerX,
+										 float32 centerY,
+										 float32 angle) {
+	SetAsBox(hx, hy, b2Vec2(centerX, centerY), angle);
+}
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+#endif

+ 109 - 101
engine/source/Box2D/Collision/Shapes/b2Shape.h

@@ -1,101 +1,109 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_SHAPE_H
-#define B2_SHAPE_H
-
-#include <Box2D/Common/b2BlockAllocator.h>
-#include <Box2D/Common/b2Math.h>
-#include <Box2D/Collision/b2Collision.h>
-
-/// This holds the mass data computed for a shape.
-struct b2MassData
-{
-	/// The mass of the shape, usually in kilograms.
-	float32 mass;
-
-	/// The position of the shape's centroid relative to the shape's origin.
-	b2Vec2 center;
-
-	/// The rotational inertia of the shape about the local origin.
-	float32 I;
-};
-
-/// A shape is used for collision detection. You can create a shape however you like.
-/// Shapes used for simulation in b2World are created automatically when a b2Fixture
-/// is created. Shapes may encapsulate a one or more child shapes.
-class b2Shape
-{
-public:
-	
-	enum Type
-	{
-		e_circle = 0,
-		e_edge = 1,
-		e_polygon = 2,
-		e_chain = 3,
-		e_typeCount = 4
-	};
-
-	virtual ~b2Shape() {}
-
-	/// Clone the concrete shape using the provided allocator.
-	virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
-
-	/// Get the type of this shape. You can use this to down cast to the concrete shape.
-	/// @return the shape type.
-	Type GetType() const;
-
-	/// Get the number of child primitives.
-	virtual int32 GetChildCount() const = 0;
-
-	/// Test a point for containment in this shape. This only works for convex shapes.
-	/// @param xf the shape world transform.
-	/// @param p a point in world coordinates.
-	virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
-
-	/// Cast a ray against a child shape.
-	/// @param output the ray-cast results.
-	/// @param input the ray-cast input parameters.
-	/// @param transform the transform to be applied to the shape.
-	/// @param childIndex the child shape index
-	virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
-						const b2Transform& transform, int32 childIndex) const = 0;
-
-	/// Given a transform, compute the associated axis aligned bounding box for a child shape.
-	/// @param aabb returns the axis aligned box.
-	/// @param xf the world transform of the shape.
-	/// @param childIndex the child shape
-	virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0;
-
-	/// Compute the mass properties of this shape using its dimensions and density.
-	/// The inertia tensor is computed about the local origin.
-	/// @param massData returns the mass data for this shape.
-	/// @param density the density in kilograms per meter squared.
-	virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;
-
-	Type m_type;
-	float32 m_radius;
-};
-
-inline b2Shape::Type b2Shape::GetType() const
-{
-	return m_type;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_SHAPE_H
+#define B2_SHAPE_H
+
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Collision.h>
+
+/// This holds the mass data computed for a shape.
+struct b2MassData
+{
+	/// The mass of the shape, usually in kilograms.
+	float32 mass;
+
+	/// The position of the shape's centroid relative to the shape's origin.
+	b2Vec2 center;
+
+	/// The rotational inertia of the shape about the local origin.
+	float32 I;
+};
+
+/// A shape is used for collision detection. You can create a shape however you like.
+/// Shapes used for simulation in b2World are created automatically when a b2Fixture
+/// is created. Shapes may encapsulate a one or more child shapes.
+class b2Shape
+{
+public:
+	
+	enum Type
+	{
+		e_circle = 0,
+		e_edge = 1,
+		e_polygon = 2,
+		e_chain = 3,
+		e_typeCount = 4
+	};
+
+	virtual ~b2Shape() {}
+
+	/// Clone the concrete shape using the provided allocator.
+	virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
+
+	/// Get the type of this shape. You can use this to down cast to the concrete shape.
+	/// @return the shape type.
+	Type GetType() const;
+
+	/// Get the number of child primitives.
+	virtual int32 GetChildCount() const = 0;
+
+	/// Test a point for containment in this shape. This only works for convex shapes.
+	/// @param xf the shape world transform.
+	/// @param p a point in world coordinates.
+	virtual bool TestPoint(const b2Transform& xf, const b2Vec2& p) const = 0;
+
+	/// Compute the distance from the current shape to the specified point. This only works for convex shapes.
+	/// @param xf the shape world transform.
+	/// @param p a point in world coordinates.
+	/// @param distance returns the distance from the current shape.
+	/// @param normal returns the direction in which the distance increases.
+	virtual void ComputeDistance(const b2Transform& xf, const b2Vec2& p, float32* distance, b2Vec2* normal, int32 childIndex) const= 0;
+
+	/// Cast a ray against a child shape.
+	/// @param output the ray-cast results.
+	/// @param input the ray-cast input parameters.
+	/// @param transform the transform to be applied to the shape.
+	/// @param childIndex the child shape index
+	virtual bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input,
+						const b2Transform& transform, int32 childIndex) const = 0;
+
+	/// Given a transform, compute the associated axis aligned bounding box for a child shape.
+	/// @param aabb returns the axis aligned box.
+	/// @param xf the world transform of the shape.
+	/// @param childIndex the child shape
+	virtual void ComputeAABB(b2AABB* aabb, const b2Transform& xf, int32 childIndex) const = 0;
+
+	/// Compute the mass properties of this shape using its dimensions and density.
+	/// The inertia tensor is computed about the local origin.
+	/// @param massData returns the mass data for this shape.
+	/// @param density the density in kilograms per meter squared.
+	virtual void ComputeMass(b2MassData* massData, float32 density) const = 0;
+
+	Type m_type;
+	float32 m_radius;
+};
+
+inline b2Shape::Type b2Shape::GetType() const
+{
+	return m_type;
+}
+
+#endif

+ 119 - 121
engine/source/Box2D/Collision/b2BroadPhase.cpp

@@ -1,121 +1,119 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2BroadPhase.h>
-#include <cstring>
-using namespace std;
-
-b2BroadPhase::b2BroadPhase()
-{
-	m_proxyCount = 0;
-
-	m_pairCapacity = 16;
-	m_pairCount = 0;
-	m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
-
-	m_moveCapacity = 16;
-	m_moveCount = 0;
-	m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
-}
-
-b2BroadPhase::~b2BroadPhase()
-{
-	b2Free(m_moveBuffer);
-	b2Free(m_pairBuffer);
-}
-
-int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)
-{
-	int32 proxyId = m_tree.CreateProxy(aabb, userData);
-	++m_proxyCount;
-	BufferMove(proxyId);
-	return proxyId;
-}
-
-void b2BroadPhase::DestroyProxy(int32 proxyId)
-{
-	UnBufferMove(proxyId);
-	--m_proxyCount;
-	m_tree.DestroyProxy(proxyId);
-}
-
-void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
-{
-	bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement);
-	if (buffer)
-	{
-		BufferMove(proxyId);
-	}
-}
-
-void b2BroadPhase::TouchProxy(int32 proxyId)
-{
-	BufferMove(proxyId);
-}
-
-void b2BroadPhase::BufferMove(int32 proxyId)
-{
-	if (m_moveCount == m_moveCapacity)
-	{
-		int32* oldBuffer = m_moveBuffer;
-		m_moveCapacity *= 2;
-		m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
-		memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32));
-		b2Free(oldBuffer);
-	}
-
-	m_moveBuffer[m_moveCount] = proxyId;
-	++m_moveCount;
-}
-
-void b2BroadPhase::UnBufferMove(int32 proxyId)
-{
-	for (int32 i = 0; i < m_moveCount; ++i)
-	{
-		if (m_moveBuffer[i] == proxyId)
-		{
-			m_moveBuffer[i] = e_nullProxy;
-		}
-	}
-}
-
-// This is called from b2DynamicTree::Query when we are gathering pairs.
-bool b2BroadPhase::QueryCallback(int32 proxyId)
-{
-	// A proxy cannot form a pair with itself.
-	if (proxyId == m_queryProxyId)
-	{
-		return true;
-	}
-
-	// Grow the pair buffer as needed.
-	if (m_pairCount == m_pairCapacity)
-	{
-		b2Pair* oldBuffer = m_pairBuffer;
-		m_pairCapacity *= 2;
-		m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
-		memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
-		b2Free(oldBuffer);
-	}
-
-	m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);
-	m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);
-	++m_pairCount;
-
-	return true;
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2BroadPhase.h>
+
+b2BroadPhase::b2BroadPhase()
+{
+	m_proxyCount = 0;
+
+	m_pairCapacity = 16;
+	m_pairCount = 0;
+	m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
+
+	m_moveCapacity = 16;
+	m_moveCount = 0;
+	m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
+}
+
+b2BroadPhase::~b2BroadPhase()
+{
+	b2Free(m_moveBuffer);
+	b2Free(m_pairBuffer);
+}
+
+int32 b2BroadPhase::CreateProxy(const b2AABB& aabb, void* userData)
+{
+	int32 proxyId = m_tree.CreateProxy(aabb, userData);
+	++m_proxyCount;
+	BufferMove(proxyId);
+	return proxyId;
+}
+
+void b2BroadPhase::DestroyProxy(int32 proxyId)
+{
+	UnBufferMove(proxyId);
+	--m_proxyCount;
+	m_tree.DestroyProxy(proxyId);
+}
+
+void b2BroadPhase::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
+{
+	bool buffer = m_tree.MoveProxy(proxyId, aabb, displacement);
+	if (buffer)
+	{
+		BufferMove(proxyId);
+	}
+}
+
+void b2BroadPhase::TouchProxy(int32 proxyId)
+{
+	BufferMove(proxyId);
+}
+
+void b2BroadPhase::BufferMove(int32 proxyId)
+{
+	if (m_moveCount == m_moveCapacity)
+	{
+		int32* oldBuffer = m_moveBuffer;
+		m_moveCapacity *= 2;
+		m_moveBuffer = (int32*)b2Alloc(m_moveCapacity * sizeof(int32));
+		memcpy(m_moveBuffer, oldBuffer, m_moveCount * sizeof(int32));
+		b2Free(oldBuffer);
+	}
+
+	m_moveBuffer[m_moveCount] = proxyId;
+	++m_moveCount;
+}
+
+void b2BroadPhase::UnBufferMove(int32 proxyId)
+{
+	for (int32 i = 0; i < m_moveCount; ++i)
+	{
+		if (m_moveBuffer[i] == proxyId)
+		{
+			m_moveBuffer[i] = e_nullProxy;
+		}
+	}
+}
+
+// This is called from b2DynamicTree::Query when we are gathering pairs.
+bool b2BroadPhase::QueryCallback(int32 proxyId)
+{
+	// A proxy cannot form a pair with itself.
+	if (proxyId == m_queryProxyId)
+	{
+		return true;
+	}
+
+	// Grow the pair buffer as needed.
+	if (m_pairCount == m_pairCapacity)
+	{
+		b2Pair* oldBuffer = m_pairBuffer;
+		m_pairCapacity *= 2;
+		m_pairBuffer = (b2Pair*)b2Alloc(m_pairCapacity * sizeof(b2Pair));
+		memcpy(m_pairBuffer, oldBuffer, m_pairCount * sizeof(b2Pair));
+		b2Free(oldBuffer);
+	}
+
+	m_pairBuffer[m_pairCount].proxyIdA = b2Min(proxyId, m_queryProxyId);
+	m_pairBuffer[m_pairCount].proxyIdB = b2Max(proxyId, m_queryProxyId);
+	++m_pairCount;
+
+	return true;
+}

+ 257 - 257
engine/source/Box2D/Collision/b2BroadPhase.h

@@ -1,257 +1,257 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_BROAD_PHASE_H
-#define B2_BROAD_PHASE_H
-
-#include <Box2D/Common/b2Settings.h>
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/b2DynamicTree.h>
-#include <algorithm>
-
-struct b2Pair
-{
-	int32 proxyIdA;
-	int32 proxyIdB;
-};
-
-/// The broad-phase is used for computing pairs and performing volume queries and ray casts.
-/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
-/// It is up to the client to consume the new pairs and to track subsequent overlap.
-class b2BroadPhase
-{
-public:
-
-	enum
-	{
-		e_nullProxy = -1
-	};
-
-	b2BroadPhase();
-	~b2BroadPhase();
-
-	/// Create a proxy with an initial AABB. Pairs are not reported until
-	/// UpdatePairs is called.
-	int32 CreateProxy(const b2AABB& aabb, void* userData);
-
-	/// Destroy a proxy. It is up to the client to remove any pairs.
-	void DestroyProxy(int32 proxyId);
-
-	/// Call MoveProxy as many times as you like, then when you are done
-	/// call UpdatePairs to finalized the proxy pairs (for your time step).
-	void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);
-
-	/// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
-	void TouchProxy(int32 proxyId);
-
-	/// Get the fat AABB for a proxy.
-	const b2AABB& GetFatAABB(int32 proxyId) const;
-
-	/// Get user data from a proxy. Returns NULL if the id is invalid.
-	void* GetUserData(int32 proxyId) const;
-
-	/// Test overlap of fat AABBs.
-	bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const;
-
-	/// Get the number of proxies.
-	int32 GetProxyCount() const;
-
-	/// Update the pairs. This results in pair callbacks. This can only add pairs.
-	template <typename T>
-	void UpdatePairs(T* callback);
-
-	/// Query an AABB for overlapping proxies. The callback class
-	/// is called for each proxy that overlaps the supplied AABB.
-	template <typename T>
-	void Query(T* callback, const b2AABB& aabb) const;
-
-	/// Ray-cast against the proxies in the tree. This relies on the callback
-	/// to perform a exact ray-cast in the case were the proxy contains a shape.
-	/// The callback also performs the any collision filtering. This has performance
-	/// roughly equal to k * log(n), where k is the number of collisions and n is the
-	/// number of proxies in the tree.
-	/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
-	/// @param callback a callback class that is called for each proxy that is hit by the ray.
-	template <typename T>
-	void RayCast(T* callback, const b2RayCastInput& input) const;
-
-	/// Get the height of the embedded tree.
-	int32 GetTreeHeight() const;
-
-	/// Get the balance of the embedded tree.
-	int32 GetTreeBalance() const;
-
-	/// Get the quality metric of the embedded tree.
-	float32 GetTreeQuality() const;
-
-	/// Shift the world origin. Useful for large worlds.
-	/// The shift formula is: position -= newOrigin
-	/// @param newOrigin the new origin with respect to the old origin
-	void ShiftOrigin(const b2Vec2& newOrigin);
-
-private:
-
-	friend class b2DynamicTree;
-
-	void BufferMove(int32 proxyId);
-	void UnBufferMove(int32 proxyId);
-
-	bool QueryCallback(int32 proxyId);
-
-	b2DynamicTree m_tree;
-
-	int32 m_proxyCount;
-
-	int32* m_moveBuffer;
-	int32 m_moveCapacity;
-	int32 m_moveCount;
-
-	b2Pair* m_pairBuffer;
-	int32 m_pairCapacity;
-	int32 m_pairCount;
-
-	int32 m_queryProxyId;
-};
-
-/// This is used to sort pairs.
-inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)
-{
-	if (pair1.proxyIdA < pair2.proxyIdA)
-	{
-		return true;
-	}
-
-	if (pair1.proxyIdA == pair2.proxyIdA)
-	{
-		return pair1.proxyIdB < pair2.proxyIdB;
-	}
-
-	return false;
-}
-
-inline void* b2BroadPhase::GetUserData(int32 proxyId) const
-{
-	return m_tree.GetUserData(proxyId);
-}
-
-inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const
-{
-	const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA);
-	const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB);
-	return b2TestOverlap(aabbA, aabbB);
-}
-
-inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const
-{
-	return m_tree.GetFatAABB(proxyId);
-}
-
-inline int32 b2BroadPhase::GetProxyCount() const
-{
-	return m_proxyCount;
-}
-
-inline int32 b2BroadPhase::GetTreeHeight() const
-{
-	return m_tree.GetHeight();
-}
-
-inline int32 b2BroadPhase::GetTreeBalance() const
-{
-	return m_tree.GetMaxBalance();
-}
-
-inline float32 b2BroadPhase::GetTreeQuality() const
-{
-	return m_tree.GetAreaRatio();
-}
-
-template <typename T>
-void b2BroadPhase::UpdatePairs(T* callback)
-{
-	// Reset pair buffer
-	m_pairCount = 0;
-
-	// Perform tree queries for all moving proxies.
-	for (int32 i = 0; i < m_moveCount; ++i)
-	{
-		m_queryProxyId = m_moveBuffer[i];
-		if (m_queryProxyId == e_nullProxy)
-		{
-			continue;
-		}
-
-		// We have to query the tree with the fat AABB so that
-		// we don't fail to create a pair that may touch later.
-		const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId);
-
-		// Query tree, create pairs and add them pair buffer.
-		m_tree.Query(this, fatAABB);
-	}
-
-	// Reset move buffer
-	m_moveCount = 0;
-
-	// Sort the pair buffer to expose duplicates.
-	std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);
-
-	// Send the pairs back to the client.
-	int32 i = 0;
-	while (i < m_pairCount)
-	{
-		b2Pair* primaryPair = m_pairBuffer + i;
-		void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);
-		void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);
-
-		callback->AddPair(userDataA, userDataB);
-		++i;
-
-		// Skip any duplicate pairs.
-		while (i < m_pairCount)
-		{
-			b2Pair* pair = m_pairBuffer + i;
-			if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
-			{
-				break;
-			}
-			++i;
-		}
-	}
-
-	// Try to keep the tree balanced.
-	//m_tree.Rebalance(4);
-}
-
-template <typename T>
-inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
-{
-	m_tree.Query(callback, aabb);
-}
-
-template <typename T>
-inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const
-{
-	m_tree.RayCast(callback, input);
-}
-
-inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin)
-{
-	m_tree.ShiftOrigin(newOrigin);
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_BROAD_PHASE_H
+#define B2_BROAD_PHASE_H
+
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <algorithm>
+
+struct b2Pair
+{
+	int32 proxyIdA;
+	int32 proxyIdB;
+};
+
+/// The broad-phase is used for computing pairs and performing volume queries and ray casts.
+/// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
+/// It is up to the client to consume the new pairs and to track subsequent overlap.
+class b2BroadPhase
+{
+public:
+
+	enum
+	{
+		e_nullProxy = -1
+	};
+
+	b2BroadPhase();
+	~b2BroadPhase();
+
+	/// Create a proxy with an initial AABB. Pairs are not reported until
+	/// UpdatePairs is called.
+	int32 CreateProxy(const b2AABB& aabb, void* userData);
+
+	/// Destroy a proxy. It is up to the client to remove any pairs.
+	void DestroyProxy(int32 proxyId);
+
+	/// Call MoveProxy as many times as you like, then when you are done
+	/// call UpdatePairs to finalized the proxy pairs (for your time step).
+	void MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement);
+
+	/// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
+	void TouchProxy(int32 proxyId);
+
+	/// Get the fat AABB for a proxy.
+	const b2AABB& GetFatAABB(int32 proxyId) const;
+
+	/// Get user data from a proxy. Returns NULL if the id is invalid.
+	void* GetUserData(int32 proxyId) const;
+
+	/// Test overlap of fat AABBs.
+	bool TestOverlap(int32 proxyIdA, int32 proxyIdB) const;
+
+	/// Get the number of proxies.
+	int32 GetProxyCount() const;
+
+	/// Update the pairs. This results in pair callbacks. This can only add pairs.
+	template <typename T>
+	void UpdatePairs(T* callback);
+
+	/// Query an AABB for overlapping proxies. The callback class
+	/// is called for each proxy that overlaps the supplied AABB.
+	template <typename T>
+	void Query(T* callback, const b2AABB& aabb) const;
+
+	/// Ray-cast against the proxies in the tree. This relies on the callback
+	/// to perform a exact ray-cast in the case were the proxy contains a shape.
+	/// The callback also performs the any collision filtering. This has performance
+	/// roughly equal to k * log(n), where k is the number of collisions and n is the
+	/// number of proxies in the tree.
+	/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+	/// @param callback a callback class that is called for each proxy that is hit by the ray.
+	template <typename T>
+	void RayCast(T* callback, const b2RayCastInput& input) const;
+
+	/// Get the height of the embedded tree.
+	int32 GetTreeHeight() const;
+
+	/// Get the balance of the embedded tree.
+	int32 GetTreeBalance() const;
+
+	/// Get the quality metric of the embedded tree.
+	float32 GetTreeQuality() const;
+
+	/// Shift the world origin. Useful for large worlds.
+	/// The shift formula is: position -= newOrigin
+	/// @param newOrigin the new origin with respect to the old origin
+	void ShiftOrigin(const b2Vec2& newOrigin);
+
+private:
+
+	friend class b2DynamicTree;
+
+	void BufferMove(int32 proxyId);
+	void UnBufferMove(int32 proxyId);
+
+	bool QueryCallback(int32 proxyId);
+
+	b2DynamicTree m_tree;
+
+	int32 m_proxyCount;
+
+	int32* m_moveBuffer;
+	int32 m_moveCapacity;
+	int32 m_moveCount;
+
+	b2Pair* m_pairBuffer;
+	int32 m_pairCapacity;
+	int32 m_pairCount;
+
+	int32 m_queryProxyId;
+};
+
+/// This is used to sort pairs.
+inline bool b2PairLessThan(const b2Pair& pair1, const b2Pair& pair2)
+{
+	if (pair1.proxyIdA < pair2.proxyIdA)
+	{
+		return true;
+	}
+
+	if (pair1.proxyIdA == pair2.proxyIdA)
+	{
+		return pair1.proxyIdB < pair2.proxyIdB;
+	}
+
+	return false;
+}
+
+inline void* b2BroadPhase::GetUserData(int32 proxyId) const
+{
+	return m_tree.GetUserData(proxyId);
+}
+
+inline bool b2BroadPhase::TestOverlap(int32 proxyIdA, int32 proxyIdB) const
+{
+	const b2AABB& aabbA = m_tree.GetFatAABB(proxyIdA);
+	const b2AABB& aabbB = m_tree.GetFatAABB(proxyIdB);
+	return b2TestOverlap(aabbA, aabbB);
+}
+
+inline const b2AABB& b2BroadPhase::GetFatAABB(int32 proxyId) const
+{
+	return m_tree.GetFatAABB(proxyId);
+}
+
+inline int32 b2BroadPhase::GetProxyCount() const
+{
+	return m_proxyCount;
+}
+
+inline int32 b2BroadPhase::GetTreeHeight() const
+{
+	return m_tree.GetHeight();
+}
+
+inline int32 b2BroadPhase::GetTreeBalance() const
+{
+	return m_tree.GetMaxBalance();
+}
+
+inline float32 b2BroadPhase::GetTreeQuality() const
+{
+	return m_tree.GetAreaRatio();
+}
+
+template <typename T>
+void b2BroadPhase::UpdatePairs(T* callback)
+{
+	// Reset pair buffer
+	m_pairCount = 0;
+
+	// Perform tree queries for all moving proxies.
+	for (int32 i = 0; i < m_moveCount; ++i)
+	{
+		m_queryProxyId = m_moveBuffer[i];
+		if (m_queryProxyId == e_nullProxy)
+		{
+			continue;
+		}
+
+		// We have to query the tree with the fat AABB so that
+		// we don't fail to create a pair that may touch later.
+		const b2AABB& fatAABB = m_tree.GetFatAABB(m_queryProxyId);
+
+		// Query tree, create pairs and add them pair buffer.
+		m_tree.Query(this, fatAABB);
+	}
+
+	// Reset move buffer
+	m_moveCount = 0;
+
+	// Sort the pair buffer to expose duplicates.
+	std::sort(m_pairBuffer, m_pairBuffer + m_pairCount, b2PairLessThan);
+
+	// Send the pairs back to the client.
+	int32 i = 0;
+	while (i < m_pairCount)
+	{
+		b2Pair* primaryPair = m_pairBuffer + i;
+		void* userDataA = m_tree.GetUserData(primaryPair->proxyIdA);
+		void* userDataB = m_tree.GetUserData(primaryPair->proxyIdB);
+
+		callback->AddPair(userDataA, userDataB);
+		++i;
+
+		// Skip any duplicate pairs.
+		while (i < m_pairCount)
+		{
+			b2Pair* pair = m_pairBuffer + i;
+			if (pair->proxyIdA != primaryPair->proxyIdA || pair->proxyIdB != primaryPair->proxyIdB)
+			{
+				break;
+			}
+			++i;
+		}
+	}
+
+	// Try to keep the tree balanced.
+	//m_tree.Rebalance(4);
+}
+
+template <typename T>
+inline void b2BroadPhase::Query(T* callback, const b2AABB& aabb) const
+{
+	m_tree.Query(callback, aabb);
+}
+
+template <typename T>
+inline void b2BroadPhase::RayCast(T* callback, const b2RayCastInput& input) const
+{
+	m_tree.RayCast(callback, input);
+}
+
+inline void b2BroadPhase::ShiftOrigin(const b2Vec2& newOrigin)
+{
+	m_tree.ShiftOrigin(newOrigin);
+}
+
+#endif

+ 154 - 154
engine/source/Box2D/Collision/b2CollideCircle.cpp

@@ -1,154 +1,154 @@
-/*
-* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-void b2CollideCircles(
-	b2Manifold* manifold,
-	const b2CircleShape* circleA, const b2Transform& xfA,
-	const b2CircleShape* circleB, const b2Transform& xfB)
-{
-	manifold->pointCount = 0;
-
-	b2Vec2 pA = b2Mul(xfA, circleA->m_p);
-	b2Vec2 pB = b2Mul(xfB, circleB->m_p);
-
-	b2Vec2 d = pB - pA;
-	float32 distSqr = b2Dot(d, d);
-	float32 rA = circleA->m_radius, rB = circleB->m_radius;
-	float32 radius = rA + rB;
-	if (distSqr > radius * radius)
-	{
-		return;
-	}
-
-	manifold->type = b2Manifold::e_circles;
-	manifold->localPoint = circleA->m_p;
-	manifold->localNormal.SetZero();
-	manifold->pointCount = 1;
-
-	manifold->points[0].localPoint = circleB->m_p;
-	manifold->points[0].id.key = 0;
-}
-
-void b2CollidePolygonAndCircle(
-	b2Manifold* manifold,
-	const b2PolygonShape* polygonA, const b2Transform& xfA,
-	const b2CircleShape* circleB, const b2Transform& xfB)
-{
-	manifold->pointCount = 0;
-
-	// Compute circle position in the frame of the polygon.
-	b2Vec2 c = b2Mul(xfB, circleB->m_p);
-	b2Vec2 cLocal = b2MulT(xfA, c);
-
-	// Find the min separating edge.
-	int32 normalIndex = 0;
-	float32 separation = -b2_maxFloat;
-	float32 radius = polygonA->m_radius + circleB->m_radius;
-	int32 vertexCount = polygonA->m_count;
-	const b2Vec2* vertices = polygonA->m_vertices;
-	const b2Vec2* normals = polygonA->m_normals;
-
-	for (int32 i = 0; i < vertexCount; ++i)
-	{
-		float32 s = b2Dot(normals[i], cLocal - vertices[i]);
-
-		if (s > radius)
-		{
-			// Early out.
-			return;
-		}
-
-		if (s > separation)
-		{
-			separation = s;
-			normalIndex = i;
-		}
-	}
-
-	// Vertices that subtend the incident face.
-	int32 vertIndex1 = normalIndex;
-	int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
-	b2Vec2 v1 = vertices[vertIndex1];
-	b2Vec2 v2 = vertices[vertIndex2];
-
-	// If the center is inside the polygon ...
-	if (separation < b2_epsilon)
-	{
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_faceA;
-		manifold->localNormal = normals[normalIndex];
-		manifold->localPoint = 0.5f * (v1 + v2);
-		manifold->points[0].localPoint = circleB->m_p;
-		manifold->points[0].id.key = 0;
-		return;
-	}
-
-	// Compute barycentric coordinates
-	float32 u1 = b2Dot(cLocal - v1, v2 - v1);
-	float32 u2 = b2Dot(cLocal - v2, v1 - v2);
-	if (u1 <= 0.0f)
-	{
-		if (b2DistanceSquared(cLocal, v1) > radius * radius)
-		{
-			return;
-		}
-
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_faceA;
-		manifold->localNormal = cLocal - v1;
-		manifold->localNormal.Normalize();
-		manifold->localPoint = v1;
-		manifold->points[0].localPoint = circleB->m_p;
-		manifold->points[0].id.key = 0;
-	}
-	else if (u2 <= 0.0f)
-	{
-		if (b2DistanceSquared(cLocal, v2) > radius * radius)
-		{
-			return;
-		}
-
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_faceA;
-		manifold->localNormal = cLocal - v2;
-		manifold->localNormal.Normalize();
-		manifold->localPoint = v2;
-		manifold->points[0].localPoint = circleB->m_p;
-		manifold->points[0].id.key = 0;
-	}
-	else
-	{
-		b2Vec2 faceCenter = 0.5f * (v1 + v2);
-		float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
-		if (separation > radius)
-		{
-			return;
-		}
-
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_faceA;
-		manifold->localNormal = normals[vertIndex1];
-		manifold->localPoint = faceCenter;
-		manifold->points[0].localPoint = circleB->m_p;
-		manifold->points[0].id.key = 0;
-	}
-}
+/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+void b2CollideCircles(
+	b2Manifold* manifold,
+	const b2CircleShape* circleA, const b2Transform& xfA,
+	const b2CircleShape* circleB, const b2Transform& xfB)
+{
+	manifold->pointCount = 0;
+
+	b2Vec2 pA = b2Mul(xfA, circleA->m_p);
+	b2Vec2 pB = b2Mul(xfB, circleB->m_p);
+
+	b2Vec2 d = pB - pA;
+	float32 distSqr = b2Dot(d, d);
+	float32 rA = circleA->m_radius, rB = circleB->m_radius;
+	float32 radius = rA + rB;
+	if (distSqr > radius * radius)
+	{
+		return;
+	}
+
+	manifold->type = b2Manifold::e_circles;
+	manifold->localPoint = circleA->m_p;
+	manifold->localNormal.SetZero();
+	manifold->pointCount = 1;
+
+	manifold->points[0].localPoint = circleB->m_p;
+	manifold->points[0].id.key = 0;
+}
+
+void b2CollidePolygonAndCircle(
+	b2Manifold* manifold,
+	const b2PolygonShape* polygonA, const b2Transform& xfA,
+	const b2CircleShape* circleB, const b2Transform& xfB)
+{
+	manifold->pointCount = 0;
+
+	// Compute circle position in the frame of the polygon.
+	b2Vec2 c = b2Mul(xfB, circleB->m_p);
+	b2Vec2 cLocal = b2MulT(xfA, c);
+
+	// Find the min separating edge.
+	int32 normalIndex = 0;
+	float32 separation = -b2_maxFloat;
+	float32 radius = polygonA->m_radius + circleB->m_radius;
+	int32 vertexCount = polygonA->m_count;
+	const b2Vec2* vertices = polygonA->m_vertices;
+	const b2Vec2* normals = polygonA->m_normals;
+
+	for (int32 i = 0; i < vertexCount; ++i)
+	{
+		float32 s = b2Dot(normals[i], cLocal - vertices[i]);
+
+		if (s > radius)
+		{
+			// Early out.
+			return;
+		}
+
+		if (s > separation)
+		{
+			separation = s;
+			normalIndex = i;
+		}
+	}
+
+	// Vertices that subtend the incident face.
+	int32 vertIndex1 = normalIndex;
+	int32 vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
+	b2Vec2 v1 = vertices[vertIndex1];
+	b2Vec2 v2 = vertices[vertIndex2];
+
+	// If the center is inside the polygon ...
+	if (separation < b2_epsilon)
+	{
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_faceA;
+		manifold->localNormal = normals[normalIndex];
+		manifold->localPoint = 0.5f * (v1 + v2);
+		manifold->points[0].localPoint = circleB->m_p;
+		manifold->points[0].id.key = 0;
+		return;
+	}
+
+	// Compute barycentric coordinates
+	float32 u1 = b2Dot(cLocal - v1, v2 - v1);
+	float32 u2 = b2Dot(cLocal - v2, v1 - v2);
+	if (u1 <= 0.0f)
+	{
+		if (b2DistanceSquared(cLocal, v1) > radius * radius)
+		{
+			return;
+		}
+
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_faceA;
+		manifold->localNormal = cLocal - v1;
+		manifold->localNormal.Normalize();
+		manifold->localPoint = v1;
+		manifold->points[0].localPoint = circleB->m_p;
+		manifold->points[0].id.key = 0;
+	}
+	else if (u2 <= 0.0f)
+	{
+		if (b2DistanceSquared(cLocal, v2) > radius * radius)
+		{
+			return;
+		}
+
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_faceA;
+		manifold->localNormal = cLocal - v2;
+		manifold->localNormal.Normalize();
+		manifold->localPoint = v2;
+		manifold->points[0].localPoint = circleB->m_p;
+		manifold->points[0].id.key = 0;
+	}
+	else
+	{
+		b2Vec2 faceCenter = 0.5f * (v1 + v2);
+		float32 separation = b2Dot(cLocal - faceCenter, normals[vertIndex1]);
+		if (separation > radius)
+		{
+			return;
+		}
+
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_faceA;
+		manifold->localNormal = normals[vertIndex1];
+		manifold->localPoint = faceCenter;
+		manifold->points[0].localPoint = circleB->m_p;
+		manifold->points[0].id.key = 0;
+	}
+}

+ 698 - 698
engine/source/Box2D/Collision/b2CollideEdge.cpp

@@ -1,698 +1,698 @@
-/*
- * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- */
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <Box2D/Collision/Shapes/b2EdgeShape.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-
-// Compute contact points for edge versus circle.
-// This accounts for edge connectivity.
-void b2CollideEdgeAndCircle(b2Manifold* manifold,
-							const b2EdgeShape* edgeA, const b2Transform& xfA,
-							const b2CircleShape* circleB, const b2Transform& xfB)
-{
-	manifold->pointCount = 0;
-	
-	// Compute circle in frame of edge
-	b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
-	
-	b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
-	b2Vec2 e = B - A;
-	
-	// Barycentric coordinates
-	float32 u = b2Dot(e, B - Q);
-	float32 v = b2Dot(e, Q - A);
-	
-	float32 radius = edgeA->m_radius + circleB->m_radius;
-	
-	b2ContactFeature cf;
-	cf.indexB = 0;
-	cf.typeB = b2ContactFeature::e_vertex;
-	
-	// Region A
-	if (v <= 0.0f)
-	{
-		b2Vec2 P = A;
-		b2Vec2 d = Q - P;
-		float32 dd = b2Dot(d, d);
-		if (dd > radius * radius)
-		{
-			return;
-		}
-		
-		// Is there an edge connected to A?
-		if (edgeA->m_hasVertex0)
-		{
-			b2Vec2 A1 = edgeA->m_vertex0;
-			b2Vec2 B1 = A;
-			b2Vec2 e1 = B1 - A1;
-			float32 u1 = b2Dot(e1, B1 - Q);
-			
-			// Is the circle in Region AB of the previous edge?
-			if (u1 > 0.0f)
-			{
-				return;
-			}
-		}
-		
-		cf.indexA = 0;
-		cf.typeA = b2ContactFeature::e_vertex;
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_circles;
-		manifold->localNormal.SetZero();
-		manifold->localPoint = P;
-		manifold->points[0].id.key = 0;
-		manifold->points[0].id.cf = cf;
-		manifold->points[0].localPoint = circleB->m_p;
-		return;
-	}
-	
-	// Region B
-	if (u <= 0.0f)
-	{
-		b2Vec2 P = B;
-		b2Vec2 d = Q - P;
-		float32 dd = b2Dot(d, d);
-		if (dd > radius * radius)
-		{
-			return;
-		}
-		
-		// Is there an edge connected to B?
-		if (edgeA->m_hasVertex3)
-		{
-			b2Vec2 B2 = edgeA->m_vertex3;
-			b2Vec2 A2 = B;
-			b2Vec2 e2 = B2 - A2;
-			float32 v2 = b2Dot(e2, Q - A2);
-			
-			// Is the circle in Region AB of the next edge?
-			if (v2 > 0.0f)
-			{
-				return;
-			}
-		}
-		
-		cf.indexA = 1;
-		cf.typeA = b2ContactFeature::e_vertex;
-		manifold->pointCount = 1;
-		manifold->type = b2Manifold::e_circles;
-		manifold->localNormal.SetZero();
-		manifold->localPoint = P;
-		manifold->points[0].id.key = 0;
-		manifold->points[0].id.cf = cf;
-		manifold->points[0].localPoint = circleB->m_p;
-		return;
-	}
-	
-	// Region AB
-	float32 den = b2Dot(e, e);
-	b2Assert(den > 0.0f);
-	b2Vec2 P = (1.0f / den) * (u * A + v * B);
-	b2Vec2 d = Q - P;
-	float32 dd = b2Dot(d, d);
-	if (dd > radius * radius)
-	{
-		return;
-	}
-	
-	b2Vec2 n(-e.y, e.x);
-	if (b2Dot(n, Q - A) < 0.0f)
-	{
-		n.Set(-n.x, -n.y);
-	}
-	n.Normalize();
-	
-	cf.indexA = 0;
-	cf.typeA = b2ContactFeature::e_face;
-	manifold->pointCount = 1;
-	manifold->type = b2Manifold::e_faceA;
-	manifold->localNormal = n;
-	manifold->localPoint = A;
-	manifold->points[0].id.key = 0;
-	manifold->points[0].id.cf = cf;
-	manifold->points[0].localPoint = circleB->m_p;
-}
-
-// This structure is used to keep track of the best separating axis.
-struct b2EPAxis
-{
-	enum Type
-	{
-		e_unknown,
-		e_edgeA,
-		e_edgeB
-	};
-	
-	Type type;
-	int32 index;
-	float32 separation;
-};
-
-// This holds polygon B expressed in frame A.
-struct b2TempPolygon
-{
-	b2Vec2 vertices[b2_maxPolygonVertices];
-	b2Vec2 normals[b2_maxPolygonVertices];
-	int32 count;
-};
-
-// Reference face used for clipping
-struct b2ReferenceFace
-{
-	int32 i1, i2;
-	
-	b2Vec2 v1, v2;
-	
-	b2Vec2 normal;
-	
-	b2Vec2 sideNormal1;
-	float32 sideOffset1;
-	
-	b2Vec2 sideNormal2;
-	float32 sideOffset2;
-};
-
-// This class collides and edge and a polygon, taking into account edge adjacency.
-struct b2EPCollider
-{
-	void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
-				 const b2PolygonShape* polygonB, const b2Transform& xfB);
-	b2EPAxis ComputeEdgeSeparation();
-	b2EPAxis ComputePolygonSeparation();
-	
-	enum VertexType
-	{
-		e_isolated,
-		e_concave,
-		e_convex
-	};
-	
-	b2TempPolygon m_polygonB;
-	
-	b2Transform m_xf;
-	b2Vec2 m_centroidB;
-	b2Vec2 m_v0, m_v1, m_v2, m_v3;
-	b2Vec2 m_normal0, m_normal1, m_normal2;
-	b2Vec2 m_normal;
-	VertexType m_type1, m_type2;
-	b2Vec2 m_lowerLimit, m_upperLimit;
-	float32 m_radius;
-	bool m_front;
-};
-
-// Algorithm:
-// 1. Classify v1 and v2
-// 2. Classify polygon centroid as front or back
-// 3. Flip normal if necessary
-// 4. Initialize normal range to [-pi, pi] about face normal
-// 5. Adjust normal range according to adjacent edges
-// 6. Visit each separating axes, only accept axes within the range
-// 7. Return if _any_ axis indicates separation
-// 8. Clip
-void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
-						   const b2PolygonShape* polygonB, const b2Transform& xfB)
-{
-	m_xf = b2MulT(xfA, xfB);
-	
-	m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
-	
-	m_v0 = edgeA->m_vertex0;
-	m_v1 = edgeA->m_vertex1;
-	m_v2 = edgeA->m_vertex2;
-	m_v3 = edgeA->m_vertex3;
-	
-	bool hasVertex0 = edgeA->m_hasVertex0;
-	bool hasVertex3 = edgeA->m_hasVertex3;
-	
-	b2Vec2 edge1 = m_v2 - m_v1;
-	edge1.Normalize();
-	m_normal1.Set(edge1.y, -edge1.x);
-	float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
-	float32 offset0 = 0.0f, offset2 = 0.0f;
-	bool convex1 = false, convex2 = false;
-	
-	// Is there a preceding edge?
-	if (hasVertex0)
-	{
-		b2Vec2 edge0 = m_v1 - m_v0;
-		edge0.Normalize();
-		m_normal0.Set(edge0.y, -edge0.x);
-		convex1 = b2Cross(edge0, edge1) >= 0.0f;
-		offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
-	}
-	
-	// Is there a following edge?
-	if (hasVertex3)
-	{
-		b2Vec2 edge2 = m_v3 - m_v2;
-		edge2.Normalize();
-		m_normal2.Set(edge2.y, -edge2.x);
-		convex2 = b2Cross(edge1, edge2) > 0.0f;
-		offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
-	}
-	
-	// Determine front or back collision. Determine collision normal limits.
-	if (hasVertex0 && hasVertex3)
-	{
-		if (convex1 && convex2)
-		{
-			m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal0;
-				m_upperLimit = m_normal2;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal1;
-				m_upperLimit = -m_normal1;
-			}
-		}
-		else if (convex1)
-		{
-			m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal0;
-				m_upperLimit = m_normal1;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal2;
-				m_upperLimit = -m_normal1;
-			}
-		}
-		else if (convex2)
-		{
-			m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal1;
-				m_upperLimit = m_normal2;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal1;
-				m_upperLimit = -m_normal0;
-			}
-		}
-		else
-		{
-			m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal1;
-				m_upperLimit = m_normal1;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal2;
-				m_upperLimit = -m_normal0;
-			}
-		}
-	}
-	else if (hasVertex0)
-	{
-		if (convex1)
-		{
-			m_front = offset0 >= 0.0f || offset1 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal0;
-				m_upperLimit = -m_normal1;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = m_normal1;
-				m_upperLimit = -m_normal1;
-			}
-		}
-		else
-		{
-			m_front = offset0 >= 0.0f && offset1 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = m_normal1;
-				m_upperLimit = -m_normal1;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = m_normal1;
-				m_upperLimit = -m_normal0;
-			}
-		}
-	}
-	else if (hasVertex3)
-	{
-		if (convex2)
-		{
-			m_front = offset1 >= 0.0f || offset2 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = -m_normal1;
-				m_upperLimit = m_normal2;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal1;
-				m_upperLimit = m_normal1;
-			}
-		}
-		else
-		{
-			m_front = offset1 >= 0.0f && offset2 >= 0.0f;
-			if (m_front)
-			{
-				m_normal = m_normal1;
-				m_lowerLimit = -m_normal1;
-				m_upperLimit = m_normal1;
-			}
-			else
-			{
-				m_normal = -m_normal1;
-				m_lowerLimit = -m_normal2;
-				m_upperLimit = m_normal1;
-			}
-		}		
-	}
-	else
-	{
-		m_front = offset1 >= 0.0f;
-		if (m_front)
-		{
-			m_normal = m_normal1;
-			m_lowerLimit = -m_normal1;
-			m_upperLimit = -m_normal1;
-		}
-		else
-		{
-			m_normal = -m_normal1;
-			m_lowerLimit = m_normal1;
-			m_upperLimit = m_normal1;
-		}
-	}
-	
-	// Get polygonB in frameA
-	m_polygonB.count = polygonB->m_count;
-	for (int32 i = 0; i < polygonB->m_count; ++i)
-	{
-		m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
-		m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
-	}
-	
-	m_radius = 2.0f * b2_polygonRadius;
-	
-	manifold->pointCount = 0;
-	
-	b2EPAxis edgeAxis = ComputeEdgeSeparation();
-	
-	// If no valid normal can be found than this edge should not collide.
-	if (edgeAxis.type == b2EPAxis::e_unknown)
-	{
-		return;
-	}
-	
-	if (edgeAxis.separation > m_radius)
-	{
-		return;
-	}
-	
-	b2EPAxis polygonAxis = ComputePolygonSeparation();
-	if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
-	{
-		return;
-	}
-	
-	// Use hysteresis for jitter reduction.
-	const float32 k_relativeTol = 0.98f;
-	const float32 k_absoluteTol = 0.001f;
-	
-	b2EPAxis primaryAxis;
-	if (polygonAxis.type == b2EPAxis::e_unknown)
-	{
-		primaryAxis = edgeAxis;
-	}
-	else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
-	{
-		primaryAxis = polygonAxis;
-	}
-	else
-	{
-		primaryAxis = edgeAxis;
-	}
-	
-	b2ClipVertex ie[2];
-	b2ReferenceFace rf;
-	if (primaryAxis.type == b2EPAxis::e_edgeA)
-	{
-		manifold->type = b2Manifold::e_faceA;
-		
-		// Search for the polygon normal that is most anti-parallel to the edge normal.
-		int32 bestIndex = 0;
-		float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
-		for (int32 i = 1; i < m_polygonB.count; ++i)
-		{
-			float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
-			if (value < bestValue)
-			{
-				bestValue = value;
-				bestIndex = i;
-			}
-		}
-		
-		int32 i1 = bestIndex;
-		int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
-		
-		ie[0].v = m_polygonB.vertices[i1];
-		ie[0].id.cf.indexA = 0;
-		ie[0].id.cf.indexB = i1;
-		ie[0].id.cf.typeA = b2ContactFeature::e_face;
-		ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
-		
-		ie[1].v = m_polygonB.vertices[i2];
-		ie[1].id.cf.indexA = 0;
-		ie[1].id.cf.indexB = i2;
-		ie[1].id.cf.typeA = b2ContactFeature::e_face;
-		ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
-		
-		if (m_front)
-		{
-			rf.i1 = 0;
-			rf.i2 = 1;
-			rf.v1 = m_v1;
-			rf.v2 = m_v2;
-			rf.normal = m_normal1;
-		}
-		else
-		{
-			rf.i1 = 1;
-			rf.i2 = 0;
-			rf.v1 = m_v2;
-			rf.v2 = m_v1;
-			rf.normal = -m_normal1;
-		}		
-	}
-	else
-	{
-		manifold->type = b2Manifold::e_faceB;
-		
-		ie[0].v = m_v1;
-		ie[0].id.cf.indexA = 0;
-		ie[0].id.cf.indexB = primaryAxis.index;
-		ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
-		ie[0].id.cf.typeB = b2ContactFeature::e_face;
-		
-		ie[1].v = m_v2;
-		ie[1].id.cf.indexA = 0;
-		ie[1].id.cf.indexB = primaryAxis.index;		
-		ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
-		ie[1].id.cf.typeB = b2ContactFeature::e_face;
-		
-		rf.i1 = primaryAxis.index;
-		rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
-		rf.v1 = m_polygonB.vertices[rf.i1];
-		rf.v2 = m_polygonB.vertices[rf.i2];
-		rf.normal = m_polygonB.normals[rf.i1];
-	}
-	
-	rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
-	rf.sideNormal2 = -rf.sideNormal1;
-	rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
-	rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
-	
-	// Clip incident edge against extruded edge1 side edges.
-	b2ClipVertex clipPoints1[2];
-	b2ClipVertex clipPoints2[2];
-	int32 np;
-	
-	// Clip to box side 1
-	np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
-	
-	if (np < b2_maxManifoldPoints)
-	{
-		return;
-	}
-	
-	// Clip to negative box side 1
-	np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
-	
-	if (np < b2_maxManifoldPoints)
-	{
-		return;
-	}
-	
-	// Now clipPoints2 contains the clipped points.
-	if (primaryAxis.type == b2EPAxis::e_edgeA)
-	{
-		manifold->localNormal = rf.normal;
-		manifold->localPoint = rf.v1;
-	}
-	else
-	{
-		manifold->localNormal = polygonB->m_normals[rf.i1];
-		manifold->localPoint = polygonB->m_vertices[rf.i1];
-	}
-	
-	int32 pointCount = 0;
-	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
-	{
-		float32 separation;
-		
-		separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
-		
-		if (separation <= m_radius)
-		{
-			b2ManifoldPoint* cp = manifold->points + pointCount;
-			
-			if (primaryAxis.type == b2EPAxis::e_edgeA)
-			{
-				cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
-				cp->id = clipPoints2[i].id;
-			}
-			else
-			{
-				cp->localPoint = clipPoints2[i].v;
-				cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
-				cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
-				cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
-				cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
-			}
-			
-			++pointCount;
-		}
-	}
-	
-	manifold->pointCount = pointCount;
-}
-
-b2EPAxis b2EPCollider::ComputeEdgeSeparation()
-{
-	b2EPAxis axis;
-	axis.type = b2EPAxis::e_edgeA;
-	axis.index = m_front ? 0 : 1;
-	axis.separation = FLT_MAX;
-	
-	for (int32 i = 0; i < m_polygonB.count; ++i)
-	{
-		float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
-		if (s < axis.separation)
-		{
-			axis.separation = s;
-		}
-	}
-	
-	return axis;
-}
-
-b2EPAxis b2EPCollider::ComputePolygonSeparation()
-{
-	b2EPAxis axis;
-	axis.type = b2EPAxis::e_unknown;
-	axis.index = -1;
-	axis.separation = -FLT_MAX;
-
-	b2Vec2 perp(-m_normal.y, m_normal.x);
-
-	for (int32 i = 0; i < m_polygonB.count; ++i)
-	{
-		b2Vec2 n = -m_polygonB.normals[i];
-		
-		float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
-		float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
-		float32 s = b2Min(s1, s2);
-		
-		if (s > m_radius)
-		{
-			// No collision
-			axis.type = b2EPAxis::e_edgeB;
-			axis.index = i;
-			axis.separation = s;
-			return axis;
-		}
-		
-		// Adjacency
-		if (b2Dot(n, perp) >= 0.0f)
-		{
-			if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
-			{
-				continue;
-			}
-		}
-		else
-		{
-			if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
-			{
-				continue;
-			}
-		}
-		
-		if (s > axis.separation)
-		{
-			axis.type = b2EPAxis::e_edgeB;
-			axis.index = i;
-			axis.separation = s;
-		}
-	}
-	
-	return axis;
-}
-
-void b2CollideEdgeAndPolygon(	b2Manifold* manifold,
-							 const b2EdgeShape* edgeA, const b2Transform& xfA,
-							 const b2PolygonShape* polygonB, const b2Transform& xfB)
-{
-	b2EPCollider collider;
-	collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
-}
+/*
+ * Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+
+// Compute contact points for edge versus circle.
+// This accounts for edge connectivity.
+void b2CollideEdgeAndCircle(b2Manifold* manifold,
+							const b2EdgeShape* edgeA, const b2Transform& xfA,
+							const b2CircleShape* circleB, const b2Transform& xfB)
+{
+	manifold->pointCount = 0;
+	
+	// Compute circle in frame of edge
+	b2Vec2 Q = b2MulT(xfA, b2Mul(xfB, circleB->m_p));
+	
+	b2Vec2 A = edgeA->m_vertex1, B = edgeA->m_vertex2;
+	b2Vec2 e = B - A;
+	
+	// Barycentric coordinates
+	float32 u = b2Dot(e, B - Q);
+	float32 v = b2Dot(e, Q - A);
+	
+	float32 radius = edgeA->m_radius + circleB->m_radius;
+	
+	b2ContactFeature cf;
+	cf.indexB = 0;
+	cf.typeB = b2ContactFeature::e_vertex;
+	
+	// Region A
+	if (v <= 0.0f)
+	{
+		b2Vec2 P = A;
+		b2Vec2 d = Q - P;
+		float32 dd = b2Dot(d, d);
+		if (dd > radius * radius)
+		{
+			return;
+		}
+		
+		// Is there an edge connected to A?
+		if (edgeA->m_hasVertex0)
+		{
+			b2Vec2 A1 = edgeA->m_vertex0;
+			b2Vec2 B1 = A;
+			b2Vec2 e1 = B1 - A1;
+			float32 u1 = b2Dot(e1, B1 - Q);
+			
+			// Is the circle in Region AB of the previous edge?
+			if (u1 > 0.0f)
+			{
+				return;
+			}
+		}
+		
+		cf.indexA = 0;
+		cf.typeA = b2ContactFeature::e_vertex;
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_circles;
+		manifold->localNormal.SetZero();
+		manifold->localPoint = P;
+		manifold->points[0].id.key = 0;
+		manifold->points[0].id.cf = cf;
+		manifold->points[0].localPoint = circleB->m_p;
+		return;
+	}
+	
+	// Region B
+	if (u <= 0.0f)
+	{
+		b2Vec2 P = B;
+		b2Vec2 d = Q - P;
+		float32 dd = b2Dot(d, d);
+		if (dd > radius * radius)
+		{
+			return;
+		}
+		
+		// Is there an edge connected to B?
+		if (edgeA->m_hasVertex3)
+		{
+			b2Vec2 B2 = edgeA->m_vertex3;
+			b2Vec2 A2 = B;
+			b2Vec2 e2 = B2 - A2;
+			float32 v2 = b2Dot(e2, Q - A2);
+			
+			// Is the circle in Region AB of the next edge?
+			if (v2 > 0.0f)
+			{
+				return;
+			}
+		}
+		
+		cf.indexA = 1;
+		cf.typeA = b2ContactFeature::e_vertex;
+		manifold->pointCount = 1;
+		manifold->type = b2Manifold::e_circles;
+		manifold->localNormal.SetZero();
+		manifold->localPoint = P;
+		manifold->points[0].id.key = 0;
+		manifold->points[0].id.cf = cf;
+		manifold->points[0].localPoint = circleB->m_p;
+		return;
+	}
+	
+	// Region AB
+	float32 den = b2Dot(e, e);
+	b2Assert(den > 0.0f);
+	b2Vec2 P = (1.0f / den) * (u * A + v * B);
+	b2Vec2 d = Q - P;
+	float32 dd = b2Dot(d, d);
+	if (dd > radius * radius)
+	{
+		return;
+	}
+	
+	b2Vec2 n(-e.y, e.x);
+	if (b2Dot(n, Q - A) < 0.0f)
+	{
+		n.Set(-n.x, -n.y);
+	}
+	n.Normalize();
+	
+	cf.indexA = 0;
+	cf.typeA = b2ContactFeature::e_face;
+	manifold->pointCount = 1;
+	manifold->type = b2Manifold::e_faceA;
+	manifold->localNormal = n;
+	manifold->localPoint = A;
+	manifold->points[0].id.key = 0;
+	manifold->points[0].id.cf = cf;
+	manifold->points[0].localPoint = circleB->m_p;
+}
+
+// This structure is used to keep track of the best separating axis.
+struct b2EPAxis
+{
+	enum Type
+	{
+		e_unknown,
+		e_edgeA,
+		e_edgeB
+	};
+	
+	Type type;
+	int32 index;
+	float32 separation;
+};
+
+// This holds polygon B expressed in frame A.
+struct b2TempPolygon
+{
+	b2Vec2 vertices[b2_maxPolygonVertices];
+	b2Vec2 normals[b2_maxPolygonVertices];
+	int32 count;
+};
+
+// Reference face used for clipping
+struct b2ReferenceFace
+{
+	int32 i1, i2;
+	
+	b2Vec2 v1, v2;
+	
+	b2Vec2 normal;
+	
+	b2Vec2 sideNormal1;
+	float32 sideOffset1;
+	
+	b2Vec2 sideNormal2;
+	float32 sideOffset2;
+};
+
+// This class collides and edge and a polygon, taking into account edge adjacency.
+struct b2EPCollider
+{
+	void Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
+				 const b2PolygonShape* polygonB, const b2Transform& xfB);
+	b2EPAxis ComputeEdgeSeparation();
+	b2EPAxis ComputePolygonSeparation();
+	
+	enum VertexType
+	{
+		e_isolated,
+		e_concave,
+		e_convex
+	};
+	
+	b2TempPolygon m_polygonB;
+	
+	b2Transform m_xf;
+	b2Vec2 m_centroidB;
+	b2Vec2 m_v0, m_v1, m_v2, m_v3;
+	b2Vec2 m_normal0, m_normal1, m_normal2;
+	b2Vec2 m_normal;
+	VertexType m_type1, m_type2;
+	b2Vec2 m_lowerLimit, m_upperLimit;
+	float32 m_radius;
+	bool m_front;
+};
+
+// Algorithm:
+// 1. Classify v1 and v2
+// 2. Classify polygon centroid as front or back
+// 3. Flip normal if necessary
+// 4. Initialize normal range to [-pi, pi] about face normal
+// 5. Adjust normal range according to adjacent edges
+// 6. Visit each separating axes, only accept axes within the range
+// 7. Return if _any_ axis indicates separation
+// 8. Clip
+void b2EPCollider::Collide(b2Manifold* manifold, const b2EdgeShape* edgeA, const b2Transform& xfA,
+						   const b2PolygonShape* polygonB, const b2Transform& xfB)
+{
+	m_xf = b2MulT(xfA, xfB);
+	
+	m_centroidB = b2Mul(m_xf, polygonB->m_centroid);
+	
+	m_v0 = edgeA->m_vertex0;
+	m_v1 = edgeA->m_vertex1;
+	m_v2 = edgeA->m_vertex2;
+	m_v3 = edgeA->m_vertex3;
+	
+	bool hasVertex0 = edgeA->m_hasVertex0;
+	bool hasVertex3 = edgeA->m_hasVertex3;
+	
+	b2Vec2 edge1 = m_v2 - m_v1;
+	edge1.Normalize();
+	m_normal1.Set(edge1.y, -edge1.x);
+	float32 offset1 = b2Dot(m_normal1, m_centroidB - m_v1);
+	float32 offset0 = 0.0f, offset2 = 0.0f;
+	bool convex1 = false, convex2 = false;
+	
+	// Is there a preceding edge?
+	if (hasVertex0)
+	{
+		b2Vec2 edge0 = m_v1 - m_v0;
+		edge0.Normalize();
+		m_normal0.Set(edge0.y, -edge0.x);
+		convex1 = b2Cross(edge0, edge1) >= 0.0f;
+		offset0 = b2Dot(m_normal0, m_centroidB - m_v0);
+	}
+	
+	// Is there a following edge?
+	if (hasVertex3)
+	{
+		b2Vec2 edge2 = m_v3 - m_v2;
+		edge2.Normalize();
+		m_normal2.Set(edge2.y, -edge2.x);
+		convex2 = b2Cross(edge1, edge2) > 0.0f;
+		offset2 = b2Dot(m_normal2, m_centroidB - m_v2);
+	}
+	
+	// Determine front or back collision. Determine collision normal limits.
+	if (hasVertex0 && hasVertex3)
+	{
+		if (convex1 && convex2)
+		{
+			m_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal0;
+				m_upperLimit = m_normal2;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal1;
+				m_upperLimit = -m_normal1;
+			}
+		}
+		else if (convex1)
+		{
+			m_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal0;
+				m_upperLimit = m_normal1;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal2;
+				m_upperLimit = -m_normal1;
+			}
+		}
+		else if (convex2)
+		{
+			m_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal1;
+				m_upperLimit = m_normal2;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal1;
+				m_upperLimit = -m_normal0;
+			}
+		}
+		else
+		{
+			m_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal1;
+				m_upperLimit = m_normal1;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal2;
+				m_upperLimit = -m_normal0;
+			}
+		}
+	}
+	else if (hasVertex0)
+	{
+		if (convex1)
+		{
+			m_front = offset0 >= 0.0f || offset1 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal0;
+				m_upperLimit = -m_normal1;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = m_normal1;
+				m_upperLimit = -m_normal1;
+			}
+		}
+		else
+		{
+			m_front = offset0 >= 0.0f && offset1 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = m_normal1;
+				m_upperLimit = -m_normal1;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = m_normal1;
+				m_upperLimit = -m_normal0;
+			}
+		}
+	}
+	else if (hasVertex3)
+	{
+		if (convex2)
+		{
+			m_front = offset1 >= 0.0f || offset2 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = -m_normal1;
+				m_upperLimit = m_normal2;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal1;
+				m_upperLimit = m_normal1;
+			}
+		}
+		else
+		{
+			m_front = offset1 >= 0.0f && offset2 >= 0.0f;
+			if (m_front)
+			{
+				m_normal = m_normal1;
+				m_lowerLimit = -m_normal1;
+				m_upperLimit = m_normal1;
+			}
+			else
+			{
+				m_normal = -m_normal1;
+				m_lowerLimit = -m_normal2;
+				m_upperLimit = m_normal1;
+			}
+		}		
+	}
+	else
+	{
+		m_front = offset1 >= 0.0f;
+		if (m_front)
+		{
+			m_normal = m_normal1;
+			m_lowerLimit = -m_normal1;
+			m_upperLimit = -m_normal1;
+		}
+		else
+		{
+			m_normal = -m_normal1;
+			m_lowerLimit = m_normal1;
+			m_upperLimit = m_normal1;
+		}
+	}
+	
+	// Get polygonB in frameA
+	m_polygonB.count = polygonB->m_count;
+	for (int32 i = 0; i < polygonB->m_count; ++i)
+	{
+		m_polygonB.vertices[i] = b2Mul(m_xf, polygonB->m_vertices[i]);
+		m_polygonB.normals[i] = b2Mul(m_xf.q, polygonB->m_normals[i]);
+	}
+	
+	m_radius = 2.0f * b2_polygonRadius;
+	
+	manifold->pointCount = 0;
+	
+	b2EPAxis edgeAxis = ComputeEdgeSeparation();
+	
+	// If no valid normal can be found than this edge should not collide.
+	if (edgeAxis.type == b2EPAxis::e_unknown)
+	{
+		return;
+	}
+	
+	if (edgeAxis.separation > m_radius)
+	{
+		return;
+	}
+	
+	b2EPAxis polygonAxis = ComputePolygonSeparation();
+	if (polygonAxis.type != b2EPAxis::e_unknown && polygonAxis.separation > m_radius)
+	{
+		return;
+	}
+	
+	// Use hysteresis for jitter reduction.
+	const float32 k_relativeTol = 0.98f;
+	const float32 k_absoluteTol = 0.001f;
+	
+	b2EPAxis primaryAxis;
+	if (polygonAxis.type == b2EPAxis::e_unknown)
+	{
+		primaryAxis = edgeAxis;
+	}
+	else if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol)
+	{
+		primaryAxis = polygonAxis;
+	}
+	else
+	{
+		primaryAxis = edgeAxis;
+	}
+	
+	b2ClipVertex ie[2];
+	b2ReferenceFace rf;
+	if (primaryAxis.type == b2EPAxis::e_edgeA)
+	{
+		manifold->type = b2Manifold::e_faceA;
+		
+		// Search for the polygon normal that is most anti-parallel to the edge normal.
+		int32 bestIndex = 0;
+		float32 bestValue = b2Dot(m_normal, m_polygonB.normals[0]);
+		for (int32 i = 1; i < m_polygonB.count; ++i)
+		{
+			float32 value = b2Dot(m_normal, m_polygonB.normals[i]);
+			if (value < bestValue)
+			{
+				bestValue = value;
+				bestIndex = i;
+			}
+		}
+		
+		int32 i1 = bestIndex;
+		int32 i2 = i1 + 1 < m_polygonB.count ? i1 + 1 : 0;
+		
+		ie[0].v = m_polygonB.vertices[i1];
+		ie[0].id.cf.indexA = 0;
+		ie[0].id.cf.indexB = static_cast<uint8>(i1);
+		ie[0].id.cf.typeA = b2ContactFeature::e_face;
+		ie[0].id.cf.typeB = b2ContactFeature::e_vertex;
+		
+		ie[1].v = m_polygonB.vertices[i2];
+		ie[1].id.cf.indexA = 0;
+		ie[1].id.cf.indexB = static_cast<uint8>(i2);
+		ie[1].id.cf.typeA = b2ContactFeature::e_face;
+		ie[1].id.cf.typeB = b2ContactFeature::e_vertex;
+		
+		if (m_front)
+		{
+			rf.i1 = 0;
+			rf.i2 = 1;
+			rf.v1 = m_v1;
+			rf.v2 = m_v2;
+			rf.normal = m_normal1;
+		}
+		else
+		{
+			rf.i1 = 1;
+			rf.i2 = 0;
+			rf.v1 = m_v2;
+			rf.v2 = m_v1;
+			rf.normal = -m_normal1;
+		}		
+	}
+	else
+	{
+		manifold->type = b2Manifold::e_faceB;
+		
+		ie[0].v = m_v1;
+		ie[0].id.cf.indexA = 0;
+		ie[0].id.cf.indexB = static_cast<uint8>(primaryAxis.index);
+		ie[0].id.cf.typeA = b2ContactFeature::e_vertex;
+		ie[0].id.cf.typeB = b2ContactFeature::e_face;
+		
+		ie[1].v = m_v2;
+		ie[1].id.cf.indexA = 0;
+		ie[1].id.cf.indexB = static_cast<uint8>(primaryAxis.index);		
+		ie[1].id.cf.typeA = b2ContactFeature::e_vertex;
+		ie[1].id.cf.typeB = b2ContactFeature::e_face;
+		
+		rf.i1 = primaryAxis.index;
+		rf.i2 = rf.i1 + 1 < m_polygonB.count ? rf.i1 + 1 : 0;
+		rf.v1 = m_polygonB.vertices[rf.i1];
+		rf.v2 = m_polygonB.vertices[rf.i2];
+		rf.normal = m_polygonB.normals[rf.i1];
+	}
+	
+	rf.sideNormal1.Set(rf.normal.y, -rf.normal.x);
+	rf.sideNormal2 = -rf.sideNormal1;
+	rf.sideOffset1 = b2Dot(rf.sideNormal1, rf.v1);
+	rf.sideOffset2 = b2Dot(rf.sideNormal2, rf.v2);
+	
+	// Clip incident edge against extruded edge1 side edges.
+	b2ClipVertex clipPoints1[2];
+	b2ClipVertex clipPoints2[2];
+	int32 np;
+	
+	// Clip to box side 1
+	np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1, rf.sideOffset1, rf.i1);
+	
+	if (np < b2_maxManifoldPoints)
+	{
+		return;
+	}
+	
+	// Clip to negative box side 1
+	np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2, rf.sideOffset2, rf.i2);
+	
+	if (np < b2_maxManifoldPoints)
+	{
+		return;
+	}
+	
+	// Now clipPoints2 contains the clipped points.
+	if (primaryAxis.type == b2EPAxis::e_edgeA)
+	{
+		manifold->localNormal = rf.normal;
+		manifold->localPoint = rf.v1;
+	}
+	else
+	{
+		manifold->localNormal = polygonB->m_normals[rf.i1];
+		manifold->localPoint = polygonB->m_vertices[rf.i1];
+	}
+	
+	int32 pointCount = 0;
+	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+	{
+		float32 separation;
+		
+		separation = b2Dot(rf.normal, clipPoints2[i].v - rf.v1);
+		
+		if (separation <= m_radius)
+		{
+			b2ManifoldPoint* cp = manifold->points + pointCount;
+			
+			if (primaryAxis.type == b2EPAxis::e_edgeA)
+			{
+				cp->localPoint = b2MulT(m_xf, clipPoints2[i].v);
+				cp->id = clipPoints2[i].id;
+			}
+			else
+			{
+				cp->localPoint = clipPoints2[i].v;
+				cp->id.cf.typeA = clipPoints2[i].id.cf.typeB;
+				cp->id.cf.typeB = clipPoints2[i].id.cf.typeA;
+				cp->id.cf.indexA = clipPoints2[i].id.cf.indexB;
+				cp->id.cf.indexB = clipPoints2[i].id.cf.indexA;
+			}
+			
+			++pointCount;
+		}
+	}
+	
+	manifold->pointCount = pointCount;
+}
+
+b2EPAxis b2EPCollider::ComputeEdgeSeparation()
+{
+	b2EPAxis axis;
+	axis.type = b2EPAxis::e_edgeA;
+	axis.index = m_front ? 0 : 1;
+	axis.separation = FLT_MAX;
+	
+	for (int32 i = 0; i < m_polygonB.count; ++i)
+	{
+		float32 s = b2Dot(m_normal, m_polygonB.vertices[i] - m_v1);
+		if (s < axis.separation)
+		{
+			axis.separation = s;
+		}
+	}
+	
+	return axis;
+}
+
+b2EPAxis b2EPCollider::ComputePolygonSeparation()
+{
+	b2EPAxis axis;
+	axis.type = b2EPAxis::e_unknown;
+	axis.index = -1;
+	axis.separation = -FLT_MAX;
+
+	b2Vec2 perp(-m_normal.y, m_normal.x);
+
+	for (int32 i = 0; i < m_polygonB.count; ++i)
+	{
+		b2Vec2 n = -m_polygonB.normals[i];
+		
+		float32 s1 = b2Dot(n, m_polygonB.vertices[i] - m_v1);
+		float32 s2 = b2Dot(n, m_polygonB.vertices[i] - m_v2);
+		float32 s = b2Min(s1, s2);
+		
+		if (s > m_radius)
+		{
+			// No collision
+			axis.type = b2EPAxis::e_edgeB;
+			axis.index = i;
+			axis.separation = s;
+			return axis;
+		}
+		
+		// Adjacency
+		if (b2Dot(n, perp) >= 0.0f)
+		{
+			if (b2Dot(n - m_upperLimit, m_normal) < -b2_angularSlop)
+			{
+				continue;
+			}
+		}
+		else
+		{
+			if (b2Dot(n - m_lowerLimit, m_normal) < -b2_angularSlop)
+			{
+				continue;
+			}
+		}
+		
+		if (s > axis.separation)
+		{
+			axis.type = b2EPAxis::e_edgeB;
+			axis.index = i;
+			axis.separation = s;
+		}
+	}
+	
+	return axis;
+}
+
+void b2CollideEdgeAndPolygon(	b2Manifold* manifold,
+							 const b2EdgeShape* edgeA, const b2Transform& xfA,
+							 const b2PolygonShape* polygonB, const b2Transform& xfB)
+{
+	b2EPCollider collider;
+	collider.Collide(manifold, edgeA, xfA, polygonB, xfB);
+}

+ 239 - 317
engine/source/Box2D/Collision/b2CollidePolygon.cpp

@@ -1,317 +1,239 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-// Find the separation between poly1 and poly2 for a give edge normal on poly1.
-static float32 b2EdgeSeparation(const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
-							  const b2PolygonShape* poly2, const b2Transform& xf2)
-{
-	const b2Vec2* vertices1 = poly1->m_vertices;
-	const b2Vec2* normals1 = poly1->m_normals;
-
-	int32 count2 = poly2->m_count;
-	const b2Vec2* vertices2 = poly2->m_vertices;
-
-	b2Assert(0 <= edge1 && edge1 < poly1->m_count);
-
-	// Convert normal from poly1's frame into poly2's frame.
-	b2Vec2 normal1World = b2Mul(xf1.q, normals1[edge1]);
-	b2Vec2 normal1 = b2MulT(xf2.q, normal1World);
-
-	// Find support vertex on poly2 for -normal.
-	int32 index = 0;
-	float32 minDot = b2_maxFloat;
-
-	for (int32 i = 0; i < count2; ++i)
-	{
-		float32 dot = b2Dot(vertices2[i], normal1);
-		if (dot < minDot)
-		{
-			minDot = dot;
-			index = i;
-		}
-	}
-
-	b2Vec2 v1 = b2Mul(xf1, vertices1[edge1]);
-	b2Vec2 v2 = b2Mul(xf2, vertices2[index]);
-	float32 separation = b2Dot(v2 - v1, normal1World);
-	return separation;
-}
-
-// Find the max separation between poly1 and poly2 using edge normals from poly1.
-static float32 b2FindMaxSeparation(int32* edgeIndex,
-								 const b2PolygonShape* poly1, const b2Transform& xf1,
-								 const b2PolygonShape* poly2, const b2Transform& xf2)
-{
-	int32 count1 = poly1->m_count;
-	const b2Vec2* normals1 = poly1->m_normals;
-
-	// Vector pointing from the centroid of poly1 to the centroid of poly2.
-	b2Vec2 d = b2Mul(xf2, poly2->m_centroid) - b2Mul(xf1, poly1->m_centroid);
-	b2Vec2 dLocal1 = b2MulT(xf1.q, d);
-
-	// Find edge normal on poly1 that has the largest projection onto d.
-	int32 edge = 0;
-	float32 maxDot = -b2_maxFloat;
-	for (int32 i = 0; i < count1; ++i)
-	{
-		float32 dot = b2Dot(normals1[i], dLocal1);
-		if (dot > maxDot)
-		{
-			maxDot = dot;
-			edge = i;
-		}
-	}
-
-	// Get the separation for the edge normal.
-	float32 s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
-
-	// Check the separation for the previous edge normal.
-	int32 prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
-	float32 sPrev = b2EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
-
-	// Check the separation for the next edge normal.
-	int32 nextEdge = edge + 1 < count1 ? edge + 1 : 0;
-	float32 sNext = b2EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
-
-	// Find the best edge and the search direction.
-	int32 bestEdge;
-	float32 bestSeparation;
-	int32 increment;
-	if (sPrev > s && sPrev > sNext)
-	{
-		increment = -1;
-		bestEdge = prevEdge;
-		bestSeparation = sPrev;
-	}
-	else if (sNext > s)
-	{
-		increment = 1;
-		bestEdge = nextEdge;
-		bestSeparation = sNext;
-	}
-	else
-	{
-		*edgeIndex = edge;
-		return s;
-	}
-
-	// Perform a local search for the best edge normal.
-	for ( ; ; )
-	{
-		if (increment == -1)
-			edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
-		else
-			edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
-
-		s = b2EdgeSeparation(poly1, xf1, edge, poly2, xf2);
-
-		if (s > bestSeparation)
-		{
-			bestEdge = edge;
-			bestSeparation = s;
-		}
-		else
-		{
-			break;
-		}
-	}
-
-	*edgeIndex = bestEdge;
-	return bestSeparation;
-}
-
-static void b2FindIncidentEdge(b2ClipVertex c[2],
-							 const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
-							 const b2PolygonShape* poly2, const b2Transform& xf2)
-{
-	const b2Vec2* normals1 = poly1->m_normals;
-
-	int32 count2 = poly2->m_count;
-	const b2Vec2* vertices2 = poly2->m_vertices;
-	const b2Vec2* normals2 = poly2->m_normals;
-
-	b2Assert(0 <= edge1 && edge1 < poly1->m_count);
-
-	// Get the normal of the reference edge in poly2's frame.
-	b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
-
-	// Find the incident edge on poly2.
-	int32 index = 0;
-	float32 minDot = b2_maxFloat;
-	for (int32 i = 0; i < count2; ++i)
-	{
-		float32 dot = b2Dot(normal1, normals2[i]);
-		if (dot < minDot)
-		{
-			minDot = dot;
-			index = i;
-		}
-	}
-
-	// Build the clip vertices for the incident edge.
-	int32 i1 = index;
-	int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
-
-	c[0].v = b2Mul(xf2, vertices2[i1]);
-	c[0].id.cf.indexA = (uint8)edge1;
-	c[0].id.cf.indexB = (uint8)i1;
-	c[0].id.cf.typeA = b2ContactFeature::e_face;
-	c[0].id.cf.typeB = b2ContactFeature::e_vertex;
-
-	c[1].v = b2Mul(xf2, vertices2[i2]);
-	c[1].id.cf.indexA = (uint8)edge1;
-	c[1].id.cf.indexB = (uint8)i2;
-	c[1].id.cf.typeA = b2ContactFeature::e_face;
-	c[1].id.cf.typeB = b2ContactFeature::e_vertex;
-}
-
-// Find edge normal of max separation on A - return if separating axis is found
-// Find edge normal of max separation on B - return if separation axis is found
-// Choose reference edge as min(minA, minB)
-// Find incident edge
-// Clip
-
-// The normal points from 1 to 2
-void b2CollidePolygons(b2Manifold* manifold,
-					  const b2PolygonShape* polyA, const b2Transform& xfA,
-					  const b2PolygonShape* polyB, const b2Transform& xfB)
-{
-	manifold->pointCount = 0;
-	float32 totalRadius = polyA->m_radius + polyB->m_radius;
-
-	int32 edgeA = 0;
-	float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
-	if (separationA > totalRadius)
-		return;
-
-	int32 edgeB = 0;
-	float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
-	if (separationB > totalRadius)
-		return;
-
-	const b2PolygonShape* poly1;	// reference polygon
-	const b2PolygonShape* poly2;	// incident polygon
-	b2Transform xf1, xf2;
-	int32 edge1;		// reference edge
-	uint8 flip;
-	const float32 k_relativeTol = 0.98f;
-	const float32 k_absoluteTol = 0.001f;
-
-	if (separationB > k_relativeTol * separationA + k_absoluteTol)
-	{
-		poly1 = polyB;
-		poly2 = polyA;
-		xf1 = xfB;
-		xf2 = xfA;
-		edge1 = edgeB;
-		manifold->type = b2Manifold::e_faceB;
-		flip = 1;
-	}
-	else
-	{
-		poly1 = polyA;
-		poly2 = polyB;
-		xf1 = xfA;
-		xf2 = xfB;
-		edge1 = edgeA;
-		manifold->type = b2Manifold::e_faceA;
-		flip = 0;
-	}
-
-	b2ClipVertex incidentEdge[2];
-	b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
-
-	int32 count1 = poly1->m_count;
-	const b2Vec2* vertices1 = poly1->m_vertices;
-
-	int32 iv1 = edge1;
-	int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
-
-	b2Vec2 v11 = vertices1[iv1];
-	b2Vec2 v12 = vertices1[iv2];
-
-	b2Vec2 localTangent = v12 - v11;
-	localTangent.Normalize();
-	
-	b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
-	b2Vec2 planePoint = 0.5f * (v11 + v12);
-
-	b2Vec2 tangent = b2Mul(xf1.q, localTangent);
-	b2Vec2 normal = b2Cross(tangent, 1.0f);
-	
-	v11 = b2Mul(xf1, v11);
-	v12 = b2Mul(xf1, v12);
-
-	// Face offset.
-	float32 frontOffset = b2Dot(normal, v11);
-
-	// Side offsets, extended by polytope skin thickness.
-	float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
-	float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
-
-	// Clip incident edge against extruded edge1 side edges.
-	b2ClipVertex clipPoints1[2];
-	b2ClipVertex clipPoints2[2];
-	int np;
-
-	// Clip to box side 1
-	np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
-
-	if (np < 2)
-		return;
-
-	// Clip to negative box side 1
-	np = b2ClipSegmentToLine(clipPoints2, clipPoints1,  tangent, sideOffset2, iv2);
-
-	if (np < 2)
-	{
-		return;
-	}
-
-	// Now clipPoints2 contains the clipped points.
-	manifold->localNormal = localNormal;
-	manifold->localPoint = planePoint;
-
-	int32 pointCount = 0;
-	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
-	{
-		float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
-
-		if (separation <= totalRadius)
-		{
-			b2ManifoldPoint* cp = manifold->points + pointCount;
-			cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
-			cp->id = clipPoints2[i].id;
-			if (flip)
-			{
-				// Swap features
-				b2ContactFeature cf = cp->id.cf;
-				cp->id.cf.indexA = cf.indexB;
-				cp->id.cf.indexB = cf.indexA;
-				cp->id.cf.typeA = cf.typeB;
-				cp->id.cf.typeB = cf.typeA;
-			}
-			++pointCount;
-		}
-	}
-
-	manifold->pointCount = pointCount;
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+// Find the max separation between poly1 and poly2 using edge normals from poly1.
+static float32 b2FindMaxSeparation(int32* edgeIndex,
+								 const b2PolygonShape* poly1, const b2Transform& xf1,
+								 const b2PolygonShape* poly2, const b2Transform& xf2)
+{
+	int32 count1 = poly1->m_count;
+	int32 count2 = poly2->m_count;
+	const b2Vec2* n1s = poly1->m_normals;
+	const b2Vec2* v1s = poly1->m_vertices;
+	const b2Vec2* v2s = poly2->m_vertices;
+	b2Transform xf = b2MulT(xf2, xf1);
+
+	int32 bestIndex = 0;
+	float32 maxSeparation = -b2_maxFloat;
+	for (int32 i = 0; i < count1; ++i)
+	{
+		// Get poly1 normal in frame2.
+		b2Vec2 n = b2Mul(xf.q, n1s[i]);
+		b2Vec2 v1 = b2Mul(xf, v1s[i]);
+
+		// Find deepest point for normal i.
+		float32 si = b2_maxFloat;
+		for (int32 j = 0; j < count2; ++j)
+		{
+			float32 sij = b2Dot(n, v2s[j] - v1);
+			if (sij < si)
+			{
+				si = sij;
+			}
+		}
+
+		if (si > maxSeparation)
+		{
+			maxSeparation = si;
+			bestIndex = i;
+		}
+	}
+
+	*edgeIndex = bestIndex;
+	return maxSeparation;
+}
+
+static void b2FindIncidentEdge(b2ClipVertex c[2],
+							 const b2PolygonShape* poly1, const b2Transform& xf1, int32 edge1,
+							 const b2PolygonShape* poly2, const b2Transform& xf2)
+{
+	const b2Vec2* normals1 = poly1->m_normals;
+
+	int32 count2 = poly2->m_count;
+	const b2Vec2* vertices2 = poly2->m_vertices;
+	const b2Vec2* normals2 = poly2->m_normals;
+
+	b2Assert(0 <= edge1 && edge1 < poly1->m_count);
+
+	// Get the normal of the reference edge in poly2's frame.
+	b2Vec2 normal1 = b2MulT(xf2.q, b2Mul(xf1.q, normals1[edge1]));
+
+	// Find the incident edge on poly2.
+	int32 index = 0;
+	float32 minDot = b2_maxFloat;
+	for (int32 i = 0; i < count2; ++i)
+	{
+		float32 dot = b2Dot(normal1, normals2[i]);
+		if (dot < minDot)
+		{
+			minDot = dot;
+			index = i;
+		}
+	}
+
+	// Build the clip vertices for the incident edge.
+	int32 i1 = index;
+	int32 i2 = i1 + 1 < count2 ? i1 + 1 : 0;
+
+	c[0].v = b2Mul(xf2, vertices2[i1]);
+	c[0].id.cf.indexA = (uint8)edge1;
+	c[0].id.cf.indexB = (uint8)i1;
+	c[0].id.cf.typeA = b2ContactFeature::e_face;
+	c[0].id.cf.typeB = b2ContactFeature::e_vertex;
+
+	c[1].v = b2Mul(xf2, vertices2[i2]);
+	c[1].id.cf.indexA = (uint8)edge1;
+	c[1].id.cf.indexB = (uint8)i2;
+	c[1].id.cf.typeA = b2ContactFeature::e_face;
+	c[1].id.cf.typeB = b2ContactFeature::e_vertex;
+}
+
+// Find edge normal of max separation on A - return if separating axis is found
+// Find edge normal of max separation on B - return if separation axis is found
+// Choose reference edge as min(minA, minB)
+// Find incident edge
+// Clip
+
+// The normal points from 1 to 2
+void b2CollidePolygons(b2Manifold* manifold,
+					  const b2PolygonShape* polyA, const b2Transform& xfA,
+					  const b2PolygonShape* polyB, const b2Transform& xfB)
+{
+	manifold->pointCount = 0;
+	float32 totalRadius = polyA->m_radius + polyB->m_radius;
+
+	int32 edgeA = 0;
+	float32 separationA = b2FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB);
+	if (separationA > totalRadius)
+		return;
+
+	int32 edgeB = 0;
+	float32 separationB = b2FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA);
+	if (separationB > totalRadius)
+		return;
+
+	const b2PolygonShape* poly1;	// reference polygon
+	const b2PolygonShape* poly2;	// incident polygon
+	b2Transform xf1, xf2;
+	int32 edge1;					// reference edge
+	uint8 flip;
+	const float32 k_tol = 0.1f * b2_linearSlop;
+
+	if (separationB > separationA + k_tol)
+	{
+		poly1 = polyB;
+		poly2 = polyA;
+		xf1 = xfB;
+		xf2 = xfA;
+		edge1 = edgeB;
+		manifold->type = b2Manifold::e_faceB;
+		flip = 1;
+	}
+	else
+	{
+		poly1 = polyA;
+		poly2 = polyB;
+		xf1 = xfA;
+		xf2 = xfB;
+		edge1 = edgeA;
+		manifold->type = b2Manifold::e_faceA;
+		flip = 0;
+	}
+
+	b2ClipVertex incidentEdge[2];
+	b2FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2);
+
+	int32 count1 = poly1->m_count;
+	const b2Vec2* vertices1 = poly1->m_vertices;
+
+	int32 iv1 = edge1;
+	int32 iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
+
+	b2Vec2 v11 = vertices1[iv1];
+	b2Vec2 v12 = vertices1[iv2];
+
+	b2Vec2 localTangent = v12 - v11;
+	localTangent.Normalize();
+	
+	b2Vec2 localNormal = b2Cross(localTangent, 1.0f);
+	b2Vec2 planePoint = 0.5f * (v11 + v12);
+
+	b2Vec2 tangent = b2Mul(xf1.q, localTangent);
+	b2Vec2 normal = b2Cross(tangent, 1.0f);
+	
+	v11 = b2Mul(xf1, v11);
+	v12 = b2Mul(xf1, v12);
+
+	// Face offset.
+	float32 frontOffset = b2Dot(normal, v11);
+
+	// Side offsets, extended by polytope skin thickness.
+	float32 sideOffset1 = -b2Dot(tangent, v11) + totalRadius;
+	float32 sideOffset2 = b2Dot(tangent, v12) + totalRadius;
+
+	// Clip incident edge against extruded edge1 side edges.
+	b2ClipVertex clipPoints1[2];
+	b2ClipVertex clipPoints2[2];
+	int np;
+
+	// Clip to box side 1
+	np = b2ClipSegmentToLine(clipPoints1, incidentEdge, -tangent, sideOffset1, iv1);
+
+	if (np < 2)
+		return;
+
+	// Clip to negative box side 1
+	np = b2ClipSegmentToLine(clipPoints2, clipPoints1,  tangent, sideOffset2, iv2);
+
+	if (np < 2)
+	{
+		return;
+	}
+
+	// Now clipPoints2 contains the clipped points.
+	manifold->localNormal = localNormal;
+	manifold->localPoint = planePoint;
+
+	int32 pointCount = 0;
+	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+	{
+		float32 separation = b2Dot(normal, clipPoints2[i].v) - frontOffset;
+
+		if (separation <= totalRadius)
+		{
+			b2ManifoldPoint* cp = manifold->points + pointCount;
+			cp->localPoint = b2MulT(xf2, clipPoints2[i].v);
+			cp->id = clipPoints2[i].id;
+			if (flip)
+			{
+				// Swap features
+				b2ContactFeature cf = cp->id.cf;
+				cp->id.cf.indexA = cf.indexB;
+				cp->id.cf.indexB = cf.indexA;
+				cp->id.cf.typeA = cf.typeB;
+				cp->id.cf.typeB = cf.typeA;
+			}
+			++pointCount;
+		}
+	}
+
+	manifold->pointCount = pointCount;
+}

+ 252 - 249
engine/source/Box2D/Collision/b2Collision.cpp

@@ -1,249 +1,252 @@
-/*
-* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/b2Distance.h>
-
-void b2WorldManifold::Initialize(const b2Manifold* manifold,
-						  const b2Transform& xfA, float32 radiusA,
-						  const b2Transform& xfB, float32 radiusB)
-{
-	if (manifold->pointCount == 0)
-	{
-		return;
-	}
-
-	switch (manifold->type)
-	{
-	case b2Manifold::e_circles:
-		{
-			normal.Set(1.0f, 0.0f);
-			b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
-			b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
-			if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
-			{
-				normal = pointB - pointA;
-				normal.Normalize();
-			}
-
-			b2Vec2 cA = pointA + radiusA * normal;
-			b2Vec2 cB = pointB - radiusB * normal;
-			points[0] = 0.5f * (cA + cB);
-		}
-		break;
-
-	case b2Manifold::e_faceA:
-		{
-			normal = b2Mul(xfA.q, manifold->localNormal);
-			b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
-			
-			for (int32 i = 0; i < manifold->pointCount; ++i)
-			{
-				b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
-				b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
-				b2Vec2 cB = clipPoint - radiusB * normal;
-				points[i] = 0.5f * (cA + cB);
-			}
-		}
-		break;
-
-	case b2Manifold::e_faceB:
-		{
-			normal = b2Mul(xfB.q, manifold->localNormal);
-			b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
-
-			for (int32 i = 0; i < manifold->pointCount; ++i)
-			{
-				b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
-				b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
-				b2Vec2 cA = clipPoint - radiusA * normal;
-				points[i] = 0.5f * (cA + cB);
-			}
-
-			// Ensure normal points from A to B.
-			normal = -normal;
-		}
-		break;
-	}
-}
-
-void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
-					  const b2Manifold* manifold1, const b2Manifold* manifold2)
-{
-	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
-	{
-		state1[i] = b2_nullState;
-		state2[i] = b2_nullState;
-	}
-
-	// Detect persists and removes.
-	for (int32 i = 0; i < manifold1->pointCount; ++i)
-	{
-		b2ContactID id = manifold1->points[i].id;
-
-		state1[i] = b2_removeState;
-
-		for (int32 j = 0; j < manifold2->pointCount; ++j)
-		{
-			if (manifold2->points[j].id.key == id.key)
-			{
-				state1[i] = b2_persistState;
-				break;
-			}
-		}
-	}
-
-	// Detect persists and adds.
-	for (int32 i = 0; i < manifold2->pointCount; ++i)
-	{
-		b2ContactID id = manifold2->points[i].id;
-
-		state2[i] = b2_addState;
-
-		for (int32 j = 0; j < manifold1->pointCount; ++j)
-		{
-			if (manifold1->points[j].id.key == id.key)
-			{
-				state2[i] = b2_persistState;
-				break;
-			}
-		}
-	}
-}
-
-// From Real-time Collision Detection, p179.
-bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
-{
-	float32 tmin = -b2_maxFloat;
-	float32 tmax = b2_maxFloat;
-
-	b2Vec2 p = input.p1;
-	b2Vec2 d = input.p2 - input.p1;
-	b2Vec2 absD = b2Abs(d);
-
-	b2Vec2 normal;
-
-	for (int32 i = 0; i < 2; ++i)
-	{
-		if (absD(i) < b2_epsilon)
-		{
-			// Parallel.
-			if (p(i) < lowerBound(i) || upperBound(i) < p(i))
-			{
-				return false;
-			}
-		}
-		else
-		{
-			float32 inv_d = 1.0f / d(i);
-			float32 t1 = (lowerBound(i) - p(i)) * inv_d;
-			float32 t2 = (upperBound(i) - p(i)) * inv_d;
-
-			// Sign of the normal vector.
-			float32 s = -1.0f;
-
-			if (t1 > t2)
-			{
-				b2Swap(t1, t2);
-				s = 1.0f;
-			}
-
-			// Push the min up
-			if (t1 > tmin)
-			{
-				normal.SetZero();
-				normal(i) = s;
-				tmin = t1;
-			}
-
-			// Pull the max down
-			tmax = b2Min(tmax, t2);
-
-			if (tmin > tmax)
-			{
-				return false;
-			}
-		}
-	}
-
-	// Does the ray start inside the box?
-	// Does the ray intersect beyond the max fraction?
-	if (tmin < 0.0f || input.maxFraction < tmin)
-	{
-		return false;
-	}
-
-	// Intersection.
-	output->fraction = tmin;
-	output->normal = normal;
-	return true;
-}
-
-// Sutherland-Hodgman clipping.
-int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
-						const b2Vec2& normal, float32 offset, int32 vertexIndexA)
-{
-	// Start with no output points
-	int32 numOut = 0;
-
-	// Calculate the distance of end points to the line
-	float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
-	float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
-
-	// If the points are behind the plane
-	if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
-	if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
-
-	// If the points are on different sides of the plane
-	if (distance0 * distance1 < 0.0f)
-	{
-		// Find intersection point of edge and plane
-		float32 interp = distance0 / (distance0 - distance1);
-		vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
-
-		// VertexA is hitting edgeB.
-		vOut[numOut].id.cf.indexA = vertexIndexA;
-		vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
-		vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
-		vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
-		++numOut;
-	}
-
-	return numOut;
-}
-
-bool b2TestOverlap(	const b2Shape* shapeA, int32 indexA,
-					const b2Shape* shapeB, int32 indexB,
-					const b2Transform& xfA, const b2Transform& xfB)
-{
-	b2DistanceInput input;
-	input.proxyA.Set(shapeA, indexA);
-	input.proxyB.Set(shapeB, indexB);
-	input.transformA = xfA;
-	input.transformB = xfB;
-	input.useRadii = true;
-
-	b2SimplexCache cache;
-	cache.count = 0;
-
-	b2DistanceOutput output;
-
-	b2Distance(&output, &cache, &input);
-
-	return output.distance < 10.0f * b2_epsilon;
-}
+/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2Distance.h>
+
+void b2WorldManifold::Initialize(const b2Manifold* manifold,
+						  const b2Transform& xfA, float32 radiusA,
+						  const b2Transform& xfB, float32 radiusB)
+{
+	if (manifold->pointCount == 0)
+	{
+		return;
+	}
+
+	switch (manifold->type)
+	{
+	case b2Manifold::e_circles:
+		{
+			normal.Set(1.0f, 0.0f);
+			b2Vec2 pointA = b2Mul(xfA, manifold->localPoint);
+			b2Vec2 pointB = b2Mul(xfB, manifold->points[0].localPoint);
+			if (b2DistanceSquared(pointA, pointB) > b2_epsilon * b2_epsilon)
+			{
+				normal = pointB - pointA;
+				normal.Normalize();
+			}
+
+			b2Vec2 cA = pointA + radiusA * normal;
+			b2Vec2 cB = pointB - radiusB * normal;
+			points[0] = 0.5f * (cA + cB);
+			separations[0] = b2Dot(cB - cA, normal);
+		}
+		break;
+
+	case b2Manifold::e_faceA:
+		{
+			normal = b2Mul(xfA.q, manifold->localNormal);
+			b2Vec2 planePoint = b2Mul(xfA, manifold->localPoint);
+			
+			for (int32 i = 0; i < manifold->pointCount; ++i)
+			{
+				b2Vec2 clipPoint = b2Mul(xfB, manifold->points[i].localPoint);
+				b2Vec2 cA = clipPoint + (radiusA - b2Dot(clipPoint - planePoint, normal)) * normal;
+				b2Vec2 cB = clipPoint - radiusB * normal;
+				points[i] = 0.5f * (cA + cB);
+				separations[i] = b2Dot(cB - cA, normal);
+			}
+		}
+		break;
+
+	case b2Manifold::e_faceB:
+		{
+			normal = b2Mul(xfB.q, manifold->localNormal);
+			b2Vec2 planePoint = b2Mul(xfB, manifold->localPoint);
+
+			for (int32 i = 0; i < manifold->pointCount; ++i)
+			{
+				b2Vec2 clipPoint = b2Mul(xfA, manifold->points[i].localPoint);
+				b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal;
+				b2Vec2 cA = clipPoint - radiusA * normal;
+				points[i] = 0.5f * (cA + cB);
+				separations[i] = b2Dot(cA - cB, normal);
+			}
+
+			// Ensure normal points from A to B.
+			normal = -normal;
+		}
+		break;
+	}
+}
+
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
+					  const b2Manifold* manifold1, const b2Manifold* manifold2)
+{
+	for (int32 i = 0; i < b2_maxManifoldPoints; ++i)
+	{
+		state1[i] = b2_nullState;
+		state2[i] = b2_nullState;
+	}
+
+	// Detect persists and removes.
+	for (int32 i = 0; i < manifold1->pointCount; ++i)
+	{
+		b2ContactID id = manifold1->points[i].id;
+
+		state1[i] = b2_removeState;
+
+		for (int32 j = 0; j < manifold2->pointCount; ++j)
+		{
+			if (manifold2->points[j].id.key == id.key)
+			{
+				state1[i] = b2_persistState;
+				break;
+			}
+		}
+	}
+
+	// Detect persists and adds.
+	for (int32 i = 0; i < manifold2->pointCount; ++i)
+	{
+		b2ContactID id = manifold2->points[i].id;
+
+		state2[i] = b2_addState;
+
+		for (int32 j = 0; j < manifold1->pointCount; ++j)
+		{
+			if (manifold1->points[j].id.key == id.key)
+			{
+				state2[i] = b2_persistState;
+				break;
+			}
+		}
+	}
+}
+
+// From Real-time Collision Detection, p179.
+bool b2AABB::RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const
+{
+	float32 tmin = -b2_maxFloat;
+	float32 tmax = b2_maxFloat;
+
+	b2Vec2 p = input.p1;
+	b2Vec2 d = input.p2 - input.p1;
+	b2Vec2 absD = b2Abs(d);
+
+	b2Vec2 normal;
+
+	for (int32 i = 0; i < 2; ++i)
+	{
+		if (absD(i) < b2_epsilon)
+		{
+			// Parallel.
+			if (p(i) < lowerBound(i) || upperBound(i) < p(i))
+			{
+				return false;
+			}
+		}
+		else
+		{
+			float32 inv_d = 1.0f / d(i);
+			float32 t1 = (lowerBound(i) - p(i)) * inv_d;
+			float32 t2 = (upperBound(i) - p(i)) * inv_d;
+
+			// Sign of the normal vector.
+			float32 s = -1.0f;
+
+			if (t1 > t2)
+			{
+				b2Swap(t1, t2);
+				s = 1.0f;
+			}
+
+			// Push the min up
+			if (t1 > tmin)
+			{
+				normal.SetZero();
+				normal(i) = s;
+				tmin = t1;
+			}
+
+			// Pull the max down
+			tmax = b2Min(tmax, t2);
+
+			if (tmin > tmax)
+			{
+				return false;
+			}
+		}
+	}
+
+	// Does the ray start inside the box?
+	// Does the ray intersect beyond the max fraction?
+	if (tmin < 0.0f || input.maxFraction < tmin)
+	{
+		return false;
+	}
+
+	// Intersection.
+	output->fraction = tmin;
+	output->normal = normal;
+	return true;
+}
+
+// Sutherland-Hodgman clipping.
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
+						const b2Vec2& normal, float32 offset, int32 vertexIndexA)
+{
+	// Start with no output points
+	int32 numOut = 0;
+
+	// Calculate the distance of end points to the line
+	float32 distance0 = b2Dot(normal, vIn[0].v) - offset;
+	float32 distance1 = b2Dot(normal, vIn[1].v) - offset;
+
+	// If the points are behind the plane
+	if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
+	if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
+
+	// If the points are on different sides of the plane
+	if (distance0 * distance1 < 0.0f)
+	{
+		// Find intersection point of edge and plane
+		float32 interp = distance0 / (distance0 - distance1);
+		vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v);
+
+		// VertexA is hitting edgeB.
+		vOut[numOut].id.cf.indexA = static_cast<uint8>(vertexIndexA);
+		vOut[numOut].id.cf.indexB = vIn[0].id.cf.indexB;
+		vOut[numOut].id.cf.typeA = b2ContactFeature::e_vertex;
+		vOut[numOut].id.cf.typeB = b2ContactFeature::e_face;
+		++numOut;
+	}
+
+	return numOut;
+}
+
+bool b2TestOverlap(	const b2Shape* shapeA, int32 indexA,
+					const b2Shape* shapeB, int32 indexB,
+					const b2Transform& xfA, const b2Transform& xfB)
+{
+	b2DistanceInput input;
+	input.proxyA.Set(shapeA, indexA);
+	input.proxyB.Set(shapeB, indexB);
+	input.transformA = xfA;
+	input.transformB = xfB;
+	input.useRadii = true;
+
+	b2SimplexCache cache;
+	cache.count = 0;
+
+	b2DistanceOutput output;
+
+	b2Distance(&output, &cache, &input);
+
+	return output.distance < 10.0f * b2_epsilon;
+}

+ 277 - 276
engine/source/Box2D/Collision/b2Collision.h

@@ -1,276 +1,277 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_COLLISION_H
-#define B2_COLLISION_H
-
-#include <Box2D/Common/b2Math.h>
-#include <climits>
-
-/// @file
-/// Structures and functions used for computing contact points, distance
-/// queries, and TOI queries.
-
-class b2Shape;
-class b2CircleShape;
-class b2EdgeShape;
-class b2PolygonShape;
-
-const uint8 b2_nullFeature = UCHAR_MAX;
-
-/// The features that intersect to form the contact point
-/// This must be 4 bytes or less.
-struct b2ContactFeature
-{
-	enum Type
-	{
-		e_vertex = 0,
-		e_face = 1
-	};
-
-	uint8 indexA;		///< Feature index on shapeA
-	uint8 indexB;		///< Feature index on shapeB
-	uint8 typeA;		///< The feature type on shapeA
-	uint8 typeB;		///< The feature type on shapeB
-};
-
-/// Contact ids to facilitate warm starting.
-union b2ContactID
-{
-	b2ContactFeature cf;
-	uint32 key;					///< Used to quickly compare contact ids.
-};
-
-/// A manifold point is a contact point belonging to a contact
-/// manifold. It holds details related to the geometry and dynamics
-/// of the contact points.
-/// The local point usage depends on the manifold type:
-/// -e_circles: the local center of circleB
-/// -e_faceA: the local center of cirlceB or the clip point of polygonB
-/// -e_faceB: the clip point of polygonA
-/// This structure is stored across time steps, so we keep it small.
-/// Note: the impulses are used for internal caching and may not
-/// provide reliable contact forces, especially for high speed collisions.
-struct b2ManifoldPoint
-{
-	b2Vec2 localPoint;		///< usage depends on manifold type
-	float32 normalImpulse;	///< the non-penetration impulse
-	float32 tangentImpulse;	///< the friction impulse
-	b2ContactID id;			///< uniquely identifies a contact point between two shapes
-};
-
-/// A manifold for two touching convex shapes.
-/// Box2D supports multiple types of contact:
-/// - clip point versus plane with radius
-/// - point versus point with radius (circles)
-/// The local point usage depends on the manifold type:
-/// -e_circles: the local center of circleA
-/// -e_faceA: the center of faceA
-/// -e_faceB: the center of faceB
-/// Similarly the local normal usage:
-/// -e_circles: not used
-/// -e_faceA: the normal on polygonA
-/// -e_faceB: the normal on polygonB
-/// We store contacts in this way so that position correction can
-/// account for movement, which is critical for continuous physics.
-/// All contact scenarios must be expressed in one of these types.
-/// This structure is stored across time steps, so we keep it small.
-struct b2Manifold
-{
-	enum Type
-	{
-		e_circles,
-		e_faceA,
-		e_faceB
-	};
-
-	b2ManifoldPoint points[b2_maxManifoldPoints];	///< the points of contact
-	b2Vec2 localNormal;								///< not use for Type::e_points
-	b2Vec2 localPoint;								///< usage depends on manifold type
-	Type type;
-	int32 pointCount;								///< the number of manifold points
-};
-
-/// This is used to compute the current state of a contact manifold.
-struct b2WorldManifold
-{
-	/// Evaluate the manifold with supplied transforms. This assumes
-	/// modest motion from the original state. This does not change the
-	/// point count, impulses, etc. The radii must come from the shapes
-	/// that generated the manifold.
-	void Initialize(const b2Manifold* manifold,
-					const b2Transform& xfA, float32 radiusA,
-					const b2Transform& xfB, float32 radiusB);
-
-	b2Vec2 normal;							///< world vector pointing from A to B
-	b2Vec2 points[b2_maxManifoldPoints];	///< world contact point (point of intersection)
-};
-
-/// This is used for determining the state of contact points.
-enum b2PointState
-{
-	b2_nullState,		///< point does not exist
-	b2_addState,		///< point was added in the update
-	b2_persistState,	///< point persisted across the update
-	b2_removeState		///< point was removed in the update
-};
-
-/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
-/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
-void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
-					  const b2Manifold* manifold1, const b2Manifold* manifold2);
-
-/// Used for computing contact manifolds.
-struct b2ClipVertex
-{
-	b2Vec2 v;
-	b2ContactID id;
-};
-
-/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
-struct b2RayCastInput
-{
-	b2Vec2 p1, p2;
-	float32 maxFraction;
-};
-
-/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
-/// come from b2RayCastInput.
-struct b2RayCastOutput
-{
-	b2Vec2 normal;
-	float32 fraction;
-};
-
-/// An axis aligned bounding box.
-struct b2AABB
-{
-	/// Verify that the bounds are sorted.
-	bool IsValid() const;
-
-	/// Get the center of the AABB.
-	b2Vec2 GetCenter() const
-	{
-		return 0.5f * (lowerBound + upperBound);
-	}
-
-	/// Get the extents of the AABB (half-widths).
-	b2Vec2 GetExtents() const
-	{
-		return 0.5f * (upperBound - lowerBound);
-	}
-
-	/// Get the perimeter length
-	float32 GetPerimeter() const
-	{
-		float32 wx = upperBound.x - lowerBound.x;
-		float32 wy = upperBound.y - lowerBound.y;
-		return 2.0f * (wx + wy);
-	}
-
-	/// Combine an AABB into this one.
-	void Combine(const b2AABB& aabb)
-	{
-		lowerBound = b2Min(lowerBound, aabb.lowerBound);
-		upperBound = b2Max(upperBound, aabb.upperBound);
-	}
-
-	/// Combine two AABBs into this one.
-	void Combine(const b2AABB& aabb1, const b2AABB& aabb2)
-	{
-		lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
-		upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
-	}
-
-	/// Does this aabb contain the provided AABB.
-	bool Contains(const b2AABB& aabb) const
-	{
-		bool result = true;
-		result = result && lowerBound.x <= aabb.lowerBound.x;
-		result = result && lowerBound.y <= aabb.lowerBound.y;
-		result = result && aabb.upperBound.x <= upperBound.x;
-		result = result && aabb.upperBound.y <= upperBound.y;
-		return result;
-	}
-
-	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
-
-	b2Vec2 lowerBound;	///< the lower vertex
-	b2Vec2 upperBound;	///< the upper vertex
-};
-
-/// Compute the collision manifold between two circles.
-void b2CollideCircles(b2Manifold* manifold,
-					  const b2CircleShape* circleA, const b2Transform& xfA,
-					  const b2CircleShape* circleB, const b2Transform& xfB);
-
-/// Compute the collision manifold between a polygon and a circle.
-void b2CollidePolygonAndCircle(b2Manifold* manifold,
-							   const b2PolygonShape* polygonA, const b2Transform& xfA,
-							   const b2CircleShape* circleB, const b2Transform& xfB);
-
-/// Compute the collision manifold between two polygons.
-void b2CollidePolygons(b2Manifold* manifold,
-					   const b2PolygonShape* polygonA, const b2Transform& xfA,
-					   const b2PolygonShape* polygonB, const b2Transform& xfB);
-
-/// Compute the collision manifold between an edge and a circle.
-void b2CollideEdgeAndCircle(b2Manifold* manifold,
-							   const b2EdgeShape* polygonA, const b2Transform& xfA,
-							   const b2CircleShape* circleB, const b2Transform& xfB);
-
-/// Compute the collision manifold between an edge and a circle.
-void b2CollideEdgeAndPolygon(b2Manifold* manifold,
-							   const b2EdgeShape* edgeA, const b2Transform& xfA,
-							   const b2PolygonShape* circleB, const b2Transform& xfB);
-
-/// Clipping for contact manifolds.
-int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
-							const b2Vec2& normal, float32 offset, int32 vertexIndexA);
-
-/// Determine if two generic shapes overlap.
-bool b2TestOverlap(	const b2Shape* shapeA, int32 indexA,
-					const b2Shape* shapeB, int32 indexB,
-					const b2Transform& xfA, const b2Transform& xfB);
-
-// ---------------- Inline Functions ------------------------------------------
-
-inline bool b2AABB::IsValid() const
-{
-	b2Vec2 d = upperBound - lowerBound;
-	bool valid = d.x >= 0.0f && d.y >= 0.0f;
-	valid = valid && lowerBound.IsValid() && upperBound.IsValid();
-	return valid;
-}
-
-inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)
-{
-	b2Vec2 d1, d2;
-	d1 = b.lowerBound - a.upperBound;
-	d2 = a.lowerBound - b.upperBound;
-
-	if (d1.x > 0.0f || d1.y > 0.0f)
-		return false;
-
-	if (d2.x > 0.0f || d2.y > 0.0f)
-		return false;
-
-	return true;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_COLLISION_H
+#define B2_COLLISION_H
+
+#include <Box2D/Common/b2Math.h>
+#include <limits.h>
+
+/// @file
+/// Structures and functions used for computing contact points, distance
+/// queries, and TOI queries.
+
+class b2Shape;
+class b2CircleShape;
+class b2EdgeShape;
+class b2PolygonShape;
+
+const uint8 b2_nullFeature = UCHAR_MAX;
+
+/// The features that intersect to form the contact point
+/// This must be 4 bytes or less.
+struct b2ContactFeature
+{
+	enum Type
+	{
+		e_vertex = 0,
+		e_face = 1
+	};
+
+	uint8 indexA;		///< Feature index on shapeA
+	uint8 indexB;		///< Feature index on shapeB
+	uint8 typeA;		///< The feature type on shapeA
+	uint8 typeB;		///< The feature type on shapeB
+};
+
+/// Contact ids to facilitate warm starting.
+union b2ContactID
+{
+	b2ContactFeature cf;
+	uint32 key;					///< Used to quickly compare contact ids.
+};
+
+/// A manifold point is a contact point belonging to a contact
+/// manifold. It holds details related to the geometry and dynamics
+/// of the contact points.
+/// The local point usage depends on the manifold type:
+/// -e_circles: the local center of circleB
+/// -e_faceA: the local center of cirlceB or the clip point of polygonB
+/// -e_faceB: the clip point of polygonA
+/// This structure is stored across time steps, so we keep it small.
+/// Note: the impulses are used for internal caching and may not
+/// provide reliable contact forces, especially for high speed collisions.
+struct b2ManifoldPoint
+{
+	b2Vec2 localPoint;		///< usage depends on manifold type
+	float32 normalImpulse;	///< the non-penetration impulse
+	float32 tangentImpulse;	///< the friction impulse
+	b2ContactID id;			///< uniquely identifies a contact point between two shapes
+};
+
+/// A manifold for two touching convex shapes.
+/// Box2D supports multiple types of contact:
+/// - clip point versus plane with radius
+/// - point versus point with radius (circles)
+/// The local point usage depends on the manifold type:
+/// -e_circles: the local center of circleA
+/// -e_faceA: the center of faceA
+/// -e_faceB: the center of faceB
+/// Similarly the local normal usage:
+/// -e_circles: not used
+/// -e_faceA: the normal on polygonA
+/// -e_faceB: the normal on polygonB
+/// We store contacts in this way so that position correction can
+/// account for movement, which is critical for continuous physics.
+/// All contact scenarios must be expressed in one of these types.
+/// This structure is stored across time steps, so we keep it small.
+struct b2Manifold
+{
+	enum Type
+	{
+		e_circles,
+		e_faceA,
+		e_faceB
+	};
+
+	b2ManifoldPoint points[b2_maxManifoldPoints];	///< the points of contact
+	b2Vec2 localNormal;								///< not use for Type::e_points
+	b2Vec2 localPoint;								///< usage depends on manifold type
+	Type type;
+	int32 pointCount;								///< the number of manifold points
+};
+
+/// This is used to compute the current state of a contact manifold.
+struct b2WorldManifold
+{
+	/// Evaluate the manifold with supplied transforms. This assumes
+	/// modest motion from the original state. This does not change the
+	/// point count, impulses, etc. The radii must come from the shapes
+	/// that generated the manifold.
+	void Initialize(const b2Manifold* manifold,
+					const b2Transform& xfA, float32 radiusA,
+					const b2Transform& xfB, float32 radiusB);
+
+	b2Vec2 normal;								///< world vector pointing from A to B
+	b2Vec2 points[b2_maxManifoldPoints];		///< world contact point (point of intersection)
+	float32 separations[b2_maxManifoldPoints];	///< a negative value indicates overlap, in meters
+};
+
+/// This is used for determining the state of contact points.
+enum b2PointState
+{
+	b2_nullState,		///< point does not exist
+	b2_addState,		///< point was added in the update
+	b2_persistState,	///< point persisted across the update
+	b2_removeState		///< point was removed in the update
+};
+
+/// Compute the point states given two manifolds. The states pertain to the transition from manifold1
+/// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
+void b2GetPointStates(b2PointState state1[b2_maxManifoldPoints], b2PointState state2[b2_maxManifoldPoints],
+					  const b2Manifold* manifold1, const b2Manifold* manifold2);
+
+/// Used for computing contact manifolds.
+struct b2ClipVertex
+{
+	b2Vec2 v;
+	b2ContactID id;
+};
+
+/// Ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+struct b2RayCastInput
+{
+	b2Vec2 p1, p2;
+	float32 maxFraction;
+};
+
+/// Ray-cast output data. The ray hits at p1 + fraction * (p2 - p1), where p1 and p2
+/// come from b2RayCastInput.
+struct b2RayCastOutput
+{
+	b2Vec2 normal;
+	float32 fraction;
+};
+
+/// An axis aligned bounding box.
+struct b2AABB
+{
+	/// Verify that the bounds are sorted.
+	bool IsValid() const;
+
+	/// Get the center of the AABB.
+	b2Vec2 GetCenter() const
+	{
+		return 0.5f * (lowerBound + upperBound);
+	}
+
+	/// Get the extents of the AABB (half-widths).
+	b2Vec2 GetExtents() const
+	{
+		return 0.5f * (upperBound - lowerBound);
+	}
+
+	/// Get the perimeter length
+	float32 GetPerimeter() const
+	{
+		float32 wx = upperBound.x - lowerBound.x;
+		float32 wy = upperBound.y - lowerBound.y;
+		return 2.0f * (wx + wy);
+	}
+
+	/// Combine an AABB into this one.
+	void Combine(const b2AABB& aabb)
+	{
+		lowerBound = b2Min(lowerBound, aabb.lowerBound);
+		upperBound = b2Max(upperBound, aabb.upperBound);
+	}
+
+	/// Combine two AABBs into this one.
+	void Combine(const b2AABB& aabb1, const b2AABB& aabb2)
+	{
+		lowerBound = b2Min(aabb1.lowerBound, aabb2.lowerBound);
+		upperBound = b2Max(aabb1.upperBound, aabb2.upperBound);
+	}
+
+	/// Does this aabb contain the provided AABB.
+	bool Contains(const b2AABB& aabb) const
+	{
+		bool result = true;
+		result = result && lowerBound.x <= aabb.lowerBound.x;
+		result = result && lowerBound.y <= aabb.lowerBound.y;
+		result = result && aabb.upperBound.x <= upperBound.x;
+		result = result && aabb.upperBound.y <= upperBound.y;
+		return result;
+	}
+
+	bool RayCast(b2RayCastOutput* output, const b2RayCastInput& input) const;
+
+	b2Vec2 lowerBound;	///< the lower vertex
+	b2Vec2 upperBound;	///< the upper vertex
+};
+
+/// Compute the collision manifold between two circles.
+void b2CollideCircles(b2Manifold* manifold,
+					  const b2CircleShape* circleA, const b2Transform& xfA,
+					  const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between a polygon and a circle.
+void b2CollidePolygonAndCircle(b2Manifold* manifold,
+							   const b2PolygonShape* polygonA, const b2Transform& xfA,
+							   const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between two polygons.
+void b2CollidePolygons(b2Manifold* manifold,
+					   const b2PolygonShape* polygonA, const b2Transform& xfA,
+					   const b2PolygonShape* polygonB, const b2Transform& xfB);
+
+/// Compute the collision manifold between an edge and a circle.
+void b2CollideEdgeAndCircle(b2Manifold* manifold,
+							   const b2EdgeShape* polygonA, const b2Transform& xfA,
+							   const b2CircleShape* circleB, const b2Transform& xfB);
+
+/// Compute the collision manifold between an edge and a circle.
+void b2CollideEdgeAndPolygon(b2Manifold* manifold,
+							   const b2EdgeShape* edgeA, const b2Transform& xfA,
+							   const b2PolygonShape* circleB, const b2Transform& xfB);
+
+/// Clipping for contact manifolds.
+int32 b2ClipSegmentToLine(b2ClipVertex vOut[2], const b2ClipVertex vIn[2],
+							const b2Vec2& normal, float32 offset, int32 vertexIndexA);
+
+/// Determine if two generic shapes overlap.
+bool b2TestOverlap(	const b2Shape* shapeA, int32 indexA,
+					const b2Shape* shapeB, int32 indexB,
+					const b2Transform& xfA, const b2Transform& xfB);
+
+// ---------------- Inline Functions ------------------------------------------
+
+inline bool b2AABB::IsValid() const
+{
+	b2Vec2 d = upperBound - lowerBound;
+	bool valid = d.x >= 0.0f && d.y >= 0.0f;
+	valid = valid && lowerBound.IsValid() && upperBound.IsValid();
+	return valid;
+}
+
+inline bool b2TestOverlap(const b2AABB& a, const b2AABB& b)
+{
+	b2Vec2 d1, d2;
+	d1 = b.lowerBound - a.upperBound;
+	d2 = a.lowerBound - b.upperBound;
+
+	if (d1.x > 0.0f || d1.y > 0.0f)
+		return false;
+
+	if (d2.x > 0.0f || d2.y > 0.0f)
+		return false;
+
+	return true;
+}
+
+#endif

+ 614 - 603
engine/source/Box2D/Collision/b2Distance.cpp

@@ -1,603 +1,614 @@
-/*
-* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2Distance.h>
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <Box2D/Collision/Shapes/b2EdgeShape.h>
-#include <Box2D/Collision/Shapes/b2ChainShape.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
-int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
-
-void b2DistanceProxy::Set(const b2Shape* shape, int32 index)
-{
-	switch (shape->GetType())
-	{
-	case b2Shape::e_circle:
-		{
-			const b2CircleShape* circle = (b2CircleShape*)shape;
-			m_vertices = &circle->m_p;
-			m_count = 1;
-			m_radius = circle->m_radius;
-		}
-		break;
-
-	case b2Shape::e_polygon:
-		{
-			const b2PolygonShape* polygon = (b2PolygonShape*)shape;
-			m_vertices = polygon->m_vertices;
-			m_count = polygon->m_count;
-			m_radius = polygon->m_radius;
-		}
-		break;
-
-	case b2Shape::e_chain:
-		{
-			const b2ChainShape* chain = (b2ChainShape*)shape;
-			b2Assert(0 <= index && index < chain->m_count);
-
-			m_buffer[0] = chain->m_vertices[index];
-			if (index + 1 < chain->m_count)
-			{
-				m_buffer[1] = chain->m_vertices[index + 1];
-			}
-			else
-			{
-				m_buffer[1] = chain->m_vertices[0];
-			}
-
-			m_vertices = m_buffer;
-			m_count = 2;
-			m_radius = chain->m_radius;
-		}
-		break;
-
-	case b2Shape::e_edge:
-		{
-			const b2EdgeShape* edge = (b2EdgeShape*)shape;
-			m_vertices = &edge->m_vertex1;
-			m_count = 2;
-			m_radius = edge->m_radius;
-		}
-		break;
-
-	default:
-		b2Assert(false);
-	}
-}
-
-
-struct b2SimplexVertex
-{
-	b2Vec2 wA;		// support point in proxyA
-	b2Vec2 wB;		// support point in proxyB
-	b2Vec2 w;		// wB - wA
-	float32 a;		// barycentric coordinate for closest point
-	int32 indexA;	// wA index
-	int32 indexB;	// wB index
-};
-
-struct b2Simplex
-{
-	void ReadCache(	const b2SimplexCache* cache,
-					const b2DistanceProxy* proxyA, const b2Transform& transformA,
-					const b2DistanceProxy* proxyB, const b2Transform& transformB)
-	{
-		b2Assert(cache->count <= 3);
-		
-		// Copy data from cache.
-		m_count = cache->count;
-		b2SimplexVertex* vertices = &m_v1;
-		for (int32 i = 0; i < m_count; ++i)
-		{
-			b2SimplexVertex* v = vertices + i;
-			v->indexA = cache->indexA[i];
-			v->indexB = cache->indexB[i];
-			b2Vec2 wALocal = proxyA->GetVertex(v->indexA);
-			b2Vec2 wBLocal = proxyB->GetVertex(v->indexB);
-			v->wA = b2Mul(transformA, wALocal);
-			v->wB = b2Mul(transformB, wBLocal);
-			v->w = v->wB - v->wA;
-			v->a = 0.0f;
-		}
-
-		// Compute the new simplex metric, if it is substantially different than
-		// old metric then flush the simplex.
-		if (m_count > 1)
-		{
-			float32 metric1 = cache->metric;
-			float32 metric2 = GetMetric();
-			if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon)
-			{
-				// Reset the simplex.
-				m_count = 0;
-			}
-		}
-
-		// If the cache is empty or invalid ...
-		if (m_count == 0)
-		{
-			b2SimplexVertex* v = vertices + 0;
-			v->indexA = 0;
-			v->indexB = 0;
-			b2Vec2 wALocal = proxyA->GetVertex(0);
-			b2Vec2 wBLocal = proxyB->GetVertex(0);
-			v->wA = b2Mul(transformA, wALocal);
-			v->wB = b2Mul(transformB, wBLocal);
-			v->w = v->wB - v->wA;
-			v->a = 1.0f;
-			m_count = 1;
-		}
-	}
-
-	void WriteCache(b2SimplexCache* cache) const
-	{
-		cache->metric = GetMetric();
-		cache->count = uint16(m_count);
-		const b2SimplexVertex* vertices = &m_v1;
-		for (int32 i = 0; i < m_count; ++i)
-		{
-			cache->indexA[i] = uint8(vertices[i].indexA);
-			cache->indexB[i] = uint8(vertices[i].indexB);
-		}
-	}
-
-	b2Vec2 GetSearchDirection() const
-	{
-		switch (m_count)
-		{
-		case 1:
-			return -m_v1.w;
-
-		case 2:
-			{
-				b2Vec2 e12 = m_v2.w - m_v1.w;
-				float32 sgn = b2Cross(e12, -m_v1.w);
-				if (sgn > 0.0f)
-				{
-					// Origin is left of e12.
-					return b2Cross(1.0f, e12);
-				}
-				else
-				{
-					// Origin is right of e12.
-					return b2Cross(e12, 1.0f);
-				}
-			}
-
-		default:
-			b2Assert(false);
-			return b2Vec2_zero;
-		}
-	}
-
-	b2Vec2 GetClosestPoint() const
-	{
-		switch (m_count)
-		{
-		case 0:
-			b2Assert(false);
-			return b2Vec2_zero;
-
-		case 1:
-			return m_v1.w;
-
-		case 2:
-			return m_v1.a * m_v1.w + m_v2.a * m_v2.w;
-
-		case 3:
-			return b2Vec2_zero;
-
-		default:
-			b2Assert(false);
-			return b2Vec2_zero;
-		}
-	}
-
-	void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const
-	{
-		switch (m_count)
-		{
-		case 0:
-			b2Assert(false);
-			break;
-
-		case 1:
-			*pA = m_v1.wA;
-			*pB = m_v1.wB;
-			break;
-
-		case 2:
-			*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;
-			*pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;
-			break;
-
-		case 3:
-			*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
-			*pB = *pA;
-			break;
-
-		default:
-			b2Assert(false);
-			break;
-		}
-	}
-
-	float32 GetMetric() const
-	{
-		switch (m_count)
-		{
-		case 0:
-			b2Assert(false);
-			return 0.0f;
-
-		case 1:
-			return 0.0f;
-
-		case 2:
-			return b2Distance(m_v1.w, m_v2.w);
-
-		case 3:
-			return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);
-
-		default:
-			b2Assert(false);
-			return 0.0f;
-		}
-	}
-
-	void Solve2();
-	void Solve3();
-
-	b2SimplexVertex m_v1, m_v2, m_v3;
-	int32 m_count;
-};
-
-
-// Solve a line segment using barycentric coordinates.
-//
-// p = a1 * w1 + a2 * w2
-// a1 + a2 = 1
-//
-// The vector from the origin to the closest point on the line is
-// perpendicular to the line.
-// e12 = w2 - w1
-// dot(p, e) = 0
-// a1 * dot(w1, e) + a2 * dot(w2, e) = 0
-//
-// 2-by-2 linear system
-// [1      1     ][a1] = [1]
-// [w1.e12 w2.e12][a2] = [0]
-//
-// Define
-// d12_1 =  dot(w2, e12)
-// d12_2 = -dot(w1, e12)
-// d12 = d12_1 + d12_2
-//
-// Solution
-// a1 = d12_1 / d12
-// a2 = d12_2 / d12
-void b2Simplex::Solve2()
-{
-	b2Vec2 w1 = m_v1.w;
-	b2Vec2 w2 = m_v2.w;
-	b2Vec2 e12 = w2 - w1;
-
-	// w1 region
-	float32 d12_2 = -b2Dot(w1, e12);
-	if (d12_2 <= 0.0f)
-	{
-		// a2 <= 0, so we clamp it to 0
-		m_v1.a = 1.0f;
-		m_count = 1;
-		return;
-	}
-
-	// w2 region
-	float32 d12_1 = b2Dot(w2, e12);
-	if (d12_1 <= 0.0f)
-	{
-		// a1 <= 0, so we clamp it to 0
-		m_v2.a = 1.0f;
-		m_count = 1;
-		m_v1 = m_v2;
-		return;
-	}
-
-	// Must be in e12 region.
-	float32 inv_d12 = 1.0f / (d12_1 + d12_2);
-	m_v1.a = d12_1 * inv_d12;
-	m_v2.a = d12_2 * inv_d12;
-	m_count = 2;
-}
-
-// Possible regions:
-// - points[2]
-// - edge points[0]-points[2]
-// - edge points[1]-points[2]
-// - inside the triangle
-void b2Simplex::Solve3()
-{
-	b2Vec2 w1 = m_v1.w;
-	b2Vec2 w2 = m_v2.w;
-	b2Vec2 w3 = m_v3.w;
-
-	// Edge12
-	// [1      1     ][a1] = [1]
-	// [w1.e12 w2.e12][a2] = [0]
-	// a3 = 0
-	b2Vec2 e12 = w2 - w1;
-	float32 w1e12 = b2Dot(w1, e12);
-	float32 w2e12 = b2Dot(w2, e12);
-	float32 d12_1 = w2e12;
-	float32 d12_2 = -w1e12;
-
-	// Edge13
-	// [1      1     ][a1] = [1]
-	// [w1.e13 w3.e13][a3] = [0]
-	// a2 = 0
-	b2Vec2 e13 = w3 - w1;
-	float32 w1e13 = b2Dot(w1, e13);
-	float32 w3e13 = b2Dot(w3, e13);
-	float32 d13_1 = w3e13;
-	float32 d13_2 = -w1e13;
-
-	// Edge23
-	// [1      1     ][a2] = [1]
-	// [w2.e23 w3.e23][a3] = [0]
-	// a1 = 0
-	b2Vec2 e23 = w3 - w2;
-	float32 w2e23 = b2Dot(w2, e23);
-	float32 w3e23 = b2Dot(w3, e23);
-	float32 d23_1 = w3e23;
-	float32 d23_2 = -w2e23;
-	
-	// Triangle123
-	float32 n123 = b2Cross(e12, e13);
-
-	float32 d123_1 = n123 * b2Cross(w2, w3);
-	float32 d123_2 = n123 * b2Cross(w3, w1);
-	float32 d123_3 = n123 * b2Cross(w1, w2);
-
-	// w1 region
-	if (d12_2 <= 0.0f && d13_2 <= 0.0f)
-	{
-		m_v1.a = 1.0f;
-		m_count = 1;
-		return;
-	}
-
-	// e12
-	if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
-	{
-		float32 inv_d12 = 1.0f / (d12_1 + d12_2);
-		m_v1.a = d12_1 * inv_d12;
-		m_v2.a = d12_2 * inv_d12;
-		m_count = 2;
-		return;
-	}
-
-	// e13
-	if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
-	{
-		float32 inv_d13 = 1.0f / (d13_1 + d13_2);
-		m_v1.a = d13_1 * inv_d13;
-		m_v3.a = d13_2 * inv_d13;
-		m_count = 2;
-		m_v2 = m_v3;
-		return;
-	}
-
-	// w2 region
-	if (d12_1 <= 0.0f && d23_2 <= 0.0f)
-	{
-		m_v2.a = 1.0f;
-		m_count = 1;
-		m_v1 = m_v2;
-		return;
-	}
-
-	// w3 region
-	if (d13_1 <= 0.0f && d23_1 <= 0.0f)
-	{
-		m_v3.a = 1.0f;
-		m_count = 1;
-		m_v1 = m_v3;
-		return;
-	}
-
-	// e23
-	if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
-	{
-		float32 inv_d23 = 1.0f / (d23_1 + d23_2);
-		m_v2.a = d23_1 * inv_d23;
-		m_v3.a = d23_2 * inv_d23;
-		m_count = 2;
-		m_v1 = m_v3;
-		return;
-	}
-
-	// Must be in triangle123
-	float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);
-	m_v1.a = d123_1 * inv_d123;
-	m_v2.a = d123_2 * inv_d123;
-	m_v3.a = d123_3 * inv_d123;
-	m_count = 3;
-}
-
-void b2Distance(b2DistanceOutput* output,
-				b2SimplexCache* cache,
-				const b2DistanceInput* input)
-{
-	++b2_gjkCalls;
-
-	const b2DistanceProxy* proxyA = &input->proxyA;
-	const b2DistanceProxy* proxyB = &input->proxyB;
-
-	b2Transform transformA = input->transformA;
-	b2Transform transformB = input->transformB;
-
-	// Initialize the simplex.
-	b2Simplex simplex;
-	simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);
-
-	// Get simplex vertices as an array.
-	b2SimplexVertex* vertices = &simplex.m_v1;
-	const int32 k_maxIters = 20;
-
-	// These store the vertices of the last simplex so that we
-	// can check for duplicates and prevent cycling.
-	int32 saveA[3], saveB[3];
-	int32 saveCount = 0;
-
-	float32 distanceSqr1 = b2_maxFloat;
-	float32 distanceSqr2 = distanceSqr1;
-
-	// Main iteration loop.
-	int32 iter = 0;
-	while (iter < k_maxIters)
-	{
-		// Copy simplex so we can identify duplicates.
-		saveCount = simplex.m_count;
-		for (int32 i = 0; i < saveCount; ++i)
-		{
-			saveA[i] = vertices[i].indexA;
-			saveB[i] = vertices[i].indexB;
-		}
-
-		switch (simplex.m_count)
-		{
-		case 1:
-			break;
-
-		case 2:
-			simplex.Solve2();
-			break;
-
-		case 3:
-			simplex.Solve3();
-			break;
-
-		default:
-			b2Assert(false);
-		}
-
-		// If we have 3 points, then the origin is in the corresponding triangle.
-		if (simplex.m_count == 3)
-		{
-			break;
-		}
-
-		// Compute closest point.
-		b2Vec2 p = simplex.GetClosestPoint();
-		distanceSqr2 = p.LengthSquared();
-
-		// Ensure progress
-		if (distanceSqr2 >= distanceSqr1)
-		{
-			//break;
-		}
-		distanceSqr1 = distanceSqr2;
-
-		// Get search direction.
-		b2Vec2 d = simplex.GetSearchDirection();
-
-		// Ensure the search direction is numerically fit.
-		if (d.LengthSquared() < b2_epsilon * b2_epsilon)
-		{
-			// The origin is probably contained by a line segment
-			// or triangle. Thus the shapes are overlapped.
-
-			// We can't return zero here even though there may be overlap.
-			// In case the simplex is a point, segment, or triangle it is difficult
-			// to determine if the origin is contained in the CSO or very close to it.
-			break;
-		}
-
-		// Compute a tentative new simplex vertex using support points.
-		b2SimplexVertex* vertex = vertices + simplex.m_count;
-		vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d));
-		vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA));
-		b2Vec2 wBLocal;
-		vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d));
-		vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB));
-		vertex->w = vertex->wB - vertex->wA;
-
-		// Iteration count is equated to the number of support point calls.
-		++iter;
-		++b2_gjkIters;
-
-		// Check for duplicate support points. This is the main termination criteria.
-		bool duplicate = false;
-		for (int32 i = 0; i < saveCount; ++i)
-		{
-			if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])
-			{
-				duplicate = true;
-				break;
-			}
-		}
-
-		// If we found a duplicate support point we must exit to avoid cycling.
-		if (duplicate)
-		{
-			break;
-		}
-
-		// New vertex is ok and needed.
-		++simplex.m_count;
-	}
-
-	b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter);
-
-	// Prepare output.
-	simplex.GetWitnessPoints(&output->pointA, &output->pointB);
-	output->distance = b2Distance(output->pointA, output->pointB);
-	output->iterations = iter;
-
-	// Cache the simplex.
-	simplex.WriteCache(cache);
-
-	// Apply radii if requested.
-	if (input->useRadii)
-	{
-		float32 rA = proxyA->m_radius;
-		float32 rB = proxyB->m_radius;
-
-		if (output->distance > rA + rB && output->distance > b2_epsilon)
-		{
-			// Shapes are still no overlapped.
-			// Move the witness points to the outer surface.
-			output->distance -= rA + rB;
-			b2Vec2 normal = output->pointB - output->pointA;
-			normal.Normalize();
-			output->pointA += rA * normal;
-			output->pointB -= rB * normal;
-		}
-		else
-		{
-			// Shapes are overlapped when radii are considered.
-			// Move the witness points to the middle.
-			b2Vec2 p = 0.5f * (output->pointA + output->pointB);
-			output->pointA = p;
-			output->pointB = p;
-			output->distance = 0.0f;
-		}
-	}
-}
+/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#include <string.h>
+#include <memory.h>
+
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2EdgeShape.h>
+#include <Box2D/Collision/Shapes/b2ChainShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+
+// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
+int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
+
+void b2DistanceProxy::Set(const b2Shape* shape, int32 index)
+{
+	switch (shape->GetType())
+	{
+	case b2Shape::e_circle:
+		{
+			const b2CircleShape* circle = static_cast<const b2CircleShape*>(shape);
+			m_vertices = &circle->m_p;
+			m_count = 1;
+			m_radius = circle->m_radius;
+		}
+		break;
+
+	case b2Shape::e_polygon:
+		{
+			const b2PolygonShape* polygon = static_cast<const b2PolygonShape*>(shape);
+			m_vertices = polygon->m_vertices;
+			m_count = polygon->m_count;
+			m_radius = polygon->m_radius;
+		}
+		break;
+
+	case b2Shape::e_chain:
+		{
+			const b2ChainShape* chain = static_cast<const b2ChainShape*>(shape);
+			b2Assert(0 <= index && index < chain->m_count);
+
+			m_buffer[0] = chain->m_vertices[index];
+			if (index + 1 < chain->m_count)
+			{
+				m_buffer[1] = chain->m_vertices[index + 1];
+			}
+			else
+			{
+				m_buffer[1] = chain->m_vertices[0];
+			}
+
+			m_vertices = m_buffer;
+			m_count = 2;
+			m_radius = chain->m_radius;
+		}
+		break;
+
+	case b2Shape::e_edge:
+		{
+			const b2EdgeShape* edge = static_cast<const b2EdgeShape*>(shape);
+			m_vertices = &edge->m_vertex1;
+			m_count = 2;
+			m_radius = edge->m_radius;
+		}
+		break;
+
+	default:
+		b2Assert(false);
+	}
+}
+
+
+struct b2SimplexVertex
+{
+	b2Vec2 wA;		// support point in proxyA
+	b2Vec2 wB;		// support point in proxyB
+	b2Vec2 w;		// wB - wA
+	float32 a;		// barycentric coordinate for closest point
+	int32 indexA;	// wA index
+	int32 indexB;	// wB index
+};
+
+struct b2Simplex
+{
+	void ReadCache(	const b2SimplexCache* cache,
+					const b2DistanceProxy* proxyA, const b2Transform& transformA,
+					const b2DistanceProxy* proxyB, const b2Transform& transformB)
+	{
+		b2Assert(cache->count <= 3);
+		
+		// Copy data from cache.
+		m_count = cache->count;
+		b2SimplexVertex* vertices = &m_v1;
+		for (int32 i = 0; i < m_count; ++i)
+		{
+			b2SimplexVertex* v = vertices + i;
+			v->indexA = cache->indexA[i];
+			v->indexB = cache->indexB[i];
+			b2Vec2 wALocal = proxyA->GetVertex(v->indexA);
+			b2Vec2 wBLocal = proxyB->GetVertex(v->indexB);
+			v->wA = b2Mul(transformA, wALocal);
+			v->wB = b2Mul(transformB, wBLocal);
+			v->w = v->wB - v->wA;
+			v->a = 0.0f;
+		}
+
+		// Compute the new simplex metric, if it is substantially different than
+		// old metric then flush the simplex.
+		if (m_count > 1)
+		{
+			float32 metric1 = cache->metric;
+			float32 metric2 = GetMetric();
+			if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < b2_epsilon)
+			{
+				// Reset the simplex.
+				m_count = 0;
+			}
+		}
+
+		// If the cache is empty or invalid ...
+		if (m_count == 0)
+		{
+			b2SimplexVertex* v = vertices + 0;
+			v->indexA = 0;
+			v->indexB = 0;
+			b2Vec2 wALocal = proxyA->GetVertex(0);
+			b2Vec2 wBLocal = proxyB->GetVertex(0);
+			v->wA = b2Mul(transformA, wALocal);
+			v->wB = b2Mul(transformB, wBLocal);
+			v->w = v->wB - v->wA;
+			v->a = 1.0f;
+			m_count = 1;
+		}
+	}
+
+	void WriteCache(b2SimplexCache* cache) const
+	{
+		cache->metric = GetMetric();
+		cache->count = uint16(m_count);
+		const b2SimplexVertex* vertices = &m_v1;
+		for (int32 i = 0; i < m_count; ++i)
+		{
+			cache->indexA[i] = uint8(vertices[i].indexA);
+			cache->indexB[i] = uint8(vertices[i].indexB);
+		}
+	}
+
+	b2Vec2 GetSearchDirection() const
+	{
+		switch (m_count)
+		{
+		case 1:
+			return -m_v1.w;
+
+		case 2:
+			{
+				b2Vec2 e12 = m_v2.w - m_v1.w;
+				float32 sgn = b2Cross(e12, -m_v1.w);
+				if (sgn > 0.0f)
+				{
+					// Origin is left of e12.
+					return b2Cross(1.0f, e12);
+				}
+				else
+				{
+					// Origin is right of e12.
+					return b2Cross(e12, 1.0f);
+				}
+			}
+
+		default:
+			b2Assert(false);
+			return b2Vec2_zero;
+		}
+	}
+
+	b2Vec2 GetClosestPoint() const
+	{
+		switch (m_count)
+		{
+		case 0:
+			b2Assert(false);
+			return b2Vec2_zero;
+
+		case 1:
+			return m_v1.w;
+
+		case 2:
+			return m_v1.a * m_v1.w + m_v2.a * m_v2.w;
+
+		case 3:
+			return b2Vec2_zero;
+
+		default:
+			b2Assert(false);
+			return b2Vec2_zero;
+		}
+	}
+
+	void GetWitnessPoints(b2Vec2* pA, b2Vec2* pB) const
+	{
+		switch (m_count)
+		{
+		case 0:
+			b2Assert(false);
+			break;
+
+		case 1:
+			*pA = m_v1.wA;
+			*pB = m_v1.wB;
+			break;
+
+		case 2:
+			*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA;
+			*pB = m_v1.a * m_v1.wB + m_v2.a * m_v2.wB;
+			break;
+
+		case 3:
+			*pA = m_v1.a * m_v1.wA + m_v2.a * m_v2.wA + m_v3.a * m_v3.wA;
+			*pB = *pA;
+			break;
+
+		default:
+			b2Assert(false);
+			break;
+		}
+	}
+
+	float32 GetMetric() const
+	{
+		switch (m_count)
+		{
+		case 0:
+			b2Assert(false);
+			return 0.0f;
+
+		case 1:
+			return 0.0f;
+
+		case 2:
+			return b2Distance(m_v1.w, m_v2.w);
+
+		case 3:
+			return b2Cross(m_v2.w - m_v1.w, m_v3.w - m_v1.w);
+
+		default:
+			b2Assert(false);
+			return 0.0f;
+		}
+	}
+
+	void Solve2();
+	void Solve3();
+
+	b2SimplexVertex m_v1, m_v2, m_v3;
+	int32 m_count;
+};
+
+
+// Solve a line segment using barycentric coordinates.
+//
+// p = a1 * w1 + a2 * w2
+// a1 + a2 = 1
+//
+// The vector from the origin to the closest point on the line is
+// perpendicular to the line.
+// e12 = w2 - w1
+// dot(p, e) = 0
+// a1 * dot(w1, e) + a2 * dot(w2, e) = 0
+//
+// 2-by-2 linear system
+// [1      1     ][a1] = [1]
+// [w1.e12 w2.e12][a2] = [0]
+//
+// Define
+// d12_1 =  dot(w2, e12)
+// d12_2 = -dot(w1, e12)
+// d12 = d12_1 + d12_2
+//
+// Solution
+// a1 = d12_1 / d12
+// a2 = d12_2 / d12
+void b2Simplex::Solve2()
+{
+	b2Vec2 w1 = m_v1.w;
+	b2Vec2 w2 = m_v2.w;
+	b2Vec2 e12 = w2 - w1;
+
+	// w1 region
+	float32 d12_2 = -b2Dot(w1, e12);
+	if (d12_2 <= 0.0f)
+	{
+		// a2 <= 0, so we clamp it to 0
+		m_v1.a = 1.0f;
+		m_count = 1;
+		return;
+	}
+
+	// w2 region
+	float32 d12_1 = b2Dot(w2, e12);
+	if (d12_1 <= 0.0f)
+	{
+		// a1 <= 0, so we clamp it to 0
+		m_v2.a = 1.0f;
+		m_count = 1;
+		m_v1 = m_v2;
+		return;
+	}
+
+	// Must be in e12 region.
+	float32 inv_d12 = 1.0f / (d12_1 + d12_2);
+	m_v1.a = d12_1 * inv_d12;
+	m_v2.a = d12_2 * inv_d12;
+	m_count = 2;
+}
+
+// Possible regions:
+// - points[2]
+// - edge points[0]-points[2]
+// - edge points[1]-points[2]
+// - inside the triangle
+void b2Simplex::Solve3()
+{
+	b2Vec2 w1 = m_v1.w;
+	b2Vec2 w2 = m_v2.w;
+	b2Vec2 w3 = m_v3.w;
+
+	// Edge12
+	// [1      1     ][a1] = [1]
+	// [w1.e12 w2.e12][a2] = [0]
+	// a3 = 0
+	b2Vec2 e12 = w2 - w1;
+	float32 w1e12 = b2Dot(w1, e12);
+	float32 w2e12 = b2Dot(w2, e12);
+	float32 d12_1 = w2e12;
+	float32 d12_2 = -w1e12;
+
+	// Edge13
+	// [1      1     ][a1] = [1]
+	// [w1.e13 w3.e13][a3] = [0]
+	// a2 = 0
+	b2Vec2 e13 = w3 - w1;
+	float32 w1e13 = b2Dot(w1, e13);
+	float32 w3e13 = b2Dot(w3, e13);
+	float32 d13_1 = w3e13;
+	float32 d13_2 = -w1e13;
+
+	// Edge23
+	// [1      1     ][a2] = [1]
+	// [w2.e23 w3.e23][a3] = [0]
+	// a1 = 0
+	b2Vec2 e23 = w3 - w2;
+	float32 w2e23 = b2Dot(w2, e23);
+	float32 w3e23 = b2Dot(w3, e23);
+	float32 d23_1 = w3e23;
+	float32 d23_2 = -w2e23;
+	
+	// Triangle123
+	float32 n123 = b2Cross(e12, e13);
+
+	float32 d123_1 = n123 * b2Cross(w2, w3);
+	float32 d123_2 = n123 * b2Cross(w3, w1);
+	float32 d123_3 = n123 * b2Cross(w1, w2);
+
+	// w1 region
+	if (d12_2 <= 0.0f && d13_2 <= 0.0f)
+	{
+		m_v1.a = 1.0f;
+		m_count = 1;
+		return;
+	}
+
+	// e12
+	if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
+	{
+		float32 inv_d12 = 1.0f / (d12_1 + d12_2);
+		m_v1.a = d12_1 * inv_d12;
+		m_v2.a = d12_2 * inv_d12;
+		m_count = 2;
+		return;
+	}
+
+	// e13
+	if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
+	{
+		float32 inv_d13 = 1.0f / (d13_1 + d13_2);
+		m_v1.a = d13_1 * inv_d13;
+		m_v3.a = d13_2 * inv_d13;
+		m_count = 2;
+		m_v2 = m_v3;
+		return;
+	}
+
+	// w2 region
+	if (d12_1 <= 0.0f && d23_2 <= 0.0f)
+	{
+		m_v2.a = 1.0f;
+		m_count = 1;
+		m_v1 = m_v2;
+		return;
+	}
+
+	// w3 region
+	if (d13_1 <= 0.0f && d23_1 <= 0.0f)
+	{
+		m_v3.a = 1.0f;
+		m_count = 1;
+		m_v1 = m_v3;
+		return;
+	}
+
+	// e23
+	if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
+	{
+		float32 inv_d23 = 1.0f / (d23_1 + d23_2);
+		m_v2.a = d23_1 * inv_d23;
+		m_v3.a = d23_2 * inv_d23;
+		m_count = 2;
+		m_v1 = m_v3;
+		return;
+	}
+
+	// Must be in triangle123
+	float32 inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);
+	m_v1.a = d123_1 * inv_d123;
+	m_v2.a = d123_2 * inv_d123;
+	m_v3.a = d123_3 * inv_d123;
+	m_count = 3;
+}
+
+void b2Distance(b2DistanceOutput* output,
+				b2SimplexCache* cache,
+				const b2DistanceInput* input)
+{
+	++b2_gjkCalls;
+
+	const b2DistanceProxy* proxyA = &input->proxyA;
+	const b2DistanceProxy* proxyB = &input->proxyB;
+
+	b2Transform transformA = input->transformA;
+	b2Transform transformB = input->transformB;
+
+	// Initialize the simplex.
+	b2Simplex simplex;
+	simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);
+
+	// Get simplex vertices as an array.
+	b2SimplexVertex* vertices = &simplex.m_v1;
+	const int32 k_maxIters = 20;
+
+	// These store the vertices of the last simplex so that we
+	// can check for duplicates and prevent cycling.
+	int32 saveA[3], saveB[3];
+	int32 saveCount = 0;
+
+	// Work around spurious gcc-4.8.2 warnings when -Wmaybe-uninitialized is
+	// enabled by initializing saveA / saveB arrays when they're referenced
+	// at the end of the main iteration loop below even though saveCount
+	// entries of each array are initialized at the start of the main
+	// iteration loop.
+	memset(saveA, 0, sizeof(saveA));
+	memset(saveB, 0, sizeof(saveB));
+
+	float32 distanceSqr1 = b2_maxFloat;
+	float32 distanceSqr2;
+
+	// Main iteration loop.
+	int32 iter = 0;
+	while (iter < k_maxIters)
+	{
+		// Copy simplex so we can identify duplicates.
+		saveCount = simplex.m_count;
+		for (int32 i = 0; i < saveCount; ++i)
+		{
+			saveA[i] = vertices[i].indexA;
+			saveB[i] = vertices[i].indexB;
+		}
+
+		switch (simplex.m_count)
+		{
+		case 1:
+			break;
+
+		case 2:
+			simplex.Solve2();
+			break;
+
+		case 3:
+			simplex.Solve3();
+			break;
+
+		default:
+			b2Assert(false);
+		}
+
+		// If we have 3 points, then the origin is in the corresponding triangle.
+		if (simplex.m_count == 3)
+		{
+			break;
+		}
+
+		// Compute closest point.
+		b2Vec2 p = simplex.GetClosestPoint();
+		distanceSqr2 = p.LengthSquared();
+
+		// Ensure progress
+		if (distanceSqr2 >= distanceSqr1)
+		{
+			//break;
+		}
+		distanceSqr1 = distanceSqr2;
+
+		// Get search direction.
+		b2Vec2 d = simplex.GetSearchDirection();
+
+		// Ensure the search direction is numerically fit.
+		if (d.LengthSquared() < b2_epsilon * b2_epsilon)
+		{
+			// The origin is probably contained by a line segment
+			// or triangle. Thus the shapes are overlapped.
+
+			// We can't return zero here even though there may be overlap.
+			// In case the simplex is a point, segment, or triangle it is difficult
+			// to determine if the origin is contained in the CSO or very close to it.
+			break;
+		}
+
+		// Compute a tentative new simplex vertex using support points.
+		b2SimplexVertex* vertex = vertices + simplex.m_count;
+		vertex->indexA = proxyA->GetSupport(b2MulT(transformA.q, -d));
+		vertex->wA = b2Mul(transformA, proxyA->GetVertex(vertex->indexA));
+		b2Vec2 wBLocal;
+		vertex->indexB = proxyB->GetSupport(b2MulT(transformB.q, d));
+		vertex->wB = b2Mul(transformB, proxyB->GetVertex(vertex->indexB));
+		vertex->w = vertex->wB - vertex->wA;
+
+		// Iteration count is equated to the number of support point calls.
+		++iter;
+		++b2_gjkIters;
+
+		// Check for duplicate support points. This is the main termination criteria.
+		bool duplicate = false;
+		for (int32 i = 0; i < saveCount; ++i)
+		{
+			if (vertex->indexA == saveA[i] && vertex->indexB == saveB[i])
+			{
+				duplicate = true;
+				break;
+			}
+		}
+
+		// If we found a duplicate support point we must exit to avoid cycling.
+		if (duplicate)
+		{
+			break;
+		}
+
+		// New vertex is ok and needed.
+		++simplex.m_count;
+	}
+
+	b2_gjkMaxIters = b2Max(b2_gjkMaxIters, iter);
+
+	// Prepare output.
+	simplex.GetWitnessPoints(&output->pointA, &output->pointB);
+	output->distance = b2Distance(output->pointA, output->pointB);
+	output->iterations = iter;
+
+	// Cache the simplex.
+	simplex.WriteCache(cache);
+
+	// Apply radii if requested.
+	if (input->useRadii)
+	{
+		float32 rA = proxyA->m_radius;
+		float32 rB = proxyB->m_radius;
+
+		if (output->distance > rA + rB && output->distance > b2_epsilon)
+		{
+			// Shapes are still no overlapped.
+			// Move the witness points to the outer surface.
+			output->distance -= rA + rB;
+			b2Vec2 normal = output->pointB - output->pointA;
+			normal.Normalize();
+			output->pointA += rA * normal;
+			output->pointB -= rB * normal;
+		}
+		else
+		{
+			// Shapes are overlapped when radii are considered.
+			// Move the witness points to the middle.
+			b2Vec2 p = 0.5f * (output->pointA + output->pointB);
+			output->pointA = p;
+			output->pointB = p;
+			output->distance = 0.0f;
+		}
+	}
+}

+ 141 - 141
engine/source/Box2D/Collision/b2Distance.h

@@ -1,141 +1,141 @@
-
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_DISTANCE_H
-#define B2_DISTANCE_H
-
-#include <Box2D/Common/b2Math.h>
-
-class b2Shape;
-
-/// A distance proxy is used by the GJK algorithm.
-/// It encapsulates any shape.
-struct b2DistanceProxy
-{
-	b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
-
-	/// Initialize the proxy using the given shape. The shape
-	/// must remain in scope while the proxy is in use.
-	void Set(const b2Shape* shape, int32 index);
-
-	/// Get the supporting vertex index in the given direction.
-	int32 GetSupport(const b2Vec2& d) const;
-
-	/// Get the supporting vertex in the given direction.
-	const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
-
-	/// Get the vertex count.
-	int32 GetVertexCount() const;
-
-	/// Get a vertex by index. Used by b2Distance.
-	const b2Vec2& GetVertex(int32 index) const;
-
-	b2Vec2 m_buffer[2];
-	const b2Vec2* m_vertices;
-	int32 m_count;
-	float32 m_radius;
-};
-
-/// Used to warm start b2Distance.
-/// Set count to zero on first call.
-struct b2SimplexCache
-{
-	float32 metric;		///< length or area
-	uint16 count;
-	uint8 indexA[3];	///< vertices on shape A
-	uint8 indexB[3];	///< vertices on shape B
-};
-
-/// Input for b2Distance.
-/// You have to option to use the shape radii
-/// in the computation. Even 
-struct b2DistanceInput
-{
-	b2DistanceProxy proxyA;
-	b2DistanceProxy proxyB;
-	b2Transform transformA;
-	b2Transform transformB;
-	bool useRadii;
-};
-
-/// Output for b2Distance.
-struct b2DistanceOutput
-{
-	b2Vec2 pointA;		///< closest point on shapeA
-	b2Vec2 pointB;		///< closest point on shapeB
-	float32 distance;
-	int32 iterations;	///< number of GJK iterations used
-};
-
-/// Compute the closest points between two shapes. Supports any combination of:
-/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
-/// On the first call set b2SimplexCache.count to zero.
-void b2Distance(b2DistanceOutput* output,
-				b2SimplexCache* cache, 
-				const b2DistanceInput* input);
-
-
-//////////////////////////////////////////////////////////////////////////
-
-inline int32 b2DistanceProxy::GetVertexCount() const
-{
-	return m_count;
-}
-
-inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
-{
-	b2Assert(0 <= index && index < m_count);
-	return m_vertices[index];
-}
-
-inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
-{
-	int32 bestIndex = 0;
-	float32 bestValue = b2Dot(m_vertices[0], d);
-	for (int32 i = 1; i < m_count; ++i)
-	{
-		float32 value = b2Dot(m_vertices[i], d);
-		if (value > bestValue)
-		{
-			bestIndex = i;
-			bestValue = value;
-		}
-	}
-
-	return bestIndex;
-}
-
-inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
-{
-	int32 bestIndex = 0;
-	float32 bestValue = b2Dot(m_vertices[0], d);
-	for (int32 i = 1; i < m_count; ++i)
-	{
-		float32 value = b2Dot(m_vertices[i], d);
-		if (value > bestValue)
-		{
-			bestIndex = i;
-			bestValue = value;
-		}
-	}
-
-	return m_vertices[bestIndex];
-}
-
-#endif
+
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DISTANCE_H
+#define B2_DISTANCE_H
+
+#include <Box2D/Common/b2Math.h>
+
+class b2Shape;
+
+/// A distance proxy is used by the GJK algorithm.
+/// It encapsulates any shape.
+struct b2DistanceProxy
+{
+	b2DistanceProxy() : m_vertices(NULL), m_count(0), m_radius(0.0f) {}
+
+	/// Initialize the proxy using the given shape. The shape
+	/// must remain in scope while the proxy is in use.
+	void Set(const b2Shape* shape, int32 index);
+
+	/// Get the supporting vertex index in the given direction.
+	int32 GetSupport(const b2Vec2& d) const;
+
+	/// Get the supporting vertex in the given direction.
+	const b2Vec2& GetSupportVertex(const b2Vec2& d) const;
+
+	/// Get the vertex count.
+	int32 GetVertexCount() const;
+
+	/// Get a vertex by index. Used by b2Distance.
+	const b2Vec2& GetVertex(int32 index) const;
+
+	b2Vec2 m_buffer[2];
+	const b2Vec2* m_vertices;
+	int32 m_count;
+	float32 m_radius;
+};
+
+/// Used to warm start b2Distance.
+/// Set count to zero on first call.
+struct b2SimplexCache
+{
+	float32 metric;		///< length or area
+	uint16 count;
+	uint8 indexA[3];	///< vertices on shape A
+	uint8 indexB[3];	///< vertices on shape B
+};
+
+/// Input for b2Distance.
+/// You have to option to use the shape radii
+/// in the computation. Even 
+struct b2DistanceInput
+{
+	b2DistanceProxy proxyA;
+	b2DistanceProxy proxyB;
+	b2Transform transformA;
+	b2Transform transformB;
+	bool useRadii;
+};
+
+/// Output for b2Distance.
+struct b2DistanceOutput
+{
+	b2Vec2 pointA;		///< closest point on shapeA
+	b2Vec2 pointB;		///< closest point on shapeB
+	float32 distance;
+	int32 iterations;	///< number of GJK iterations used
+};
+
+/// Compute the closest points between two shapes. Supports any combination of:
+/// b2CircleShape, b2PolygonShape, b2EdgeShape. The simplex cache is input/output.
+/// On the first call set b2SimplexCache.count to zero.
+void b2Distance(b2DistanceOutput* output,
+				b2SimplexCache* cache, 
+				const b2DistanceInput* input);
+
+
+//////////////////////////////////////////////////////////////////////////
+
+inline int32 b2DistanceProxy::GetVertexCount() const
+{
+	return m_count;
+}
+
+inline const b2Vec2& b2DistanceProxy::GetVertex(int32 index) const
+{
+	b2Assert(0 <= index && index < m_count);
+	return m_vertices[index];
+}
+
+inline int32 b2DistanceProxy::GetSupport(const b2Vec2& d) const
+{
+	int32 bestIndex = 0;
+	float32 bestValue = b2Dot(m_vertices[0], d);
+	for (int32 i = 1; i < m_count; ++i)
+	{
+		float32 value = b2Dot(m_vertices[i], d);
+		if (value > bestValue)
+		{
+			bestIndex = i;
+			bestValue = value;
+		}
+	}
+
+	return bestIndex;
+}
+
+inline const b2Vec2& b2DistanceProxy::GetSupportVertex(const b2Vec2& d) const
+{
+	int32 bestIndex = 0;
+	float32 bestValue = b2Dot(m_vertices[0], d);
+	for (int32 i = 1; i < m_count; ++i)
+	{
+		float32 value = b2Dot(m_vertices[i], d);
+		if (value > bestValue)
+		{
+			bestIndex = i;
+			bestValue = value;
+		}
+	}
+
+	return m_vertices[bestIndex];
+}
+
+#endif

+ 784 - 781
engine/source/Box2D/Collision/b2DynamicTree.cpp

@@ -1,781 +1,784 @@
-/*
-* Copyright (c) 2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2DynamicTree.h>
-#include <cstring>
-#include <cfloat>
-using namespace std;
-
-
-b2DynamicTree::b2DynamicTree()
-{
-	m_root = b2_nullNode;
-
-	m_nodeCapacity = 16;
-	m_nodeCount = 0;
-	m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
-	memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode));
-
-	// Build a linked list for the free list.
-	for (int32 i = 0; i < m_nodeCapacity - 1; ++i)
-	{
-		m_nodes[i].next = i + 1;
-		m_nodes[i].height = -1;
-	}
-	m_nodes[m_nodeCapacity-1].next = b2_nullNode;
-	m_nodes[m_nodeCapacity-1].height = -1;
-	m_freeList = 0;
-
-	m_path = 0;
-
-	m_insertionCount = 0;
-}
-
-b2DynamicTree::~b2DynamicTree()
-{
-	// This frees the entire tree in one shot.
-	b2Free(m_nodes);
-}
-
-// Allocate a node from the pool. Grow the pool if necessary.
-int32 b2DynamicTree::AllocateNode()
-{
-	// Expand the node pool as needed.
-	if (m_freeList == b2_nullNode)
-	{
-		b2Assert(m_nodeCount == m_nodeCapacity);
-
-		// The free list is empty. Rebuild a bigger pool.
-		b2TreeNode* oldNodes = m_nodes;
-		m_nodeCapacity *= 2;
-		m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
-		memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode));
-		b2Free(oldNodes);
-
-		// Build a linked list for the free list. The parent
-		// pointer becomes the "next" pointer.
-		for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
-		{
-			m_nodes[i].next = i + 1;
-			m_nodes[i].height = -1;
-		}
-		m_nodes[m_nodeCapacity-1].next = b2_nullNode;
-		m_nodes[m_nodeCapacity-1].height = -1;
-		m_freeList = m_nodeCount;
-	}
-
-	// Peel a node off the free list.
-	int32 nodeId = m_freeList;
-	m_freeList = m_nodes[nodeId].next;
-	m_nodes[nodeId].parent = b2_nullNode;
-	m_nodes[nodeId].child1 = b2_nullNode;
-	m_nodes[nodeId].child2 = b2_nullNode;
-	m_nodes[nodeId].height = 0;
-	m_nodes[nodeId].userData = NULL;
-	++m_nodeCount;
-	return nodeId;
-}
-
-// Return a node to the pool.
-void b2DynamicTree::FreeNode(int32 nodeId)
-{
-	b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
-	b2Assert(0 < m_nodeCount);
-	m_nodes[nodeId].next = m_freeList;
-	m_nodes[nodeId].height = -1;
-	m_freeList = nodeId;
-	--m_nodeCount;
-}
-
-// Create a proxy in the tree as a leaf node. We return the index
-// of the node instead of a pointer so that we can grow
-// the node pool.
-int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)
-{
-	int32 proxyId = AllocateNode();
-
-	// Fatten the aabb.
-	b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
-	m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;
-	m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;
-	m_nodes[proxyId].userData = userData;
-	m_nodes[proxyId].height = 0;
-
-	InsertLeaf(proxyId);
-
-	return proxyId;
-}
-
-void b2DynamicTree::DestroyProxy(int32 proxyId)
-{
-	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
-	b2Assert(m_nodes[proxyId].IsLeaf());
-
-	RemoveLeaf(proxyId);
-	FreeNode(proxyId);
-}
-
-bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
-{
-	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
-
-	b2Assert(m_nodes[proxyId].IsLeaf());
-
-	if (m_nodes[proxyId].aabb.Contains(aabb))
-	{
-		return false;
-	}
-
-	RemoveLeaf(proxyId);
-
-	// Extend AABB.
-	b2AABB b = aabb;
-	b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
-	b.lowerBound = b.lowerBound - r;
-	b.upperBound = b.upperBound + r;
-
-	// Predict AABB displacement.
-	b2Vec2 d = b2_aabbMultiplier * displacement;
-
-	if (d.x < 0.0f)
-	{
-		b.lowerBound.x += d.x;
-	}
-	else
-	{
-		b.upperBound.x += d.x;
-	}
-
-	if (d.y < 0.0f)
-	{
-		b.lowerBound.y += d.y;
-	}
-	else
-	{
-		b.upperBound.y += d.y;
-	}
-
-	m_nodes[proxyId].aabb = b;
-
-	InsertLeaf(proxyId);
-	return true;
-}
-
-void b2DynamicTree::InsertLeaf(int32 leaf)
-{
-	++m_insertionCount;
-
-	if (m_root == b2_nullNode)
-	{
-		m_root = leaf;
-		m_nodes[m_root].parent = b2_nullNode;
-		return;
-	}
-
-	// Find the best sibling for this node
-	b2AABB leafAABB = m_nodes[leaf].aabb;
-	int32 index = m_root;
-	while (m_nodes[index].IsLeaf() == false)
-	{
-		int32 child1 = m_nodes[index].child1;
-		int32 child2 = m_nodes[index].child2;
-
-		float32 area = m_nodes[index].aabb.GetPerimeter();
-
-		b2AABB combinedAABB;
-		combinedAABB.Combine(m_nodes[index].aabb, leafAABB);
-		float32 combinedArea = combinedAABB.GetPerimeter();
-
-		// Cost of creating a new parent for this node and the new leaf
-		float32 cost = 2.0f * combinedArea;
-
-		// Minimum cost of pushing the leaf further down the tree
-		float32 inheritanceCost = 2.0f * (combinedArea - area);
-
-		// Cost of descending into child1
-		float32 cost1;
-		if (m_nodes[child1].IsLeaf())
-		{
-			b2AABB aabb;
-			aabb.Combine(leafAABB, m_nodes[child1].aabb);
-			cost1 = aabb.GetPerimeter() + inheritanceCost;
-		}
-		else
-		{
-			b2AABB aabb;
-			aabb.Combine(leafAABB, m_nodes[child1].aabb);
-			float32 oldArea = m_nodes[child1].aabb.GetPerimeter();
-			float32 newArea = aabb.GetPerimeter();
-			cost1 = (newArea - oldArea) + inheritanceCost;
-		}
-
-		// Cost of descending into child2
-		float32 cost2;
-		if (m_nodes[child2].IsLeaf())
-		{
-			b2AABB aabb;
-			aabb.Combine(leafAABB, m_nodes[child2].aabb);
-			cost2 = aabb.GetPerimeter() + inheritanceCost;
-		}
-		else
-		{
-			b2AABB aabb;
-			aabb.Combine(leafAABB, m_nodes[child2].aabb);
-			float32 oldArea = m_nodes[child2].aabb.GetPerimeter();
-			float32 newArea = aabb.GetPerimeter();
-			cost2 = newArea - oldArea + inheritanceCost;
-		}
-
-		// Descend according to the minimum cost.
-		if (cost < cost1 && cost < cost2)
-		{
-			break;
-		}
-
-		// Descend
-		if (cost1 < cost2)
-		{
-			index = child1;
-		}
-		else
-		{
-			index = child2;
-		}
-	}
-
-	int32 sibling = index;
-
-	// Create a new parent.
-	int32 oldParent = m_nodes[sibling].parent;
-	int32 newParent = AllocateNode();
-	m_nodes[newParent].parent = oldParent;
-	m_nodes[newParent].userData = NULL;
-	m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb);
-	m_nodes[newParent].height = m_nodes[sibling].height + 1;
-
-	if (oldParent != b2_nullNode)
-	{
-		// The sibling was not the root.
-		if (m_nodes[oldParent].child1 == sibling)
-		{
-			m_nodes[oldParent].child1 = newParent;
-		}
-		else
-		{
-			m_nodes[oldParent].child2 = newParent;
-		}
-
-		m_nodes[newParent].child1 = sibling;
-		m_nodes[newParent].child2 = leaf;
-		m_nodes[sibling].parent = newParent;
-		m_nodes[leaf].parent = newParent;
-	}
-	else
-	{
-		// The sibling was the root.
-		m_nodes[newParent].child1 = sibling;
-		m_nodes[newParent].child2 = leaf;
-		m_nodes[sibling].parent = newParent;
-		m_nodes[leaf].parent = newParent;
-		m_root = newParent;
-	}
-
-	// Walk back up the tree fixing heights and AABBs
-	index = m_nodes[leaf].parent;
-	while (index != b2_nullNode)
-	{
-		index = Balance(index);
-
-		int32 child1 = m_nodes[index].child1;
-		int32 child2 = m_nodes[index].child2;
-
-		b2Assert(child1 != b2_nullNode);
-		b2Assert(child2 != b2_nullNode);
-
-		m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
-		m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
-
-		index = m_nodes[index].parent;
-	}
-
-	//Validate();
-}
-
-void b2DynamicTree::RemoveLeaf(int32 leaf)
-{
-	if (leaf == m_root)
-	{
-		m_root = b2_nullNode;
-		return;
-	}
-
-	int32 parent = m_nodes[leaf].parent;
-	int32 grandParent = m_nodes[parent].parent;
-	int32 sibling;
-	if (m_nodes[parent].child1 == leaf)
-	{
-		sibling = m_nodes[parent].child2;
-	}
-	else
-	{
-		sibling = m_nodes[parent].child1;
-	}
-
-	if (grandParent != b2_nullNode)
-	{
-		// Destroy parent and connect sibling to grandParent.
-		if (m_nodes[grandParent].child1 == parent)
-		{
-			m_nodes[grandParent].child1 = sibling;
-		}
-		else
-		{
-			m_nodes[grandParent].child2 = sibling;
-		}
-		m_nodes[sibling].parent = grandParent;
-		FreeNode(parent);
-
-		// Adjust ancestor bounds.
-		int32 index = grandParent;
-		while (index != b2_nullNode)
-		{
-			index = Balance(index);
-
-			int32 child1 = m_nodes[index].child1;
-			int32 child2 = m_nodes[index].child2;
-
-			m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
-			m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
-
-			index = m_nodes[index].parent;
-		}
-	}
-	else
-	{
-		m_root = sibling;
-		m_nodes[sibling].parent = b2_nullNode;
-		FreeNode(parent);
-	}
-
-	//Validate();
-}
-
-// Perform a left or right rotation if node A is imbalanced.
-// Returns the new root index.
-int32 b2DynamicTree::Balance(int32 iA)
-{
-	b2Assert(iA != b2_nullNode);
-
-	b2TreeNode* A = m_nodes + iA;
-	if (A->IsLeaf() || A->height < 2)
-	{
-		return iA;
-	}
-
-	int32 iB = A->child1;
-	int32 iC = A->child2;
-	b2Assert(0 <= iB && iB < m_nodeCapacity);
-	b2Assert(0 <= iC && iC < m_nodeCapacity);
-
-	b2TreeNode* B = m_nodes + iB;
-	b2TreeNode* C = m_nodes + iC;
-
-	int32 balance = C->height - B->height;
-
-	// Rotate C up
-	if (balance > 1)
-	{
-		int32 iF = C->child1;
-		int32 iG = C->child2;
-		b2TreeNode* F = m_nodes + iF;
-		b2TreeNode* G = m_nodes + iG;
-		b2Assert(0 <= iF && iF < m_nodeCapacity);
-		b2Assert(0 <= iG && iG < m_nodeCapacity);
-
-		// Swap A and C
-		C->child1 = iA;
-		C->parent = A->parent;
-		A->parent = iC;
-
-		// A's old parent should point to C
-		if (C->parent != b2_nullNode)
-		{
-			if (m_nodes[C->parent].child1 == iA)
-			{
-				m_nodes[C->parent].child1 = iC;
-			}
-			else
-			{
-				b2Assert(m_nodes[C->parent].child2 == iA);
-				m_nodes[C->parent].child2 = iC;
-			}
-		}
-		else
-		{
-			m_root = iC;
-		}
-
-		// Rotate
-		if (F->height > G->height)
-		{
-			C->child2 = iF;
-			A->child2 = iG;
-			G->parent = iA;
-			A->aabb.Combine(B->aabb, G->aabb);
-			C->aabb.Combine(A->aabb, F->aabb);
-
-			A->height = 1 + b2Max(B->height, G->height);
-			C->height = 1 + b2Max(A->height, F->height);
-		}
-		else
-		{
-			C->child2 = iG;
-			A->child2 = iF;
-			F->parent = iA;
-			A->aabb.Combine(B->aabb, F->aabb);
-			C->aabb.Combine(A->aabb, G->aabb);
-
-			A->height = 1 + b2Max(B->height, F->height);
-			C->height = 1 + b2Max(A->height, G->height);
-		}
-
-		return iC;
-	}
-	
-	// Rotate B up
-	if (balance < -1)
-	{
-		int32 iD = B->child1;
-		int32 iE = B->child2;
-		b2TreeNode* D = m_nodes + iD;
-		b2TreeNode* E = m_nodes + iE;
-		b2Assert(0 <= iD && iD < m_nodeCapacity);
-		b2Assert(0 <= iE && iE < m_nodeCapacity);
-
-		// Swap A and B
-		B->child1 = iA;
-		B->parent = A->parent;
-		A->parent = iB;
-
-		// A's old parent should point to B
-		if (B->parent != b2_nullNode)
-		{
-			if (m_nodes[B->parent].child1 == iA)
-			{
-				m_nodes[B->parent].child1 = iB;
-			}
-			else
-			{
-				b2Assert(m_nodes[B->parent].child2 == iA);
-				m_nodes[B->parent].child2 = iB;
-			}
-		}
-		else
-		{
-			m_root = iB;
-		}
-
-		// Rotate
-		if (D->height > E->height)
-		{
-			B->child2 = iD;
-			A->child1 = iE;
-			E->parent = iA;
-			A->aabb.Combine(C->aabb, E->aabb);
-			B->aabb.Combine(A->aabb, D->aabb);
-
-			A->height = 1 + b2Max(C->height, E->height);
-			B->height = 1 + b2Max(A->height, D->height);
-		}
-		else
-		{
-			B->child2 = iE;
-			A->child1 = iD;
-			D->parent = iA;
-			A->aabb.Combine(C->aabb, D->aabb);
-			B->aabb.Combine(A->aabb, E->aabb);
-
-			A->height = 1 + b2Max(C->height, D->height);
-			B->height = 1 + b2Max(A->height, E->height);
-		}
-
-		return iB;
-	}
-
-	return iA;
-}
-
-int32 b2DynamicTree::GetHeight() const
-{
-	if (m_root == b2_nullNode)
-	{
-		return 0;
-	}
-
-	return m_nodes[m_root].height;
-}
-
-//
-float32 b2DynamicTree::GetAreaRatio() const
-{
-	if (m_root == b2_nullNode)
-	{
-		return 0.0f;
-	}
-
-	const b2TreeNode* root = m_nodes + m_root;
-	float32 rootArea = root->aabb.GetPerimeter();
-
-	float32 totalArea = 0.0f;
-	for (int32 i = 0; i < m_nodeCapacity; ++i)
-	{
-		const b2TreeNode* node = m_nodes + i;
-		if (node->height < 0)
-		{
-			// Free node in pool
-			continue;
-		}
-
-		totalArea += node->aabb.GetPerimeter();
-	}
-
-	return totalArea / rootArea;
-}
-
-// Compute the height of a sub-tree.
-int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
-{
-	b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
-	b2TreeNode* node = m_nodes + nodeId;
-
-	if (node->IsLeaf())
-	{
-		return 0;
-	}
-
-	int32 height1 = ComputeHeight(node->child1);
-	int32 height2 = ComputeHeight(node->child2);
-	return 1 + b2Max(height1, height2);
-}
-
-int32 b2DynamicTree::ComputeHeight() const
-{
-	int32 height = ComputeHeight(m_root);
-	return height;
-}
-
-void b2DynamicTree::ValidateStructure(int32 index) const
-{
-	if (index == b2_nullNode)
-	{
-		return;
-	}
-
-	if (index == m_root)
-	{
-		b2Assert(m_nodes[index].parent == b2_nullNode);
-	}
-
-	const b2TreeNode* node = m_nodes + index;
-
-	int32 child1 = node->child1;
-	int32 child2 = node->child2;
-
-	if (node->IsLeaf())
-	{
-		b2Assert(child1 == b2_nullNode);
-		b2Assert(child2 == b2_nullNode);
-		b2Assert(node->height == 0);
-		return;
-	}
-
-	b2Assert(0 <= child1 && child1 < m_nodeCapacity);
-	b2Assert(0 <= child2 && child2 < m_nodeCapacity);
-
-	b2Assert(m_nodes[child1].parent == index);
-	b2Assert(m_nodes[child2].parent == index);
-
-	ValidateStructure(child1);
-	ValidateStructure(child2);
-}
-
-void b2DynamicTree::ValidateMetrics(int32 index) const
-{
-	if (index == b2_nullNode)
-	{
-		return;
-	}
-
-	const b2TreeNode* node = m_nodes + index;
-
-	int32 child1 = node->child1;
-	int32 child2 = node->child2;
-
-	if (node->IsLeaf())
-	{
-		b2Assert(child1 == b2_nullNode);
-		b2Assert(child2 == b2_nullNode);
-		b2Assert(node->height == 0);
-		return;
-	}
-
-	b2Assert(0 <= child1 && child1 < m_nodeCapacity);
-	b2Assert(0 <= child2 && child2 < m_nodeCapacity);
-
-	int32 height1 = m_nodes[child1].height;
-	int32 height2 = m_nodes[child2].height;
-	int32 height;
-	height = 1 + b2Max(height1, height2);
-	b2Assert(node->height == height);
-
-	b2AABB aabb;
-	aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
-
-	b2Assert(aabb.lowerBound == node->aabb.lowerBound);
-	b2Assert(aabb.upperBound == node->aabb.upperBound);
-
-	ValidateMetrics(child1);
-	ValidateMetrics(child2);
-}
-
-void b2DynamicTree::Validate() const
-{
-	ValidateStructure(m_root);
-	ValidateMetrics(m_root);
-
-	int32 freeCount = 0;
-	int32 freeIndex = m_freeList;
-	while (freeIndex != b2_nullNode)
-	{
-		b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity);
-		freeIndex = m_nodes[freeIndex].next;
-		++freeCount;
-	}
-
-	b2Assert(GetHeight() == ComputeHeight());
-
-	b2Assert(m_nodeCount + freeCount == m_nodeCapacity);
-}
-
-int32 b2DynamicTree::GetMaxBalance() const
-{
-	int32 maxBalance = 0;
-	for (int32 i = 0; i < m_nodeCapacity; ++i)
-	{
-		const b2TreeNode* node = m_nodes + i;
-		if (node->height <= 1)
-		{
-			continue;
-		}
-
-		b2Assert(node->IsLeaf() == false);
-
-		int32 child1 = node->child1;
-		int32 child2 = node->child2;
-		int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height);
-		maxBalance = b2Max(maxBalance, balance);
-	}
-
-	return maxBalance;
-}
-
-void b2DynamicTree::RebuildBottomUp()
-{
-	int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32));
-	int32 count = 0;
-
-	// Build array of leaves. Free the rest.
-	for (int32 i = 0; i < m_nodeCapacity; ++i)
-	{
-		if (m_nodes[i].height < 0)
-		{
-			// free node in pool
-			continue;
-		}
-
-		if (m_nodes[i].IsLeaf())
-		{
-			m_nodes[i].parent = b2_nullNode;
-			nodes[count] = i;
-			++count;
-		}
-		else
-		{
-			FreeNode(i);
-		}
-	}
-
-	while (count > 1)
-	{
-		float32 minCost = b2_maxFloat;
-		int32 iMin = -1, jMin = -1;
-		for (int32 i = 0; i < count; ++i)
-		{
-			b2AABB aabbi = m_nodes[nodes[i]].aabb;
-
-			for (int32 j = i + 1; j < count; ++j)
-			{
-				b2AABB aabbj = m_nodes[nodes[j]].aabb;
-				b2AABB b;
-				b.Combine(aabbi, aabbj);
-				float32 cost = b.GetPerimeter();
-				if (cost < minCost)
-				{
-					iMin = i;
-					jMin = j;
-					minCost = cost;
-				}
-			}
-		}
-
-		int32 index1 = nodes[iMin];
-		int32 index2 = nodes[jMin];
-		b2TreeNode* child1 = m_nodes + index1;
-		b2TreeNode* child2 = m_nodes + index2;
-
-		int32 parentIndex = AllocateNode();
-		b2TreeNode* parent = m_nodes + parentIndex;
-		parent->child1 = index1;
-		parent->child2 = index2;
-		parent->height = 1 + b2Max(child1->height, child2->height);
-		parent->aabb.Combine(child1->aabb, child2->aabb);
-		parent->parent = b2_nullNode;
-
-		child1->parent = parentIndex;
-		child2->parent = parentIndex;
-
-		nodes[jMin] = nodes[count-1];
-		nodes[iMin] = parentIndex;
-		--count;
-	}
-
-	m_root = nodes[0];
-	b2Free(nodes);
-
-	Validate();
-}
-
-void b2DynamicTree::ShiftOrigin(const b2Vec2& newOrigin)
-{
-	// Build array of leaves. Free the rest.
-	for (int32 i = 0; i < m_nodeCapacity; ++i)
-	{
-		m_nodes[i].aabb.lowerBound -= newOrigin;
-		m_nodes[i].aabb.upperBound -= newOrigin;
-	}
-}
+/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2DynamicTree.h>
+#include <memory.h>
+#include <string.h>
+
+b2DynamicTree::b2DynamicTree()
+{
+	m_root = b2_nullNode;
+
+	m_nodeCapacity = 16;
+	m_nodeCount = 0;
+	m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
+	memset(m_nodes, 0, m_nodeCapacity * sizeof(b2TreeNode));
+
+	// Build a linked list for the free list.
+	for (int32 i = 0; i < m_nodeCapacity - 1; ++i)
+	{
+		m_nodes[i].next = i + 1;
+		m_nodes[i].height = -1;
+	}
+	m_nodes[m_nodeCapacity-1].next = b2_nullNode;
+	m_nodes[m_nodeCapacity-1].height = -1;
+	m_freeList = 0;
+
+	m_path = 0;
+
+	m_insertionCount = 0;
+}
+
+b2DynamicTree::~b2DynamicTree()
+{
+	// This frees the entire tree in one shot.
+	b2Free(m_nodes);
+}
+
+// Allocate a node from the pool. Grow the pool if necessary.
+int32 b2DynamicTree::AllocateNode()
+{
+	// Expand the node pool as needed.
+	if (m_freeList == b2_nullNode)
+	{
+		b2Assert(m_nodeCount == m_nodeCapacity);
+
+		// The free list is empty. Rebuild a bigger pool.
+		b2TreeNode* oldNodes = m_nodes;
+		m_nodeCapacity *= 2;
+		m_nodes = (b2TreeNode*)b2Alloc(m_nodeCapacity * sizeof(b2TreeNode));
+		memcpy(m_nodes, oldNodes, m_nodeCount * sizeof(b2TreeNode));
+		b2Free(oldNodes);
+
+		// Build a linked list for the free list. The parent
+		// pointer becomes the "next" pointer.
+		for (int32 i = m_nodeCount; i < m_nodeCapacity - 1; ++i)
+		{
+			m_nodes[i].next = i + 1;
+			m_nodes[i].height = -1;
+		}
+		m_nodes[m_nodeCapacity-1].next = b2_nullNode;
+		m_nodes[m_nodeCapacity-1].height = -1;
+		m_freeList = m_nodeCount;
+	}
+
+	// Peel a node off the free list.
+	int32 nodeId = m_freeList;
+	m_freeList = m_nodes[nodeId].next;
+	m_nodes[nodeId].parent = b2_nullNode;
+	m_nodes[nodeId].child1 = b2_nullNode;
+	m_nodes[nodeId].child2 = b2_nullNode;
+	m_nodes[nodeId].height = 0;
+	m_nodes[nodeId].userData = NULL;
+	++m_nodeCount;
+	return nodeId;
+}
+
+// Return a node to the pool.
+void b2DynamicTree::FreeNode(int32 nodeId)
+{
+	b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
+	b2Assert(0 < m_nodeCount);
+	m_nodes[nodeId].next = m_freeList;
+	m_nodes[nodeId].height = -1;
+	m_freeList = nodeId;
+	--m_nodeCount;
+}
+
+// Create a proxy in the tree as a leaf node. We return the index
+// of the node instead of a pointer so that we can grow
+// the node pool.
+int32 b2DynamicTree::CreateProxy(const b2AABB& aabb, void* userData)
+{
+	int32 proxyId = AllocateNode();
+
+	// Fatten the aabb.
+	b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
+	m_nodes[proxyId].aabb.lowerBound = aabb.lowerBound - r;
+	m_nodes[proxyId].aabb.upperBound = aabb.upperBound + r;
+	m_nodes[proxyId].userData = userData;
+	m_nodes[proxyId].height = 0;
+
+	InsertLeaf(proxyId);
+
+	return proxyId;
+}
+
+void b2DynamicTree::DestroyProxy(int32 proxyId)
+{
+	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+	b2Assert(m_nodes[proxyId].IsLeaf());
+
+	RemoveLeaf(proxyId);
+	FreeNode(proxyId);
+}
+
+bool b2DynamicTree::MoveProxy(int32 proxyId, const b2AABB& aabb, const b2Vec2& displacement)
+{
+	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+
+	b2Assert(m_nodes[proxyId].IsLeaf());
+
+	if (m_nodes[proxyId].aabb.Contains(aabb))
+	{
+		return false;
+	}
+
+	RemoveLeaf(proxyId);
+
+	// Extend AABB.
+	b2AABB b = aabb;
+	b2Vec2 r(b2_aabbExtension, b2_aabbExtension);
+	b.lowerBound = b.lowerBound - r;
+	b.upperBound = b.upperBound + r;
+
+	// Predict AABB displacement.
+	b2Vec2 d = b2_aabbMultiplier * displacement;
+
+	if (d.x < 0.0f)
+	{
+		b.lowerBound.x += d.x;
+	}
+	else
+	{
+		b.upperBound.x += d.x;
+	}
+
+	if (d.y < 0.0f)
+	{
+		b.lowerBound.y += d.y;
+	}
+	else
+	{
+		b.upperBound.y += d.y;
+	}
+
+	m_nodes[proxyId].aabb = b;
+
+	InsertLeaf(proxyId);
+	return true;
+}
+
+void b2DynamicTree::InsertLeaf(int32 leaf)
+{
+	++m_insertionCount;
+
+	if (m_root == b2_nullNode)
+	{
+		m_root = leaf;
+		m_nodes[m_root].parent = b2_nullNode;
+		return;
+	}
+
+	// Find the best sibling for this node
+	b2AABB leafAABB = m_nodes[leaf].aabb;
+	int32 index = m_root;
+	while (m_nodes[index].IsLeaf() == false)
+	{
+		int32 child1 = m_nodes[index].child1;
+		int32 child2 = m_nodes[index].child2;
+
+		float32 area = m_nodes[index].aabb.GetPerimeter();
+
+		b2AABB combinedAABB;
+		combinedAABB.Combine(m_nodes[index].aabb, leafAABB);
+		float32 combinedArea = combinedAABB.GetPerimeter();
+
+		// Cost of creating a new parent for this node and the new leaf
+		float32 cost = 2.0f * combinedArea;
+
+		// Minimum cost of pushing the leaf further down the tree
+		float32 inheritanceCost = 2.0f * (combinedArea - area);
+
+		// Cost of descending into child1
+		float32 cost1;
+		if (m_nodes[child1].IsLeaf())
+		{
+			b2AABB aabb;
+			aabb.Combine(leafAABB, m_nodes[child1].aabb);
+			cost1 = aabb.GetPerimeter() + inheritanceCost;
+		}
+		else
+		{
+			b2AABB aabb;
+			aabb.Combine(leafAABB, m_nodes[child1].aabb);
+			float32 oldArea = m_nodes[child1].aabb.GetPerimeter();
+			float32 newArea = aabb.GetPerimeter();
+			cost1 = (newArea - oldArea) + inheritanceCost;
+		}
+
+		// Cost of descending into child2
+		float32 cost2;
+		if (m_nodes[child2].IsLeaf())
+		{
+			b2AABB aabb;
+			aabb.Combine(leafAABB, m_nodes[child2].aabb);
+			cost2 = aabb.GetPerimeter() + inheritanceCost;
+		}
+		else
+		{
+			b2AABB aabb;
+			aabb.Combine(leafAABB, m_nodes[child2].aabb);
+			float32 oldArea = m_nodes[child2].aabb.GetPerimeter();
+			float32 newArea = aabb.GetPerimeter();
+			cost2 = newArea - oldArea + inheritanceCost;
+		}
+
+		// Descend according to the minimum cost.
+		if (cost < cost1 && cost < cost2)
+		{
+			break;
+		}
+
+		// Descend
+		if (cost1 < cost2)
+		{
+			index = child1;
+		}
+		else
+		{
+			index = child2;
+		}
+	}
+
+	int32 sibling = index;
+
+	// Create a new parent.
+	int32 oldParent = m_nodes[sibling].parent;
+	int32 newParent = AllocateNode();
+	m_nodes[newParent].parent = oldParent;
+	m_nodes[newParent].userData = NULL;
+	m_nodes[newParent].aabb.Combine(leafAABB, m_nodes[sibling].aabb);
+	m_nodes[newParent].height = m_nodes[sibling].height + 1;
+
+	if (oldParent != b2_nullNode)
+	{
+		// The sibling was not the root.
+		if (m_nodes[oldParent].child1 == sibling)
+		{
+			m_nodes[oldParent].child1 = newParent;
+		}
+		else
+		{
+			m_nodes[oldParent].child2 = newParent;
+		}
+
+		m_nodes[newParent].child1 = sibling;
+		m_nodes[newParent].child2 = leaf;
+		m_nodes[sibling].parent = newParent;
+		m_nodes[leaf].parent = newParent;
+	}
+	else
+	{
+		// The sibling was the root.
+		m_nodes[newParent].child1 = sibling;
+		m_nodes[newParent].child2 = leaf;
+		m_nodes[sibling].parent = newParent;
+		m_nodes[leaf].parent = newParent;
+		m_root = newParent;
+	}
+
+	// Walk back up the tree fixing heights and AABBs
+	index = m_nodes[leaf].parent;
+	while (index != b2_nullNode)
+	{
+		index = Balance(index);
+
+		int32 child1 = m_nodes[index].child1;
+		int32 child2 = m_nodes[index].child2;
+
+		b2Assert(child1 != b2_nullNode);
+		b2Assert(child2 != b2_nullNode);
+
+		m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
+		m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+
+		index = m_nodes[index].parent;
+	}
+
+	//Validate();
+}
+
+void b2DynamicTree::RemoveLeaf(int32 leaf)
+{
+	if (leaf == m_root)
+	{
+		m_root = b2_nullNode;
+		return;
+	}
+
+	int32 parent = m_nodes[leaf].parent;
+	int32 grandParent = m_nodes[parent].parent;
+	int32 sibling;
+	if (m_nodes[parent].child1 == leaf)
+	{
+		sibling = m_nodes[parent].child2;
+	}
+	else
+	{
+		sibling = m_nodes[parent].child1;
+	}
+
+	if (grandParent != b2_nullNode)
+	{
+		// Destroy parent and connect sibling to grandParent.
+		if (m_nodes[grandParent].child1 == parent)
+		{
+			m_nodes[grandParent].child1 = sibling;
+		}
+		else
+		{
+			m_nodes[grandParent].child2 = sibling;
+		}
+		m_nodes[sibling].parent = grandParent;
+		FreeNode(parent);
+
+		// Adjust ancestor bounds.
+		int32 index = grandParent;
+		while (index != b2_nullNode)
+		{
+			index = Balance(index);
+
+			int32 child1 = m_nodes[index].child1;
+			int32 child2 = m_nodes[index].child2;
+
+			m_nodes[index].aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+			m_nodes[index].height = 1 + b2Max(m_nodes[child1].height, m_nodes[child2].height);
+
+			index = m_nodes[index].parent;
+		}
+	}
+	else
+	{
+		m_root = sibling;
+		m_nodes[sibling].parent = b2_nullNode;
+		FreeNode(parent);
+	}
+
+	//Validate();
+}
+
+// Perform a left or right rotation if node A is imbalanced.
+// Returns the new root index.
+int32 b2DynamicTree::Balance(int32 iA)
+{
+	b2Assert(iA != b2_nullNode);
+
+	b2TreeNode* A = m_nodes + iA;
+	if (A->IsLeaf() || A->height < 2)
+	{
+		return iA;
+	}
+
+	int32 iB = A->child1;
+	int32 iC = A->child2;
+	b2Assert(0 <= iB && iB < m_nodeCapacity);
+	b2Assert(0 <= iC && iC < m_nodeCapacity);
+
+	b2TreeNode* B = m_nodes + iB;
+	b2TreeNode* C = m_nodes + iC;
+
+	int32 balance = C->height - B->height;
+
+	// Rotate C up
+	if (balance > 1)
+	{
+		int32 iF = C->child1;
+		int32 iG = C->child2;
+		b2TreeNode* F = m_nodes + iF;
+		b2TreeNode* G = m_nodes + iG;
+		b2Assert(0 <= iF && iF < m_nodeCapacity);
+		b2Assert(0 <= iG && iG < m_nodeCapacity);
+
+		// Swap A and C
+		C->child1 = iA;
+		C->parent = A->parent;
+		A->parent = iC;
+
+		// A's old parent should point to C
+		if (C->parent != b2_nullNode)
+		{
+			if (m_nodes[C->parent].child1 == iA)
+			{
+				m_nodes[C->parent].child1 = iC;
+			}
+			else
+			{
+				b2Assert(m_nodes[C->parent].child2 == iA);
+				m_nodes[C->parent].child2 = iC;
+			}
+		}
+		else
+		{
+			m_root = iC;
+		}
+
+		// Rotate
+		if (F->height > G->height)
+		{
+			C->child2 = iF;
+			A->child2 = iG;
+			G->parent = iA;
+			A->aabb.Combine(B->aabb, G->aabb);
+			C->aabb.Combine(A->aabb, F->aabb);
+
+			A->height = 1 + b2Max(B->height, G->height);
+			C->height = 1 + b2Max(A->height, F->height);
+		}
+		else
+		{
+			C->child2 = iG;
+			A->child2 = iF;
+			F->parent = iA;
+			A->aabb.Combine(B->aabb, F->aabb);
+			C->aabb.Combine(A->aabb, G->aabb);
+
+			A->height = 1 + b2Max(B->height, F->height);
+			C->height = 1 + b2Max(A->height, G->height);
+		}
+
+		return iC;
+	}
+	
+	// Rotate B up
+	if (balance < -1)
+	{
+		int32 iD = B->child1;
+		int32 iE = B->child2;
+		b2TreeNode* D = m_nodes + iD;
+		b2TreeNode* E = m_nodes + iE;
+		b2Assert(0 <= iD && iD < m_nodeCapacity);
+		b2Assert(0 <= iE && iE < m_nodeCapacity);
+
+		// Swap A and B
+		B->child1 = iA;
+		B->parent = A->parent;
+		A->parent = iB;
+
+		// A's old parent should point to B
+		if (B->parent != b2_nullNode)
+		{
+			if (m_nodes[B->parent].child1 == iA)
+			{
+				m_nodes[B->parent].child1 = iB;
+			}
+			else
+			{
+				b2Assert(m_nodes[B->parent].child2 == iA);
+				m_nodes[B->parent].child2 = iB;
+			}
+		}
+		else
+		{
+			m_root = iB;
+		}
+
+		// Rotate
+		if (D->height > E->height)
+		{
+			B->child2 = iD;
+			A->child1 = iE;
+			E->parent = iA;
+			A->aabb.Combine(C->aabb, E->aabb);
+			B->aabb.Combine(A->aabb, D->aabb);
+
+			A->height = 1 + b2Max(C->height, E->height);
+			B->height = 1 + b2Max(A->height, D->height);
+		}
+		else
+		{
+			B->child2 = iE;
+			A->child1 = iD;
+			D->parent = iA;
+			A->aabb.Combine(C->aabb, D->aabb);
+			B->aabb.Combine(A->aabb, E->aabb);
+
+			A->height = 1 + b2Max(C->height, D->height);
+			B->height = 1 + b2Max(A->height, E->height);
+		}
+
+		return iB;
+	}
+
+	return iA;
+}
+
+int32 b2DynamicTree::GetHeight() const
+{
+	if (m_root == b2_nullNode)
+	{
+		return 0;
+	}
+
+	return m_nodes[m_root].height;
+}
+
+//
+float32 b2DynamicTree::GetAreaRatio() const
+{
+	if (m_root == b2_nullNode)
+	{
+		return 0.0f;
+	}
+
+	const b2TreeNode* root = m_nodes + m_root;
+	float32 rootArea = root->aabb.GetPerimeter();
+
+	float32 totalArea = 0.0f;
+	for (int32 i = 0; i < m_nodeCapacity; ++i)
+	{
+		const b2TreeNode* node = m_nodes + i;
+		if (node->height < 0)
+		{
+			// Free node in pool
+			continue;
+		}
+
+		totalArea += node->aabb.GetPerimeter();
+	}
+
+	return totalArea / rootArea;
+}
+
+// Compute the height of a sub-tree.
+int32 b2DynamicTree::ComputeHeight(int32 nodeId) const
+{
+	b2Assert(0 <= nodeId && nodeId < m_nodeCapacity);
+	b2TreeNode* node = m_nodes + nodeId;
+
+	if (node->IsLeaf())
+	{
+		return 0;
+	}
+
+	int32 height1 = ComputeHeight(node->child1);
+	int32 height2 = ComputeHeight(node->child2);
+	return 1 + b2Max(height1, height2);
+}
+
+int32 b2DynamicTree::ComputeHeight() const
+{
+	int32 height = ComputeHeight(m_root);
+	return height;
+}
+
+void b2DynamicTree::ValidateStructure(int32 index) const
+{
+	if (index == b2_nullNode)
+	{
+		return;
+	}
+
+	if (index == m_root)
+	{
+		b2Assert(m_nodes[index].parent == b2_nullNode);
+	}
+
+	const b2TreeNode* node = m_nodes + index;
+
+#if B2_ASSERT_ENABLED || DEBUG
+	int32 child1 = node->child1;
+	int32 child2 = node->child2;
+#endif  // B2_ASSERT_ENABLED || DEBUG
+
+	if (node->IsLeaf())
+	{
+		b2Assert(child1 == b2_nullNode);
+		b2Assert(child2 == b2_nullNode);
+		b2Assert(node->height == 0);
+		return;
+	}
+
+	b2Assert(0 <= child1 && child1 < m_nodeCapacity);
+	b2Assert(0 <= child2 && child2 < m_nodeCapacity);
+
+	b2Assert(m_nodes[child1].parent == index);
+	b2Assert(m_nodes[child2].parent == index);
+
+	B2_DEBUG_STATEMENT(ValidateStructure(child1));
+	B2_DEBUG_STATEMENT(ValidateStructure(child2));
+}
+
+void b2DynamicTree::ValidateMetrics(int32 index) const
+{
+	if (index == b2_nullNode)
+	{
+		return;
+	}
+
+	const b2TreeNode* node = m_nodes + index;
+
+	int32 child1 = node->child1;
+	int32 child2 = node->child2;
+
+	if (node->IsLeaf())
+	{
+		b2Assert(child1 == b2_nullNode);
+		b2Assert(child2 == b2_nullNode);
+		b2Assert(node->height == 0);
+		return;
+	}
+
+	b2Assert(0 <= child1 && child1 < m_nodeCapacity);
+	b2Assert(0 <= child2 && child2 < m_nodeCapacity);
+
+#if B2_ASSERT_ENABLED
+	int32 height1 = m_nodes[child1].height;
+	int32 height2 = m_nodes[child2].height;
+	int32 height;
+	height = 1 + b2Max(height1, height2);
+#endif // B2_ASSERT_ENABLED
+	b2Assert(node->height == height);
+
+	b2AABB aabb;
+	aabb.Combine(m_nodes[child1].aabb, m_nodes[child2].aabb);
+
+	b2Assert(aabb.lowerBound == node->aabb.lowerBound);
+	b2Assert(aabb.upperBound == node->aabb.upperBound);
+
+	ValidateMetrics(child1);
+	ValidateMetrics(child2);
+}
+
+void b2DynamicTree::Validate() const
+{
+	B2_DEBUG_STATEMENT(ValidateStructure(m_root));
+	B2_DEBUG_STATEMENT(ValidateMetrics(m_root));
+
+	int32 freeCount = 0;
+	int32 freeIndex = m_freeList;
+	while (freeIndex != b2_nullNode)
+	{
+		b2Assert(0 <= freeIndex && freeIndex < m_nodeCapacity);
+		freeIndex = m_nodes[freeIndex].next;
+		++freeCount;
+	}
+
+	b2Assert(GetHeight() == ComputeHeight());
+
+	b2Assert(m_nodeCount + freeCount == m_nodeCapacity);
+}
+
+int32 b2DynamicTree::GetMaxBalance() const
+{
+	int32 maxBalance = 0;
+	for (int32 i = 0; i < m_nodeCapacity; ++i)
+	{
+		const b2TreeNode* node = m_nodes + i;
+		if (node->height <= 1)
+		{
+			continue;
+		}
+
+		b2Assert(node->IsLeaf() == false);
+
+		int32 child1 = node->child1;
+		int32 child2 = node->child2;
+		int32 balance = b2Abs(m_nodes[child2].height - m_nodes[child1].height);
+		maxBalance = b2Max(maxBalance, balance);
+	}
+
+	return maxBalance;
+}
+
+void b2DynamicTree::RebuildBottomUp()
+{
+	int32* nodes = (int32*)b2Alloc(m_nodeCount * sizeof(int32));
+	int32 count = 0;
+
+	// Build array of leaves. Free the rest.
+	for (int32 i = 0; i < m_nodeCapacity; ++i)
+	{
+		if (m_nodes[i].height < 0)
+		{
+			// free node in pool
+			continue;
+		}
+
+		if (m_nodes[i].IsLeaf())
+		{
+			m_nodes[i].parent = b2_nullNode;
+			nodes[count] = i;
+			++count;
+		}
+		else
+		{
+			FreeNode(i);
+		}
+	}
+
+	while (count > 1)
+	{
+		float32 minCost = b2_maxFloat;
+		int32 iMin = -1, jMin = -1;
+		for (int32 i = 0; i < count; ++i)
+		{
+			b2AABB aabbi = m_nodes[nodes[i]].aabb;
+
+			for (int32 j = i + 1; j < count; ++j)
+			{
+				b2AABB aabbj = m_nodes[nodes[j]].aabb;
+				b2AABB b;
+				b.Combine(aabbi, aabbj);
+				float32 cost = b.GetPerimeter();
+				if (cost < minCost)
+				{
+					iMin = i;
+					jMin = j;
+					minCost = cost;
+				}
+			}
+		}
+
+		int32 index1 = nodes[iMin];
+		int32 index2 = nodes[jMin];
+		b2TreeNode* child1 = m_nodes + index1;
+		b2TreeNode* child2 = m_nodes + index2;
+
+		int32 parentIndex = AllocateNode();
+		b2TreeNode* parent = m_nodes + parentIndex;
+		parent->child1 = index1;
+		parent->child2 = index2;
+		parent->height = 1 + b2Max(child1->height, child2->height);
+		parent->aabb.Combine(child1->aabb, child2->aabb);
+		parent->parent = b2_nullNode;
+
+		child1->parent = parentIndex;
+		child2->parent = parentIndex;
+
+		nodes[jMin] = nodes[count-1];
+		nodes[iMin] = parentIndex;
+		--count;
+	}
+
+	m_root = nodes[0];
+	b2Free(nodes);
+
+	B2_DEBUG_STATEMENT(Validate());
+}
+
+void b2DynamicTree::ShiftOrigin(const b2Vec2& newOrigin)
+{
+	// Build array of leaves. Free the rest.
+	for (int32 i = 0; i < m_nodeCapacity; ++i)
+	{
+		m_nodes[i].aabb.lowerBound -= newOrigin;
+		m_nodes[i].aabb.upperBound -= newOrigin;
+	}
+}

+ 289 - 289
engine/source/Box2D/Collision/b2DynamicTree.h

@@ -1,289 +1,289 @@
-/*
-* Copyright (c) 2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_DYNAMIC_TREE_H
-#define B2_DYNAMIC_TREE_H
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Common/b2GrowableStack.h>
-
-#define b2_nullNode (-1)
-
-/// A node in the dynamic tree. The client does not interact with this directly.
-struct b2TreeNode
-{
-	bool IsLeaf() const
-	{
-		return child1 == b2_nullNode;
-	}
-
-	/// Enlarged AABB
-	b2AABB aabb;
-
-	void* userData;
-
-	union
-	{
-		int32 parent;
-		int32 next;
-	};
-
-	int32 child1;
-	int32 child2;
-
-	// leaf = 0, free node = -1
-	int32 height;
-};
-
-/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
-/// A dynamic tree arranges data in a binary tree to accelerate
-/// queries such as volume queries and ray casts. Leafs are proxies
-/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
-/// so that the proxy AABB is bigger than the client object. This allows the client
-/// object to move by small amounts without triggering a tree update.
-///
-/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
-class b2DynamicTree
-{
-public:
-	/// Constructing the tree initializes the node pool.
-	b2DynamicTree();
-
-	/// Destroy the tree, freeing the node pool.
-	~b2DynamicTree();
-
-	/// Create a proxy. Provide a tight fitting AABB and a userData pointer.
-	int32 CreateProxy(const b2AABB& aabb, void* userData);
-
-	/// Destroy a proxy. This asserts if the id is invalid.
-	void DestroyProxy(int32 proxyId);
-
-	/// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,
-	/// then the proxy is removed from the tree and re-inserted. Otherwise
-	/// the function returns immediately.
-	/// @return true if the proxy was re-inserted.
-	bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
-
-	/// Get proxy user data.
-	/// @return the proxy user data or 0 if the id is invalid.
-	void* GetUserData(int32 proxyId) const;
-
-	/// Get the fat AABB for a proxy.
-	const b2AABB& GetFatAABB(int32 proxyId) const;
-
-	/// Query an AABB for overlapping proxies. The callback class
-	/// is called for each proxy that overlaps the supplied AABB.
-	template <typename T>
-	void Query(T* callback, const b2AABB& aabb) const;
-
-	/// Ray-cast against the proxies in the tree. This relies on the callback
-	/// to perform a exact ray-cast in the case were the proxy contains a shape.
-	/// The callback also performs the any collision filtering. This has performance
-	/// roughly equal to k * log(n), where k is the number of collisions and n is the
-	/// number of proxies in the tree.
-	/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
-	/// @param callback a callback class that is called for each proxy that is hit by the ray.
-	template <typename T>
-	void RayCast(T* callback, const b2RayCastInput& input) const;
-
-	/// Validate this tree. For testing.
-	void Validate() const;
-
-	/// Compute the height of the binary tree in O(N) time. Should not be
-	/// called often.
-	int32 GetHeight() const;
-
-	/// Get the maximum balance of an node in the tree. The balance is the difference
-	/// in height of the two children of a node.
-	int32 GetMaxBalance() const;
-
-	/// Get the ratio of the sum of the node areas to the root area.
-	float32 GetAreaRatio() const;
-
-	/// Build an optimal tree. Very expensive. For testing.
-	void RebuildBottomUp();
-
-	/// Shift the world origin. Useful for large worlds.
-	/// The shift formula is: position -= newOrigin
-	/// @param newOrigin the new origin with respect to the old origin
-	void ShiftOrigin(const b2Vec2& newOrigin);
-
-private:
-
-	int32 AllocateNode();
-	void FreeNode(int32 node);
-
-	void InsertLeaf(int32 node);
-	void RemoveLeaf(int32 node);
-
-	int32 Balance(int32 index);
-
-	int32 ComputeHeight() const;
-	int32 ComputeHeight(int32 nodeId) const;
-
-	void ValidateStructure(int32 index) const;
-	void ValidateMetrics(int32 index) const;
-
-	int32 m_root;
-
-	b2TreeNode* m_nodes;
-	int32 m_nodeCount;
-	int32 m_nodeCapacity;
-
-	int32 m_freeList;
-
-	/// This is used to incrementally traverse the tree for re-balancing.
-	uint32 m_path;
-
-	int32 m_insertionCount;
-};
-
-inline void* b2DynamicTree::GetUserData(int32 proxyId) const
-{
-	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
-	return m_nodes[proxyId].userData;
-}
-
-inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
-{
-	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
-	return m_nodes[proxyId].aabb;
-}
-
-template <typename T>
-inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
-{
-	b2GrowableStack<int32, 256> stack;
-	stack.Push(m_root);
-
-	while (stack.GetCount() > 0)
-	{
-		int32 nodeId = stack.Pop();
-		if (nodeId == b2_nullNode)
-		{
-			continue;
-		}
-
-		const b2TreeNode* node = m_nodes + nodeId;
-
-		if (b2TestOverlap(node->aabb, aabb))
-		{
-			if (node->IsLeaf())
-			{
-				bool proceed = callback->QueryCallback(nodeId);
-				if (proceed == false)
-				{
-					return;
-				}
-			}
-			else
-			{
-				stack.Push(node->child1);
-				stack.Push(node->child2);
-			}
-		}
-	}
-}
-
-template <typename T>
-inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const
-{
-	b2Vec2 p1 = input.p1;
-	b2Vec2 p2 = input.p2;
-	b2Vec2 r = p2 - p1;
-	b2Assert(r.LengthSquared() > 0.0f);
-	r.Normalize();
-
-	// v is perpendicular to the segment.
-	b2Vec2 v = b2Cross(1.0f, r);
-	b2Vec2 abs_v = b2Abs(v);
-
-	// Separating axis for segment (Gino, p80).
-	// |dot(v, p1 - c)| > dot(|v|, h)
-
-	float32 maxFraction = input.maxFraction;
-
-	// Build a bounding box for the segment.
-	b2AABB segmentAABB;
-	{
-		b2Vec2 t = p1 + maxFraction * (p2 - p1);
-		segmentAABB.lowerBound = b2Min(p1, t);
-		segmentAABB.upperBound = b2Max(p1, t);
-	}
-
-	b2GrowableStack<int32, 256> stack;
-	stack.Push(m_root);
-
-	while (stack.GetCount() > 0)
-	{
-		int32 nodeId = stack.Pop();
-		if (nodeId == b2_nullNode)
-		{
-			continue;
-		}
-
-		const b2TreeNode* node = m_nodes + nodeId;
-
-		if (b2TestOverlap(node->aabb, segmentAABB) == false)
-		{
-			continue;
-		}
-
-		// Separating axis for segment (Gino, p80).
-		// |dot(v, p1 - c)| > dot(|v|, h)
-		b2Vec2 c = node->aabb.GetCenter();
-		b2Vec2 h = node->aabb.GetExtents();
-		float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
-		if (separation > 0.0f)
-		{
-			continue;
-		}
-
-		if (node->IsLeaf())
-		{
-			b2RayCastInput subInput;
-			subInput.p1 = input.p1;
-			subInput.p2 = input.p2;
-			subInput.maxFraction = maxFraction;
-
-			float32 value = callback->RayCastCallback(subInput, nodeId);
-
-			if (value == 0.0f)
-			{
-				// The client has terminated the ray cast.
-				return;
-			}
-
-			if (value > 0.0f)
-			{
-				// Update segment bounding box.
-				maxFraction = value;
-				b2Vec2 t = p1 + maxFraction * (p2 - p1);
-				segmentAABB.lowerBound = b2Min(p1, t);
-				segmentAABB.upperBound = b2Max(p1, t);
-			}
-		}
-		else
-		{
-			stack.Push(node->child1);
-			stack.Push(node->child2);
-		}
-	}
-}
-
-#endif
+/*
+* Copyright (c) 2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DYNAMIC_TREE_H
+#define B2_DYNAMIC_TREE_H
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Common/b2GrowableStack.h>
+
+#define b2_nullNode (-1)
+
+/// A node in the dynamic tree. The client does not interact with this directly.
+struct b2TreeNode
+{
+	bool IsLeaf() const
+	{
+		return child1 == b2_nullNode;
+	}
+
+	/// Enlarged AABB
+	b2AABB aabb;
+
+	void* userData;
+
+	union
+	{
+		int32 parent;
+		int32 next;
+	};
+
+	int32 child1;
+	int32 child2;
+
+	// leaf = 0, free node = -1
+	int32 height;
+};
+
+/// A dynamic AABB tree broad-phase, inspired by Nathanael Presson's btDbvt.
+/// A dynamic tree arranges data in a binary tree to accelerate
+/// queries such as volume queries and ray casts. Leafs are proxies
+/// with an AABB. In the tree we expand the proxy AABB by b2_fatAABBFactor
+/// so that the proxy AABB is bigger than the client object. This allows the client
+/// object to move by small amounts without triggering a tree update.
+///
+/// Nodes are pooled and relocatable, so we use node indices rather than pointers.
+class b2DynamicTree
+{
+public:
+	/// Constructing the tree initializes the node pool.
+	b2DynamicTree();
+
+	/// Destroy the tree, freeing the node pool.
+	~b2DynamicTree();
+
+	/// Create a proxy. Provide a tight fitting AABB and a userData pointer.
+	int32 CreateProxy(const b2AABB& aabb, void* userData);
+
+	/// Destroy a proxy. This asserts if the id is invalid.
+	void DestroyProxy(int32 proxyId);
+
+	/// Move a proxy with a swepted AABB. If the proxy has moved outside of its fattened AABB,
+	/// then the proxy is removed from the tree and re-inserted. Otherwise
+	/// the function returns immediately.
+	/// @return true if the proxy was re-inserted.
+	bool MoveProxy(int32 proxyId, const b2AABB& aabb1, const b2Vec2& displacement);
+
+	/// Get proxy user data.
+	/// @return the proxy user data or 0 if the id is invalid.
+	void* GetUserData(int32 proxyId) const;
+
+	/// Get the fat AABB for a proxy.
+	const b2AABB& GetFatAABB(int32 proxyId) const;
+
+	/// Query an AABB for overlapping proxies. The callback class
+	/// is called for each proxy that overlaps the supplied AABB.
+	template <typename T>
+	void Query(T* callback, const b2AABB& aabb) const;
+
+	/// Ray-cast against the proxies in the tree. This relies on the callback
+	/// to perform a exact ray-cast in the case were the proxy contains a shape.
+	/// The callback also performs the any collision filtering. This has performance
+	/// roughly equal to k * log(n), where k is the number of collisions and n is the
+	/// number of proxies in the tree.
+	/// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
+	/// @param callback a callback class that is called for each proxy that is hit by the ray.
+	template <typename T>
+	void RayCast(T* callback, const b2RayCastInput& input) const;
+
+	/// Validate this tree. For testing.
+	void Validate() const;
+
+	/// Compute the height of the binary tree in O(N) time. Should not be
+	/// called often.
+	int32 GetHeight() const;
+
+	/// Get the maximum balance of an node in the tree. The balance is the difference
+	/// in height of the two children of a node.
+	int32 GetMaxBalance() const;
+
+	/// Get the ratio of the sum of the node areas to the root area.
+	float32 GetAreaRatio() const;
+
+	/// Build an optimal tree. Very expensive. For testing.
+	void RebuildBottomUp();
+
+	/// Shift the world origin. Useful for large worlds.
+	/// The shift formula is: position -= newOrigin
+	/// @param newOrigin the new origin with respect to the old origin
+	void ShiftOrigin(const b2Vec2& newOrigin);
+
+private:
+
+	int32 AllocateNode();
+	void FreeNode(int32 node);
+
+	void InsertLeaf(int32 node);
+	void RemoveLeaf(int32 node);
+
+	int32 Balance(int32 index);
+
+	int32 ComputeHeight() const;
+	int32 ComputeHeight(int32 nodeId) const;
+
+	void ValidateStructure(int32 index) const;
+	void ValidateMetrics(int32 index) const;
+
+	int32 m_root;
+
+	b2TreeNode* m_nodes;
+	int32 m_nodeCount;
+	int32 m_nodeCapacity;
+
+	int32 m_freeList;
+
+	/// This is used to incrementally traverse the tree for re-balancing.
+	uint32 m_path;
+
+	int32 m_insertionCount;
+};
+
+inline void* b2DynamicTree::GetUserData(int32 proxyId) const
+{
+	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+	return m_nodes[proxyId].userData;
+}
+
+inline const b2AABB& b2DynamicTree::GetFatAABB(int32 proxyId) const
+{
+	b2Assert(0 <= proxyId && proxyId < m_nodeCapacity);
+	return m_nodes[proxyId].aabb;
+}
+
+template <typename T>
+inline void b2DynamicTree::Query(T* callback, const b2AABB& aabb) const
+{
+	b2GrowableStack<int32, 256> stack;
+	stack.Push(m_root);
+
+	while (stack.GetCount() > 0)
+	{
+		int32 nodeId = stack.Pop();
+		if (nodeId == b2_nullNode)
+		{
+			continue;
+		}
+
+		const b2TreeNode* node = m_nodes + nodeId;
+
+		if (b2TestOverlap(node->aabb, aabb))
+		{
+			if (node->IsLeaf())
+			{
+				bool proceed = callback->QueryCallback(nodeId);
+				if (proceed == false)
+				{
+					return;
+				}
+			}
+			else
+			{
+				stack.Push(node->child1);
+				stack.Push(node->child2);
+			}
+		}
+	}
+}
+
+template <typename T>
+inline void b2DynamicTree::RayCast(T* callback, const b2RayCastInput& input) const
+{
+	b2Vec2 p1 = input.p1;
+	b2Vec2 p2 = input.p2;
+	b2Vec2 r = p2 - p1;
+	b2Assert(r.LengthSquared() > 0.0f);
+	r.Normalize();
+
+	// v is perpendicular to the segment.
+	b2Vec2 v = b2Cross(1.0f, r);
+	b2Vec2 abs_v = b2Abs(v);
+
+	// Separating axis for segment (Gino, p80).
+	// |dot(v, p1 - c)| > dot(|v|, h)
+
+	float32 maxFraction = input.maxFraction;
+
+	// Build a bounding box for the segment.
+	b2AABB segmentAABB;
+	{
+		b2Vec2 t = p1 + maxFraction * (p2 - p1);
+		segmentAABB.lowerBound = b2Min(p1, t);
+		segmentAABB.upperBound = b2Max(p1, t);
+	}
+
+	b2GrowableStack<int32, 256> stack;
+	stack.Push(m_root);
+
+	while (stack.GetCount() > 0)
+	{
+		int32 nodeId = stack.Pop();
+		if (nodeId == b2_nullNode)
+		{
+			continue;
+		}
+
+		const b2TreeNode* node = m_nodes + nodeId;
+
+		if (b2TestOverlap(node->aabb, segmentAABB) == false)
+		{
+			continue;
+		}
+
+		// Separating axis for segment (Gino, p80).
+		// |dot(v, p1 - c)| > dot(|v|, h)
+		b2Vec2 c = node->aabb.GetCenter();
+		b2Vec2 h = node->aabb.GetExtents();
+		float32 separation = b2Abs(b2Dot(v, p1 - c)) - b2Dot(abs_v, h);
+		if (separation > 0.0f)
+		{
+			continue;
+		}
+
+		if (node->IsLeaf())
+		{
+			b2RayCastInput subInput;
+			subInput.p1 = input.p1;
+			subInput.p2 = input.p2;
+			subInput.maxFraction = maxFraction;
+
+			float32 value = callback->RayCastCallback(subInput, nodeId);
+
+			if (value == 0.0f)
+			{
+				// The client has terminated the ray cast.
+				return;
+			}
+
+			if (value > 0.0f)
+			{
+				// Update segment bounding box.
+				maxFraction = value;
+				b2Vec2 t = p1 + maxFraction * (p2 - p1);
+				segmentAABB.lowerBound = b2Min(p1, t);
+				segmentAABB.upperBound = b2Max(p1, t);
+			}
+		}
+		else
+		{
+			stack.Push(node->child1);
+			stack.Push(node->child2);
+		}
+	}
+}
+
+#endif

+ 487 - 476
engine/source/Box2D/Collision/b2TimeOfImpact.cpp

@@ -1,476 +1,487 @@
-/*
-* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Collision/b2Collision.h>
-#include <Box2D/Collision/b2Distance.h>
-#include <Box2D/Collision/b2TimeOfImpact.h>
-#include <Box2D/Collision/Shapes/b2CircleShape.h>
-#include <Box2D/Collision/Shapes/b2PolygonShape.h>
-
-#include <cstdio>
-using namespace std;
-
-int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
-int32 b2_toiRootIters, b2_toiMaxRootIters;
-
-struct b2SeparationFunction
-{
-	enum Type
-	{
-		e_points,
-		e_faceA,
-		e_faceB
-	};
-
-	// TODO_ERIN might not need to return the separation
-
-	float32 Initialize(const b2SimplexCache* cache,
-		const b2DistanceProxy* proxyA, const b2Sweep& sweepA,
-		const b2DistanceProxy* proxyB, const b2Sweep& sweepB,
-		float32 t1)
-	{
-		m_proxyA = proxyA;
-		m_proxyB = proxyB;
-		int32 count = cache->count;
-		b2Assert(0 < count && count < 3);
-
-		m_sweepA = sweepA;
-		m_sweepB = sweepB;
-
-		b2Transform xfA, xfB;
-		m_sweepA.GetTransform(&xfA, t1);
-		m_sweepB.GetTransform(&xfB, t1);
-
-		if (count == 1)
-		{
-			m_type = e_points;
-			b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);
-			b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
-			b2Vec2 pointA = b2Mul(xfA, localPointA);
-			b2Vec2 pointB = b2Mul(xfB, localPointB);
-			m_axis = pointB - pointA;
-			float32 s = m_axis.Normalize();
-			return s;
-		}
-		else if (cache->indexA[0] == cache->indexA[1])
-		{
-			// Two points on B and one on A.
-			m_type = e_faceB;
-			b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);
-			b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);
-
-			m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);
-			m_axis.Normalize();
-			b2Vec2 normal = b2Mul(xfB.q, m_axis);
-
-			m_localPoint = 0.5f * (localPointB1 + localPointB2);
-			b2Vec2 pointB = b2Mul(xfB, m_localPoint);
-
-			b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);
-			b2Vec2 pointA = b2Mul(xfA, localPointA);
-
-			float32 s = b2Dot(pointA - pointB, normal);
-			if (s < 0.0f)
-			{
-				m_axis = -m_axis;
-				s = -s;
-			}
-			return s;
-		}
-		else
-		{
-			// Two points on A and one or two points on B.
-			m_type = e_faceA;
-			b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);
-			b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);
-			
-			m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);
-			m_axis.Normalize();
-			b2Vec2 normal = b2Mul(xfA.q, m_axis);
-
-			m_localPoint = 0.5f * (localPointA1 + localPointA2);
-			b2Vec2 pointA = b2Mul(xfA, m_localPoint);
-
-			b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
-			b2Vec2 pointB = b2Mul(xfB, localPointB);
-
-			float32 s = b2Dot(pointB - pointA, normal);
-			if (s < 0.0f)
-			{
-				m_axis = -m_axis;
-				s = -s;
-			}
-			return s;
-		}
-	}
-
-	float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const
-	{
-		b2Transform xfA, xfB;
-		m_sweepA.GetTransform(&xfA, t);
-		m_sweepB.GetTransform(&xfB, t);
-
-		switch (m_type)
-		{
-		case e_points:
-			{
-				b2Vec2 axisA = b2MulT(xfA.q,  m_axis);
-				b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
-
-				*indexA = m_proxyA->GetSupport(axisA);
-				*indexB = m_proxyB->GetSupport(axisB);
-
-				b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
-				b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
-				
-				b2Vec2 pointA = b2Mul(xfA, localPointA);
-				b2Vec2 pointB = b2Mul(xfB, localPointB);
-
-				float32 separation = b2Dot(pointB - pointA, m_axis);
-				return separation;
-			}
-
-		case e_faceA:
-			{
-				b2Vec2 normal = b2Mul(xfA.q, m_axis);
-				b2Vec2 pointA = b2Mul(xfA, m_localPoint);
-
-				b2Vec2 axisB = b2MulT(xfB.q, -normal);
-				
-				*indexA = -1;
-				*indexB = m_proxyB->GetSupport(axisB);
-
-				b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
-				b2Vec2 pointB = b2Mul(xfB, localPointB);
-
-				float32 separation = b2Dot(pointB - pointA, normal);
-				return separation;
-			}
-
-		case e_faceB:
-			{
-				b2Vec2 normal = b2Mul(xfB.q, m_axis);
-				b2Vec2 pointB = b2Mul(xfB, m_localPoint);
-
-				b2Vec2 axisA = b2MulT(xfA.q, -normal);
-
-				*indexB = -1;
-				*indexA = m_proxyA->GetSupport(axisA);
-
-				b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
-				b2Vec2 pointA = b2Mul(xfA, localPointA);
-
-				float32 separation = b2Dot(pointA - pointB, normal);
-				return separation;
-			}
-
-		default:
-			b2Assert(false);
-			*indexA = -1;
-			*indexB = -1;
-			return 0.0f;
-		}
-	}
-
-	float32 Evaluate(int32 indexA, int32 indexB, float32 t) const
-	{
-		b2Transform xfA, xfB;
-		m_sweepA.GetTransform(&xfA, t);
-		m_sweepB.GetTransform(&xfB, t);
-
-		switch (m_type)
-		{
-		case e_points:
-			{
-				b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
-				b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
-
-				b2Vec2 pointA = b2Mul(xfA, localPointA);
-				b2Vec2 pointB = b2Mul(xfB, localPointB);
-				float32 separation = b2Dot(pointB - pointA, m_axis);
-
-				return separation;
-			}
-
-		case e_faceA:
-			{
-				b2Vec2 normal = b2Mul(xfA.q, m_axis);
-				b2Vec2 pointA = b2Mul(xfA, m_localPoint);
-
-				b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
-				b2Vec2 pointB = b2Mul(xfB, localPointB);
-
-				float32 separation = b2Dot(pointB - pointA, normal);
-				return separation;
-			}
-
-		case e_faceB:
-			{
-				b2Vec2 normal = b2Mul(xfB.q, m_axis);
-				b2Vec2 pointB = b2Mul(xfB, m_localPoint);
-
-				b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
-				b2Vec2 pointA = b2Mul(xfA, localPointA);
-
-				float32 separation = b2Dot(pointA - pointB, normal);
-				return separation;
-			}
-
-		default:
-			b2Assert(false);
-			return 0.0f;
-		}
-	}
-
-	const b2DistanceProxy* m_proxyA;
-	const b2DistanceProxy* m_proxyB;
-	b2Sweep m_sweepA, m_sweepB;
-	Type m_type;
-	b2Vec2 m_localPoint;
-	b2Vec2 m_axis;
-};
-
-// CCD via the local separating axis method. This seeks progression
-// by computing the largest time at which separation is maintained.
-void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)
-{
-	++b2_toiCalls;
-
-	output->state = b2TOIOutput::e_unknown;
-	output->t = input->tMax;
-
-	const b2DistanceProxy* proxyA = &input->proxyA;
-	const b2DistanceProxy* proxyB = &input->proxyB;
-
-	b2Sweep sweepA = input->sweepA;
-	b2Sweep sweepB = input->sweepB;
-
-	// Large rotations can make the root finder fail, so we normalize the
-	// sweep angles.
-	sweepA.Normalize();
-	sweepB.Normalize();
-
-	float32 tMax = input->tMax;
-
-	float32 totalRadius = proxyA->m_radius + proxyB->m_radius;
-	float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);
-	float32 tolerance = 0.25f * b2_linearSlop;
-	b2Assert(target > tolerance);
-
-	float32 t1 = 0.0f;
-	const int32 k_maxIterations = 20;	// TODO_ERIN b2Settings
-	int32 iter = 0;
-
-	// Prepare input for distance query.
-	b2SimplexCache cache;
-	cache.count = 0;
-	b2DistanceInput distanceInput;
-	distanceInput.proxyA = input->proxyA;
-	distanceInput.proxyB = input->proxyB;
-	distanceInput.useRadii = false;
-
-	// The outer loop progressively attempts to compute new separating axes.
-	// This loop terminates when an axis is repeated (no progress is made).
-	for(;;)
-	{
-		b2Transform xfA, xfB;
-		sweepA.GetTransform(&xfA, t1);
-		sweepB.GetTransform(&xfB, t1);
-
-		// Get the distance between shapes. We can also use the results
-		// to get a separating axis.
-		distanceInput.transformA = xfA;
-		distanceInput.transformB = xfB;
-		b2DistanceOutput distanceOutput;
-		b2Distance(&distanceOutput, &cache, &distanceInput);
-
-		// If the shapes are overlapped, we give up on continuous collision.
-		if (distanceOutput.distance <= 0.0f)
-		{
-			// Failure!
-			output->state = b2TOIOutput::e_overlapped;
-			output->t = 0.0f;
-			break;
-		}
-
-		if (distanceOutput.distance < target + tolerance)
-		{
-			// Victory!
-			output->state = b2TOIOutput::e_touching;
-			output->t = t1;
-			break;
-		}
-
-		// Initialize the separating axis.
-		b2SeparationFunction fcn;
-		fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
-#if 0
-		// Dump the curve seen by the root finder
-		{
-			const int32 N = 100;
-			float32 dx = 1.0f / N;
-			float32 xs[N+1];
-			float32 fs[N+1];
-
-			float32 x = 0.0f;
-
-			for (int32 i = 0; i <= N; ++i)
-			{
-				sweepA.GetTransform(&xfA, x);
-				sweepB.GetTransform(&xfB, x);
-				float32 f = fcn.Evaluate(xfA, xfB) - target;
-
-				printf("%g %g\n", x, f);
-
-				xs[i] = x;
-				fs[i] = f;
-
-				x += dx;
-			}
-		}
-#endif
-
-		// Compute the TOI on the separating axis. We do this by successively
-		// resolving the deepest point. This loop is bounded by the number of vertices.
-		bool done = false;
-		float32 t2 = tMax;
-		int32 pushBackIter = 0;
-		for (;;)
-		{
-			// Find the deepest point at t2. Store the witness point indices.
-			int32 indexA, indexB;
-			float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);
-
-			// Is the final configuration separated?
-			if (s2 > target + tolerance)
-			{
-				// Victory!
-				output->state = b2TOIOutput::e_separated;
-				output->t = tMax;
-				done = true;
-				break;
-			}
-
-			// Has the separation reached tolerance?
-			if (s2 > target - tolerance)
-			{
-				// Advance the sweeps
-				t1 = t2;
-				break;
-			}
-
-			// Compute the initial separation of the witness points.
-			float32 s1 = fcn.Evaluate(indexA, indexB, t1);
-
-			// Check for initial overlap. This might happen if the root finder
-			// runs out of iterations.
-			if (s1 < target - tolerance)
-			{
-				output->state = b2TOIOutput::e_failed;
-				output->t = t1;
-				done = true;
-				break;
-			}
-
-			// Check for touching
-			if (s1 <= target + tolerance)
-			{
-				// Victory! t1 should hold the TOI (could be 0.0).
-				output->state = b2TOIOutput::e_touching;
-				output->t = t1;
-				done = true;
-				break;
-			}
-
-			// Compute 1D root of: f(x) - target = 0
-			int32 rootIterCount = 0;
-			float32 a1 = t1, a2 = t2;
-			for (;;)
-			{
-				// Use a mix of the secant rule and bisection.
-				float32 t;
-				if (rootIterCount & 1)
-				{
-					// Secant rule to improve convergence.
-					t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
-				}
-				else
-				{
-					// Bisection to guarantee progress.
-					t = 0.5f * (a1 + a2);
-				}
-
-				float32 s = fcn.Evaluate(indexA, indexB, t);
-
-				if (b2Abs(s - target) < tolerance)
-				{
-					// t2 holds a tentative value for t1
-					t2 = t;
-					break;
-				}
-
-				// Ensure we continue to bracket the root.
-				if (s > target)
-				{
-					a1 = t;
-					s1 = s;
-				}
-				else
-				{
-					a2 = t;
-					s2 = s;
-				}
-
-				++rootIterCount;
-				++b2_toiRootIters;
-
-				if (rootIterCount == 50)
-				{
-					break;
-				}
-			}
-
-			b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
-
-			++pushBackIter;
-
-			if (pushBackIter == b2_maxPolygonVertices)
-			{
-				break;
-			}
-		}
-
-		++iter;
-		++b2_toiIters;
-
-		if (done)
-		{
-			break;
-		}
-
-		if (iter == k_maxIterations)
-		{
-			// Root finder got stuck. Semi-victory.
-			output->state = b2TOIOutput::e_failed;
-			output->t = t1;
-			break;
-		}
-	}
-
-	b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);
-}
+/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Collision/b2Collision.h>
+#include <Box2D/Collision/b2Distance.h>
+#include <Box2D/Collision/b2TimeOfImpact.h>
+#include <Box2D/Collision/Shapes/b2CircleShape.h>
+#include <Box2D/Collision/Shapes/b2PolygonShape.h>
+#include <Box2D/Common/b2Timer.h>
+
+#include <stdio.h>
+
+float32 b2_toiTime, b2_toiMaxTime;
+int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
+int32 b2_toiRootIters, b2_toiMaxRootIters;
+
+//
+struct b2SeparationFunction
+{
+	enum Type
+	{
+		e_points,
+		e_faceA,
+		e_faceB
+	};
+
+	// TODO_ERIN might not need to return the separation
+
+	float32 Initialize(const b2SimplexCache* cache,
+		const b2DistanceProxy* proxyA, const b2Sweep& sweepA,
+		const b2DistanceProxy* proxyB, const b2Sweep& sweepB,
+		float32 t1)
+	{
+		m_proxyA = proxyA;
+		m_proxyB = proxyB;
+		int32 count = cache->count;
+		b2Assert(0 < count && count < 3);
+
+		m_sweepA = sweepA;
+		m_sweepB = sweepB;
+
+		b2Transform xfA, xfB;
+		m_sweepA.GetTransform(&xfA, t1);
+		m_sweepB.GetTransform(&xfB, t1);
+
+		if (count == 1)
+		{
+			m_type = e_points;
+			b2Vec2 localPointA = m_proxyA->GetVertex(cache->indexA[0]);
+			b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
+			b2Vec2 pointA = b2Mul(xfA, localPointA);
+			b2Vec2 pointB = b2Mul(xfB, localPointB);
+			m_axis = pointB - pointA;
+			float32 s = m_axis.Normalize();
+			m_localPoint = b2Vec2_zero;
+			return s;
+		}
+		else if (cache->indexA[0] == cache->indexA[1])
+		{
+			// Two points on B and one on A.
+			m_type = e_faceB;
+			b2Vec2 localPointB1 = proxyB->GetVertex(cache->indexB[0]);
+			b2Vec2 localPointB2 = proxyB->GetVertex(cache->indexB[1]);
+
+			m_axis = b2Cross(localPointB2 - localPointB1, 1.0f);
+			m_axis.Normalize();
+			b2Vec2 normal = b2Mul(xfB.q, m_axis);
+
+			m_localPoint = 0.5f * (localPointB1 + localPointB2);
+			b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+			b2Vec2 localPointA = proxyA->GetVertex(cache->indexA[0]);
+			b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+			float32 s = b2Dot(pointA - pointB, normal);
+			if (s < 0.0f)
+			{
+				m_axis = -m_axis;
+				s = -s;
+			}
+			return s;
+		}
+		else
+		{
+			// Two points on A and one or two points on B.
+			m_type = e_faceA;
+			b2Vec2 localPointA1 = m_proxyA->GetVertex(cache->indexA[0]);
+			b2Vec2 localPointA2 = m_proxyA->GetVertex(cache->indexA[1]);
+			
+			m_axis = b2Cross(localPointA2 - localPointA1, 1.0f);
+			m_axis.Normalize();
+			b2Vec2 normal = b2Mul(xfA.q, m_axis);
+
+			m_localPoint = 0.5f * (localPointA1 + localPointA2);
+			b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+			b2Vec2 localPointB = m_proxyB->GetVertex(cache->indexB[0]);
+			b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+			float32 s = b2Dot(pointB - pointA, normal);
+			if (s < 0.0f)
+			{
+				m_axis = -m_axis;
+				s = -s;
+			}
+			return s;
+		}
+	}
+
+	//
+	float32 FindMinSeparation(int32* indexA, int32* indexB, float32 t) const
+	{
+		b2Transform xfA, xfB;
+		m_sweepA.GetTransform(&xfA, t);
+		m_sweepB.GetTransform(&xfB, t);
+
+		switch (m_type)
+		{
+		case e_points:
+			{
+				b2Vec2 axisA = b2MulT(xfA.q,  m_axis);
+				b2Vec2 axisB = b2MulT(xfB.q, -m_axis);
+
+				*indexA = m_proxyA->GetSupport(axisA);
+				*indexB = m_proxyB->GetSupport(axisB);
+
+				b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
+				b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
+				
+				b2Vec2 pointA = b2Mul(xfA, localPointA);
+				b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+				float32 separation = b2Dot(pointB - pointA, m_axis);
+				return separation;
+			}
+
+		case e_faceA:
+			{
+				b2Vec2 normal = b2Mul(xfA.q, m_axis);
+				b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+				b2Vec2 axisB = b2MulT(xfB.q, -normal);
+				
+				*indexA = -1;
+				*indexB = m_proxyB->GetSupport(axisB);
+
+				b2Vec2 localPointB = m_proxyB->GetVertex(*indexB);
+				b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+				float32 separation = b2Dot(pointB - pointA, normal);
+				return separation;
+			}
+
+		case e_faceB:
+			{
+				b2Vec2 normal = b2Mul(xfB.q, m_axis);
+				b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+				b2Vec2 axisA = b2MulT(xfA.q, -normal);
+
+				*indexB = -1;
+				*indexA = m_proxyA->GetSupport(axisA);
+
+				b2Vec2 localPointA = m_proxyA->GetVertex(*indexA);
+				b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+				float32 separation = b2Dot(pointA - pointB, normal);
+				return separation;
+			}
+
+		default:
+			b2Assert(false);
+			*indexA = -1;
+			*indexB = -1;
+			return 0.0f;
+		}
+	}
+
+	//
+	float32 Evaluate(int32 indexA, int32 indexB, float32 t) const
+	{
+		b2Transform xfA, xfB;
+		m_sweepA.GetTransform(&xfA, t);
+		m_sweepB.GetTransform(&xfB, t);
+
+		switch (m_type)
+		{
+		case e_points:
+			{
+				b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
+				b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
+
+				b2Vec2 pointA = b2Mul(xfA, localPointA);
+				b2Vec2 pointB = b2Mul(xfB, localPointB);
+				float32 separation = b2Dot(pointB - pointA, m_axis);
+
+				return separation;
+			}
+
+		case e_faceA:
+			{
+				b2Vec2 normal = b2Mul(xfA.q, m_axis);
+				b2Vec2 pointA = b2Mul(xfA, m_localPoint);
+
+				b2Vec2 localPointB = m_proxyB->GetVertex(indexB);
+				b2Vec2 pointB = b2Mul(xfB, localPointB);
+
+				float32 separation = b2Dot(pointB - pointA, normal);
+				return separation;
+			}
+
+		case e_faceB:
+			{
+				b2Vec2 normal = b2Mul(xfB.q, m_axis);
+				b2Vec2 pointB = b2Mul(xfB, m_localPoint);
+
+				b2Vec2 localPointA = m_proxyA->GetVertex(indexA);
+				b2Vec2 pointA = b2Mul(xfA, localPointA);
+
+				float32 separation = b2Dot(pointA - pointB, normal);
+				return separation;
+			}
+
+		default:
+			b2Assert(false);
+			return 0.0f;
+		}
+	}
+
+	const b2DistanceProxy* m_proxyA;
+	const b2DistanceProxy* m_proxyB;
+	b2Sweep m_sweepA, m_sweepB;
+	Type m_type;
+	b2Vec2 m_localPoint;
+	b2Vec2 m_axis;
+};
+
+// CCD via the local separating axis method. This seeks progression
+// by computing the largest time at which separation is maintained.
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input)
+{
+	b2Timer timer;
+
+	++b2_toiCalls;
+
+	output->state = b2TOIOutput::e_unknown;
+	output->t = input->tMax;
+
+	const b2DistanceProxy* proxyA = &input->proxyA;
+	const b2DistanceProxy* proxyB = &input->proxyB;
+
+	b2Sweep sweepA = input->sweepA;
+	b2Sweep sweepB = input->sweepB;
+
+	// Large rotations can make the root finder fail, so we normalize the
+	// sweep angles.
+	sweepA.Normalize();
+	sweepB.Normalize();
+
+	float32 tMax = input->tMax;
+
+	float32 totalRadius = proxyA->m_radius + proxyB->m_radius;
+	float32 target = b2Max(b2_linearSlop, totalRadius - 3.0f * b2_linearSlop);
+	float32 tolerance = 0.25f * b2_linearSlop;
+	b2Assert(target > tolerance);
+
+	float32 t1 = 0.0f;
+	const int32 k_maxIterations = 20;	// TODO_ERIN b2Settings
+	int32 iter = 0;
+
+	// Prepare input for distance query.
+	b2SimplexCache cache;
+	cache.count = 0;
+	b2DistanceInput distanceInput;
+	distanceInput.proxyA = input->proxyA;
+	distanceInput.proxyB = input->proxyB;
+	distanceInput.useRadii = false;
+
+	// The outer loop progressively attempts to compute new separating axes.
+	// This loop terminates when an axis is repeated (no progress is made).
+	for(;;)
+	{
+		b2Transform xfA, xfB;
+		sweepA.GetTransform(&xfA, t1);
+		sweepB.GetTransform(&xfB, t1);
+
+		// Get the distance between shapes. We can also use the results
+		// to get a separating axis.
+		distanceInput.transformA = xfA;
+		distanceInput.transformB = xfB;
+		b2DistanceOutput distanceOutput;
+		b2Distance(&distanceOutput, &cache, &distanceInput);
+
+		// If the shapes are overlapped, we give up on continuous collision.
+		if (distanceOutput.distance <= 0.0f)
+		{
+			// Failure!
+			output->state = b2TOIOutput::e_overlapped;
+			output->t = 0.0f;
+			break;
+		}
+
+		if (distanceOutput.distance < target + tolerance)
+		{
+			// Victory!
+			output->state = b2TOIOutput::e_touching;
+			output->t = t1;
+			break;
+		}
+
+		// Initialize the separating axis.
+		b2SeparationFunction fcn;
+		fcn.Initialize(&cache, proxyA, sweepA, proxyB, sweepB, t1);
+#if 0
+		// Dump the curve seen by the root finder
+		{
+			const int32 N = 100;
+			float32 dx = 1.0f / N;
+			float32 xs[N+1];
+			float32 fs[N+1];
+
+			float32 x = 0.0f;
+
+			for (int32 i = 0; i <= N; ++i)
+			{
+				sweepA.GetTransform(&xfA, x);
+				sweepB.GetTransform(&xfB, x);
+				float32 f = fcn.Evaluate(xfA, xfB) - target;
+
+				printf("%g %g\n", x, f);
+
+				xs[i] = x;
+				fs[i] = f;
+
+				x += dx;
+			}
+		}
+#endif
+
+		// Compute the TOI on the separating axis. We do this by successively
+		// resolving the deepest point. This loop is bounded by the number of vertices.
+		bool done = false;
+		float32 t2 = tMax;
+		int32 pushBackIter = 0;
+		for (;;)
+		{
+			// Find the deepest point at t2. Store the witness point indices.
+			int32 indexA, indexB;
+			float32 s2 = fcn.FindMinSeparation(&indexA, &indexB, t2);
+
+			// Is the final configuration separated?
+			if (s2 > target + tolerance)
+			{
+				// Victory!
+				output->state = b2TOIOutput::e_separated;
+				output->t = tMax;
+				done = true;
+				break;
+			}
+
+			// Has the separation reached tolerance?
+			if (s2 > target - tolerance)
+			{
+				// Advance the sweeps
+				t1 = t2;
+				break;
+			}
+
+			// Compute the initial separation of the witness points.
+			float32 s1 = fcn.Evaluate(indexA, indexB, t1);
+
+			// Check for initial overlap. This might happen if the root finder
+			// runs out of iterations.
+			if (s1 < target - tolerance)
+			{
+				output->state = b2TOIOutput::e_failed;
+				output->t = t1;
+				done = true;
+				break;
+			}
+
+			// Check for touching
+			if (s1 <= target + tolerance)
+			{
+				// Victory! t1 should hold the TOI (could be 0.0).
+				output->state = b2TOIOutput::e_touching;
+				output->t = t1;
+				done = true;
+				break;
+			}
+
+			// Compute 1D root of: f(x) - target = 0
+			int32 rootIterCount = 0;
+			float32 a1 = t1, a2 = t2;
+			for (;;)
+			{
+				// Use a mix of the secant rule and bisection.
+				float32 t;
+				if (rootIterCount & 1)
+				{
+					// Secant rule to improve convergence.
+					t = a1 + (target - s1) * (a2 - a1) / (s2 - s1);
+				}
+				else
+				{
+					// Bisection to guarantee progress.
+					t = 0.5f * (a1 + a2);
+				}
+
+				++rootIterCount;
+				++b2_toiRootIters;
+
+				float32 s = fcn.Evaluate(indexA, indexB, t);
+
+				if (b2Abs(s - target) < tolerance)
+				{
+					// t2 holds a tentative value for t1
+					t2 = t;
+					break;
+				}
+
+				// Ensure we continue to bracket the root.
+				if (s > target)
+				{
+					a1 = t;
+					s1 = s;
+				}
+				else
+				{
+					a2 = t;
+					s2 = s;
+				}
+				
+				if (rootIterCount == 50)
+				{
+					break;
+				}
+			}
+
+			b2_toiMaxRootIters = b2Max(b2_toiMaxRootIters, rootIterCount);
+
+			++pushBackIter;
+
+			if (pushBackIter == b2_maxPolygonVertices)
+			{
+				break;
+			}
+		}
+
+		++iter;
+		++b2_toiIters;
+
+		if (done)
+		{
+			break;
+		}
+
+		if (iter == k_maxIterations)
+		{
+			// Root finder got stuck. Semi-victory.
+			output->state = b2TOIOutput::e_failed;
+			output->t = t1;
+			break;
+		}
+	}
+
+	b2_toiMaxIters = b2Max(b2_toiMaxIters, iter);
+
+	float32 time = timer.GetMilliseconds();
+	b2_toiMaxTime = b2Max(b2_toiMaxTime, time);
+	b2_toiTime += time;
+}

+ 58 - 58
engine/source/Box2D/Collision/b2TimeOfImpact.h

@@ -1,58 +1,58 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_TIME_OF_IMPACT_H
-#define B2_TIME_OF_IMPACT_H
-
-#include <Box2D/Common/b2Math.h>
-#include <Box2D/Collision/b2Distance.h>
-
-/// Input parameters for b2TimeOfImpact
-struct b2TOIInput
-{
-	b2DistanceProxy proxyA;
-	b2DistanceProxy proxyB;
-	b2Sweep sweepA;
-	b2Sweep sweepB;
-	float32 tMax;		// defines sweep interval [0, tMax]
-};
-
-// Output parameters for b2TimeOfImpact.
-struct b2TOIOutput
-{
-	enum State
-	{
-		e_unknown,
-		e_failed,
-		e_overlapped,
-		e_touching,
-		e_separated
-	};
-
-	State state;
-	float32 t;
-};
-
-/// Compute the upper bound on time before two shapes penetrate. Time is represented as
-/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
-/// non-tunneling collision. If you change the time interval, you should call this function
-/// again.
-/// Note: use b2Distance to compute the contact point and normal at the time of impact.
-void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_TIME_OF_IMPACT_H
+#define B2_TIME_OF_IMPACT_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Collision/b2Distance.h>
+
+/// Input parameters for b2TimeOfImpact
+struct b2TOIInput
+{
+	b2DistanceProxy proxyA;
+	b2DistanceProxy proxyB;
+	b2Sweep sweepA;
+	b2Sweep sweepB;
+	float32 tMax;		// defines sweep interval [0, tMax]
+};
+
+// Output parameters for b2TimeOfImpact.
+struct b2TOIOutput
+{
+	enum State
+	{
+		e_unknown,
+		e_failed,
+		e_overlapped,
+		e_touching,
+		e_separated
+	};
+
+	State state;
+	float32 t;
+};
+
+/// Compute the upper bound on time before two shapes penetrate. Time is represented as
+/// a fraction between [0,tMax]. This uses a swept separating axis and may miss some intermediate,
+/// non-tunneling collision. If you change the time interval, you should call this function
+/// again.
+/// Note: use b2Distance to compute the contact point and normal at the time of impact.
+void b2TimeOfImpact(b2TOIOutput* output, const b2TOIInput* input);
+
+#endif

+ 225 - 217
engine/source/Box2D/Common/b2BlockAllocator.cpp

@@ -1,217 +1,225 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2BlockAllocator.h>
-#include <cstdlib>
-#include <climits>
-#include <cstring>
-#include <memory>
-using namespace std;
-
-int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] = 
-{
-	16,		// 0
-	32,		// 1
-	64,		// 2
-	96,		// 3
-	128,	// 4
-	160,	// 5
-	192,	// 6
-	224,	// 7
-	256,	// 8
-	320,	// 9
-	384,	// 10
-	448,	// 11
-	512,	// 12
-	640,	// 13
-};
-uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
-bool b2BlockAllocator::s_blockSizeLookupInitialized;
-
-struct b2Chunk
-{
-	int32 blockSize;
-	b2Block* blocks;
-};
-
-struct b2Block
-{
-	b2Block* next;
-};
-
-b2BlockAllocator::b2BlockAllocator()
-{
-	b2Assert(b2_blockSizes < UCHAR_MAX);
-
-	m_chunkSpace = b2_chunkArrayIncrement;
-	m_chunkCount = 0;
-	m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
-	
-	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
-	memset(m_freeLists, 0, sizeof(m_freeLists));
-
-	if (s_blockSizeLookupInitialized == false)
-	{
-		int32 j = 0;
-		for (int32 i = 1; i <= b2_maxBlockSize; ++i)
-		{
-			b2Assert(j < b2_blockSizes);
-			if (i <= s_blockSizes[j])
-			{
-				s_blockSizeLookup[i] = (uint8)j;
-			}
-			else
-			{
-				++j;
-				s_blockSizeLookup[i] = (uint8)j;
-			}
-		}
-
-		s_blockSizeLookupInitialized = true;
-	}
-}
-
-b2BlockAllocator::~b2BlockAllocator()
-{
-	for (int32 i = 0; i < m_chunkCount; ++i)
-	{
-		b2Free(m_chunks[i].blocks);
-	}
-
-	b2Free(m_chunks);
-}
-
-void* b2BlockAllocator::Allocate(int32 size)
-{
-	if (size == 0)
-		return NULL;
-
-	b2Assert(0 < size);
-
-	if (size > b2_maxBlockSize)
-	{
-		return b2Alloc(size);
-	}
-
-	int32 index = s_blockSizeLookup[size];
-	b2Assert(0 <= index && index < b2_blockSizes);
-
-	if (m_freeLists[index])
-	{
-		b2Block* block = m_freeLists[index];
-		m_freeLists[index] = block->next;
-		return block;
-	}
-	else
-	{
-		if (m_chunkCount == m_chunkSpace)
-		{
-			b2Chunk* oldChunks = m_chunks;
-			m_chunkSpace += b2_chunkArrayIncrement;
-			m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
-			memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
-			memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
-			b2Free(oldChunks);
-		}
-
-		b2Chunk* chunk = m_chunks + m_chunkCount;
-		chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
-#if defined(_DEBUG)
-		memset(chunk->blocks, 0xcd, b2_chunkSize);
-#endif
-		int32 blockSize = s_blockSizes[index];
-		chunk->blockSize = blockSize;
-		int32 blockCount = b2_chunkSize / blockSize;
-		b2Assert(blockCount * blockSize <= b2_chunkSize);
-		for (int32 i = 0; i < blockCount - 1; ++i)
-		{
-			b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
-			b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
-			block->next = next;
-		}
-		b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
-		last->next = NULL;
-
-		m_freeLists[index] = chunk->blocks->next;
-		++m_chunkCount;
-
-		return chunk->blocks;
-	}
-}
-
-void b2BlockAllocator::Free(void* p, int32 size)
-{
-	if (size == 0)
-	{
-		return;
-	}
-
-	b2Assert(0 < size);
-
-	if (size > b2_maxBlockSize)
-	{
-		b2Free(p);
-		return;
-	}
-
-	int32 index = s_blockSizeLookup[size];
-	b2Assert(0 <= index && index < b2_blockSizes);
-
-#ifdef _DEBUG
-	// Verify the memory address and size is valid.
-	int32 blockSize = s_blockSizes[index];
-	bool found = false;
-	for (int32 i = 0; i < m_chunkCount; ++i)
-	{
-		b2Chunk* chunk = m_chunks + i;
-		if (chunk->blockSize != blockSize)
-		{
-			b2Assert(	(int8*)p + blockSize <= (int8*)chunk->blocks ||
-						(int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
-		}
-		else
-		{
-			if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
-			{
-				found = true;
-			}
-		}
-	}
-
-	b2Assert(found);
-
-	memset(p, 0xfd, blockSize);
-#endif
-
-	b2Block* block = (b2Block*)p;
-	block->next = m_freeLists[index];
-	m_freeLists[index] = block;
-}
-
-void b2BlockAllocator::Clear()
-{
-	for (int32 i = 0; i < m_chunkCount; ++i)
-	{
-		b2Free(m_chunks[i].blocks);
-	}
-
-	m_chunkCount = 0;
-	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
-
-	memset(m_freeLists, 0, sizeof(m_freeLists));
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <limits.h>
+#include <memory.h>
+#include <stddef.h>
+#include <string.h>
+#include <new> // For placement new
+
+int32 b2BlockAllocator::s_blockSizes[b2_blockSizes] =
+{
+	16,		// 0
+	32,		// 1
+	64,		// 2
+	96,		// 3
+	128,	// 4
+	160,	// 5
+	192,	// 6
+	224,	// 7
+	256,	// 8
+	320,	// 9
+	384,	// 10
+	448,	// 11
+	512,	// 12
+	640,	// 13
+};
+uint8 b2BlockAllocator::s_blockSizeLookup[b2_maxBlockSize + 1];
+bool b2BlockAllocator::s_blockSizeLookupInitialized;
+
+struct b2Chunk
+{
+	int32 blockSize;
+	b2Block* blocks;
+};
+
+struct b2Block
+{
+	b2Block* next;
+};
+
+b2BlockAllocator::b2BlockAllocator()
+{
+	b2Assert((uint32)b2_blockSizes < UCHAR_MAX);
+
+	m_chunkSpace = b2_chunkArrayIncrement;
+	m_chunkCount = 0;
+	m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
+
+	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
+	memset(m_freeLists, 0, sizeof(m_freeLists));
+
+	if (s_blockSizeLookupInitialized == false)
+	{
+		int32 j = 0;
+		for (int32 i = 1; i <= b2_maxBlockSize; ++i)
+		{
+			b2Assert(j < b2_blockSizes);
+			if (i <= s_blockSizes[j])
+			{
+				s_blockSizeLookup[i] = (uint8)j;
+			}
+			else
+			{
+				++j;
+				s_blockSizeLookup[i] = (uint8)j;
+			}
+		}
+
+		s_blockSizeLookupInitialized = true;
+	}
+}
+
+b2BlockAllocator::~b2BlockAllocator()
+{
+	for (int32 i = 0; i < m_chunkCount; ++i)
+	{
+		b2Free(m_chunks[i].blocks);
+	}
+
+	b2Free(m_chunks);
+}
+
+uint32 b2BlockAllocator::GetNumGiantAllocations() const
+{
+	return m_giants.GetList().GetLength();
+}
+
+void* b2BlockAllocator::Allocate(int32 size)
+{
+	if (size == 0)
+		return NULL;
+
+	b2Assert(0 < size);
+
+	if (size > b2_maxBlockSize)
+	{
+		return m_giants.Allocate(size);
+	}
+
+	int32 index = s_blockSizeLookup[size];
+	b2Assert(0 <= index && index < b2_blockSizes);
+
+	if (m_freeLists[index])
+	{
+		b2Block* block = m_freeLists[index];
+		m_freeLists[index] = block->next;
+		return block;
+	}
+	else
+	{
+		if (m_chunkCount == m_chunkSpace)
+		{
+			b2Chunk* oldChunks = m_chunks;
+			m_chunkSpace += b2_chunkArrayIncrement;
+			m_chunks = (b2Chunk*)b2Alloc(m_chunkSpace * sizeof(b2Chunk));
+			memcpy(m_chunks, oldChunks, m_chunkCount * sizeof(b2Chunk));
+			memset(m_chunks + m_chunkCount, 0, b2_chunkArrayIncrement * sizeof(b2Chunk));
+			b2Free(oldChunks);
+		}
+
+		b2Chunk* chunk = m_chunks + m_chunkCount;
+		chunk->blocks = (b2Block*)b2Alloc(b2_chunkSize);
+#if DEBUG
+		memset(chunk->blocks, 0xcd, b2_chunkSize);
+#endif
+		int32 blockSize = s_blockSizes[index];
+		chunk->blockSize = blockSize;
+		int32 blockCount = b2_chunkSize / blockSize;
+		b2Assert(blockCount * blockSize <= b2_chunkSize);
+		for (int32 i = 0; i < blockCount - 1; ++i)
+		{
+			b2Block* block = (b2Block*)((int8*)chunk->blocks + blockSize * i);
+			b2Block* next = (b2Block*)((int8*)chunk->blocks + blockSize * (i + 1));
+			block->next = next;
+		}
+		b2Block* last = (b2Block*)((int8*)chunk->blocks + blockSize * (blockCount - 1));
+		last->next = NULL;
+
+		m_freeLists[index] = chunk->blocks->next;
+		++m_chunkCount;
+
+		return chunk->blocks;
+	}
+}
+
+void b2BlockAllocator::Free(void* p, int32 size)
+{
+	if (size == 0)
+	{
+		return;
+	}
+
+	b2Assert(0 < size);
+
+	if (size > b2_maxBlockSize)
+	{
+		m_giants.Free(p);
+		return;
+	}
+
+	int32 index = s_blockSizeLookup[size];
+	b2Assert(0 <= index && index < b2_blockSizes);
+
+#if B2_ASSERT_ENABLED
+	// Verify the memory address and size is valid.
+	int32 blockSize = s_blockSizes[index];
+	bool found = false;
+	for (int32 i = 0; i < m_chunkCount; ++i)
+	{
+		b2Chunk* chunk = m_chunks + i;
+		if (chunk->blockSize != blockSize)
+		{
+			b2Assert(	(int8*)p + blockSize <= (int8*)chunk->blocks ||
+						(int8*)chunk->blocks + b2_chunkSize <= (int8*)p);
+		}
+		else
+		{
+			if ((int8*)chunk->blocks <= (int8*)p && (int8*)p + blockSize <= (int8*)chunk->blocks + b2_chunkSize)
+			{
+				found = true;
+			}
+		}
+	}
+
+	b2Assert(found);
+#endif // B2_ASSERT_ENABLED
+
+#if DEBUG
+	memset(p, 0xfd, s_blockSizes[index]);
+#endif
+
+	b2Block* block = (b2Block*)p;
+	block->next = m_freeLists[index];
+	m_freeLists[index] = block;
+}
+
+void b2BlockAllocator::Clear()
+{
+	for (int32 i = 0; i < m_chunkCount; ++i)
+	{
+		b2Free(m_chunks[i].blocks);
+	}
+
+	m_chunkCount = 0;
+	memset(m_chunks, 0, m_chunkSpace * sizeof(b2Chunk));
+
+	memset(m_freeLists, 0, sizeof(m_freeLists));
+}

+ 68 - 62
engine/source/Box2D/Common/b2BlockAllocator.h

@@ -1,62 +1,68 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_BLOCK_ALLOCATOR_H
-#define B2_BLOCK_ALLOCATOR_H
-
-#include <Box2D/Common/b2Settings.h>
-
-const int32 b2_chunkSize = 16 * 1024;
-const int32 b2_maxBlockSize = 640;
-const int32 b2_blockSizes = 14;
-const int32 b2_chunkArrayIncrement = 128;
-
-struct b2Block;
-struct b2Chunk;
-
-/// This is a small object allocator used for allocating small
-/// objects that persist for more than one time step.
-/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
-class b2BlockAllocator
-{
-public:
-	b2BlockAllocator();
-	~b2BlockAllocator();
-
-	/// Allocate memory. This will use b2Alloc if the size is larger than b2_maxBlockSize.
-	void* Allocate(int32 size);
-
-	/// Free memory. This will use b2Free if the size is larger than b2_maxBlockSize.
-	void Free(void* p, int32 size);
-
-	void Clear();
-
-private:
-
-	b2Chunk* m_chunks;
-	int32 m_chunkCount;
-	int32 m_chunkSpace;
-
-	b2Block* m_freeLists[b2_blockSizes];
-
-	static int32 s_blockSizes[b2_blockSizes];
-	static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
-	static bool s_blockSizeLookupInitialized;
-};
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_BLOCK_ALLOCATOR_H
+#define B2_BLOCK_ALLOCATOR_H
+
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Common/b2TrackedBlock.h>
+
+const int32 b2_chunkSize = 16 * 1024;
+const int32 b2_maxBlockSize = 640;
+const int32 b2_blockSizes = 14;
+const int32 b2_chunkArrayIncrement = 128;
+
+struct b2Block;
+struct b2Chunk;
+
+/// This is a small object allocator used for allocating small
+/// objects that persist for more than one time step.
+/// See: http://www.codeproject.com/useritems/Small_Block_Allocator.asp
+class b2BlockAllocator
+{
+public:
+	b2BlockAllocator();
+	~b2BlockAllocator();
+
+	/// Allocate memory. This uses b2Alloc if the size is larger than b2_maxBlockSize.
+	void* Allocate(int32 size);
+
+	/// Free memory. This uses b2Free if the size is larger than b2_maxBlockSize.
+	void Free(void* p, int32 size);
+
+	void Clear();
+
+	/// Returns the number of allocations larger than the max block size.
+	uint32 GetNumGiantAllocations() const;
+
+private:
+	b2Chunk* m_chunks;
+	int32 m_chunkCount;
+	int32 m_chunkSpace;
+
+	b2Block* m_freeLists[b2_blockSizes];
+
+	// Record giant allocations--ones bigger than the max block size
+	b2TrackedBlockAllocator m_giants;
+
+	static int32 s_blockSizes[b2_blockSizes];
+	static uint8 s_blockSizeLookup[b2_maxBlockSize + 1];
+	static bool s_blockSizeLookupInitialized;
+};
+
+#endif

+ 44 - 44
engine/source/Box2D/Common/b2Draw.cpp

@@ -1,44 +1,44 @@
-/*
-* Copyright (c) 2011 Erin Catto http://box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2Draw.h>
-
-b2Draw::b2Draw()
-{
-	m_drawFlags = 0;
-}
-
-void b2Draw::SetFlags(uint32 flags)
-{
-	m_drawFlags = flags;
-}
-
-uint32 b2Draw::GetFlags() const
-{
-	return m_drawFlags;
-}
-
-void b2Draw::AppendFlags(uint32 flags)
-{
-	m_drawFlags |= flags;
-}
-
-void b2Draw::ClearFlags(uint32 flags)
-{
-	m_drawFlags &= ~flags;
-}
+/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Draw.h>
+
+b2Draw::b2Draw()
+{
+	m_drawFlags = 0;
+}
+
+void b2Draw::SetFlags(uint32 flags)
+{
+	m_drawFlags = flags;
+}
+
+uint32 b2Draw::GetFlags() const
+{
+	return m_drawFlags;
+}
+
+void b2Draw::AppendFlags(uint32 flags)
+{
+	m_drawFlags |= flags;
+}
+
+void b2Draw::ClearFlags(uint32 flags)
+{
+	m_drawFlags &= ~flags;
+}

+ 92 - 86
engine/source/Box2D/Common/b2Draw.h

@@ -1,86 +1,92 @@
-/*
-* Copyright (c) 2011 Erin Catto http://box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_DRAW_H
-#define B2_DRAW_H
-
-#include <Box2D/Common/b2Math.h>
-
-/// Color for debug drawing. Each value has the range [0,1].
-struct b2Color
-{
-	b2Color() {}
-	b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
-	void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
-	float32 r, g, b;
-};
-
-/// Implement and register this class with a b2World to provide debug drawing of physics
-/// entities in your game.
-class b2Draw
-{
-public:
-	b2Draw();
-
-	virtual ~b2Draw() {}
-
-	enum
-	{
-		e_shapeBit				= 0x0001,	///< draw shapes
-		e_jointBit				= 0x0002,	///< draw joint connections
-		e_aabbBit				= 0x0004,	///< draw axis aligned bounding boxes
-		e_pairBit				= 0x0008,	///< draw broad-phase pairs
-		e_centerOfMassBit		= 0x0010	///< draw center of mass frame
-	};
-
-	/// Set the drawing flags.
-	void SetFlags(uint32 flags);
-
-	/// Get the drawing flags.
-	uint32 GetFlags() const;
-	
-	/// Append flags to the current flags.
-	void AppendFlags(uint32 flags);
-
-	/// Clear flags from the current flags.
-	void ClearFlags(uint32 flags);
-
-	/// Draw a closed polygon provided in CCW order.
-	virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
-
-	/// Draw a solid closed polygon provided in CCW order.
-	virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
-
-	/// Draw a circle.
-	virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
-	
-	/// Draw a solid circle.
-	virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
-	
-	/// Draw a line segment.
-	virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
-
-	/// Draw a transform. Choose your own length scale.
-	/// @param xf a transform.
-	virtual void DrawTransform(const b2Transform& xf) = 0;
-
-protected:
-	uint32 m_drawFlags;
-};
-
-#endif
+/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_DRAW_H
+#define B2_DRAW_H
+
+#include <Box2D/Common/b2Math.h>
+#include <Box2D/Particle/b2Particle.h>
+
+/// Color for debug drawing. Each value has the range [0,1].
+struct b2Color
+{
+	b2Color() {}
+	b2Color(float32 r, float32 g, float32 b) : r(r), g(g), b(b) {}
+	void Set(float32 ri, float32 gi, float32 bi) { r = ri; g = gi; b = bi; }
+	float32 r, g, b;
+};
+
+/// Implement and register this class with a b2World to provide debug drawing of physics
+/// entities in your game.
+class b2Draw
+{
+public:
+	b2Draw();
+
+	virtual ~b2Draw() {}
+
+	enum
+	{
+		e_shapeBit				= 0x0001,	///< draw shapes
+		e_jointBit				= 0x0002,	///< draw joint connections
+		e_aabbBit				= 0x0004,	///< draw axis aligned bounding boxes
+		e_pairBit				= 0x0008,	///< draw broad-phase pairs
+		e_centerOfMassBit			= 0x0010,	///< draw center of mass frame
+		e_particleBit				= 0x0020  ///< draw particles
+	};
+
+	/// Set the drawing flags.
+	void SetFlags(uint32 flags);
+
+	/// Get the drawing flags.
+	uint32 GetFlags() const;
+
+	/// Append flags to the current flags.
+	void AppendFlags(uint32 flags);
+
+	/// Clear flags from the current flags.
+	void ClearFlags(uint32 flags);
+
+	/// Draw a closed polygon provided in CCW order.
+	virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
+
+	/// Draw a solid closed polygon provided in CCW order.
+	virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color) = 0;
+
+	/// Draw a circle.
+	virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) = 0;
+
+	/// Draw a solid circle.
+	virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) = 0;
+
+	/// Draw a particle array
+	virtual void DrawParticles(const b2Vec2 *centers, float32 radius, const b2ParticleColor *colors, int32 count) = 0;
+
+	/// Draw a line segment.
+	virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) = 0;
+
+	/// Draw a transform. Choose your own length scale.
+	/// @param xf a transform.
+	virtual void DrawTransform(const b2Transform& xf) = 0;
+
+protected:
+	uint32 m_drawFlags;
+};
+
+#endif

+ 57 - 0
engine/source/Box2D/Common/b2FreeList.cpp

@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#include <Box2D/Common/b2FreeList.h>
+#include <Box2D/Common/b2IntrusiveList.h>
+#include <Box2D/Common/b2Settings.h>
+
+/// Allocate an item from the freelist.
+b2IntrusiveListNode* b2FreeList::Allocate()
+{
+	if (m_free.IsEmpty()) return NULL;
+	b2IntrusiveListNode * const node = m_free.GetNext();
+	node->Remove();
+	m_allocated.InsertBefore(node);
+	return node;
+}
+
+void b2FreeList::Free(b2IntrusiveListNode* node)
+{
+	b2Assert(node);
+#if B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE
+	b2Assert(m_allocated.FindNodeInList(node));
+#endif // B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE
+	node->Remove();
+	m_free.InsertAfter(node);
+}
+
+void b2FreeList::AddToFreeList(b2IntrusiveListNode* node)
+{
+	b2Assert(node);
+	b2Assert(!node->InList());
+	m_free.InsertBefore(node);
+}
+
+void b2FreeList::RemoveAll()
+{
+	while (!m_allocated.IsEmpty()) {
+		m_allocated.GetNext()->Remove();
+	}
+	while (!m_free.IsEmpty()) {
+		m_free.GetNext()->Remove();
+	}
+}

+ 113 - 0
engine/source/Box2D/Common/b2FreeList.h

@@ -0,0 +1,113 @@
+/*
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef B2_FREE_LIST_H
+#define B2_FREE_LIST_H
+
+#include <Box2D/Common/b2IntrusiveList.h>
+#include <Box2D/Common/b2Settings.h>
+
+/// When B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE is 1, b2FreeList::Free() will
+/// check that the deallocated node was allocated from the freelist.
+#ifndef B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE
+#define B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE 0
+#endif // B2_FREE_LIST_CHECK_ALLOCATED_ON_FREE
+
+
+/// Fast - O(1) - list based allocator for items that can be inserted into
+/// b2IntrusiveListNode lists.
+class b2FreeList
+{
+public:
+	/// Construct the free list.
+	b2FreeList() { }
+
+	/// Destroy the free list.
+	~b2FreeList() { }
+
+	/// Allocate an item from the freelist.
+	b2IntrusiveListNode* Allocate();
+
+	/// Free an item from the freelist.
+	void Free(b2IntrusiveListNode* node);
+
+	/// Add an item to the freelist so that it can be allocated using
+	/// b2FreeList::Allocate().
+	void AddToFreeList(b2IntrusiveListNode* node);
+
+	/// Remove all items (allocated and free) from the freelist.
+	void RemoveAll();
+
+	/// Get the list which tracks allocated items.
+	const b2IntrusiveListNode& GetAllocatedList() const {
+		return m_allocated;
+	}
+
+	/// Get the list which tracks free items.
+	const b2IntrusiveListNode& GetFreeList() const {
+		return m_free;
+	}
+
+protected:
+	/// List of allocated items.
+	b2IntrusiveListNode m_allocated;
+	/// List of free items.
+	b2IntrusiveListNode m_free;
+};
+
+
+/// Typed b2FreeList which manages items of type T assuming T implements
+/// the GetInstanceFromListNode() and GetListNode() methods.
+template<typename T>
+class b2TypedFreeList {
+public:
+	/// Construct the free list.
+	b2TypedFreeList() { }
+
+	/// Destroy the free list.
+	~b2TypedFreeList() { }
+
+	/// Allocate an item from the free list.
+	T* Allocate() {
+		b2IntrusiveListNode* const node = m_freeList.Allocate();
+		if (!node) return NULL;
+		return T::GetInstanceFromListNode(node);
+	}
+
+	/// Free an item.
+	void Free(T* instance) {
+		b2Assert(instance);
+		m_freeList.Free(instance->GetListNode());
+	}
+
+	/// Add an item to the freelist so that it can be allocated with
+	/// b2TypedFreeList::Allocate().
+	void AddToFreeList(T* instance)
+	{
+		b2Assert(instance);
+		m_freeList.AddToFreeList(instance->GetListNode());
+	}
+
+	// Get the underlying b2FreeList.
+	b2FreeList* GetFreeList() { return &m_freeList; }
+	const b2FreeList* GetFreeList() const { return &m_freeList; }
+
+protected:
+	b2FreeList m_freeList;
+};
+
+#endif  // B2_FREE_LIST_H

+ 200 - 0
engine/source/Box2D/Common/b2GrowableBuffer.h

@@ -0,0 +1,200 @@
+/*
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef B2_GROWABLE_BUFFER_H
+#define B2_GROWABLE_BUFFER_H
+
+#include <Box2D/Common/b2BlockAllocator.h>
+#include <string.h>
+#include <memory.h>
+#include <algorithm>
+
+
+/// A simple array-like container, similar to std::vector.
+/// If we ever start using stl, we should replace this with std::vector.
+template <typename T>
+class b2GrowableBuffer
+{
+public:
+	b2GrowableBuffer(b2BlockAllocator& allocator) :
+		data(NULL),
+		count(0),
+		capacity(0),
+		allocator(&allocator)
+	{
+	#if defined(LIQUIDFUN_SIMD_NEON)
+		// b2ParticleAssemply.neon.s assumes these values are at fixed offsets.
+        // If this assert fails, be sure to update the assembly offsets!
+		// ldr r3, [r9, #0] @ r3 = out = contacts.data
+        // ldr r6, [r9, #8] @ r6 = contacts.capacity
+		b2Assert((intptr_t)&data - (intptr_t)(this) == 0
+			  && (intptr_t)&capacity - (intptr_t)(this) == 8);
+	#endif // defined(LIQUIDFUN_SIMD_NEON)
+	}
+
+	b2GrowableBuffer(const b2GrowableBuffer<T>& rhs) :
+		data(NULL),
+		count(rhs.count),
+		capacity(rhs.capacity),
+		allocator(rhs.allocator)
+	{
+		if (rhs.data != NULL)
+		{
+			data = (T*) allocator->Allocate(sizeof(T) * capacity);
+			memcpy(data, rhs.data, sizeof(T) * count);
+		}
+	}
+
+	~b2GrowableBuffer()
+	{
+		Free();
+	}
+
+	T& Append()
+	{
+		if (count >= capacity)
+		{
+			Grow();
+		}
+		return data[count++];
+	}
+
+	void Reserve(int32 newCapacity)
+	{
+		if (capacity >= newCapacity)
+			return;
+
+		// Reallocate and copy.
+		T* newData = (T*) allocator->Allocate(sizeof(T) * newCapacity);
+		if (data)
+		{
+			memcpy(newData, data, sizeof(T) * count);
+			allocator->Free(data, sizeof(T) * capacity);
+		}
+
+		// Update pointer and capacity.
+		capacity = newCapacity;
+		data = newData;
+	}
+
+	void Grow()
+	{
+		// Double the capacity.
+		int32 newCapacity = capacity ? 2 * capacity
+						  : b2_minParticleSystemBufferCapacity;
+		b2Assert(newCapacity > capacity);
+		Reserve(newCapacity);
+	}
+
+	void Free()
+	{
+		if (data == NULL)
+			return;
+
+		allocator->Free(data, sizeof(data[0]) * capacity);
+		data = NULL;
+		capacity = 0;
+		count = 0;
+	}
+
+	void Shorten(const T* newEnd)
+	{
+		b2Assert(newEnd >= data);
+		count = (int32) (newEnd - data);
+	}
+
+	T& operator[](int i)
+	{
+		return data[i];
+	}
+
+	const T& operator[](int i) const
+	{
+		return data[i];
+	}
+
+	T* Data()
+	{
+		return data;
+	}
+
+	const T* Data() const
+	{
+		return data;
+	}
+
+	T* Begin()
+	{
+		return data;
+	}
+
+	const T* Begin() const
+	{
+		return data;
+	}
+
+	T* End()
+	{
+		return &data[count];
+	}
+
+	const T* End() const
+	{
+		return &data[count];
+	}
+
+	int32 GetCount() const
+	{
+		return count;
+	}
+
+	void SetCount(int32 newCount)
+	{
+		b2Assert(0 <= newCount && newCount <= capacity);
+		count = newCount;
+	}
+
+	int32 GetCapacity() const
+	{
+		return capacity;
+	}
+
+	template<class UnaryPredicate>
+	T* RemoveIf(UnaryPredicate pred)
+	{
+		T* newEnd = std::remove_if(data, data + count, pred);
+		Shorten(newEnd);
+		return newEnd;
+	}
+
+	template<class BinaryPredicate>
+	T* Unique(BinaryPredicate pred)
+	{
+		T* newEnd = std::unique(data, data + count, pred);
+		Shorten(newEnd);
+		return newEnd;
+	}
+
+private:
+	T* data;
+	int32 count;
+	int32 capacity;
+	b2BlockAllocator* allocator;
+};
+
+#endif // B2_GROWABLE_BUFFER_H
+

+ 87 - 85
engine/source/Box2D/Common/b2GrowableStack.h

@@ -1,85 +1,87 @@
-/*
-* Copyright (c) 2010 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_GROWABLE_STACK_H
-#define B2_GROWABLE_STACK_H
-#include <Box2D/Common/b2Settings.h>
-#include <cstring>
-
-/// This is a growable LIFO stack with an initial capacity of N.
-/// If the stack size exceeds the initial capacity, the heap is used
-/// to increase the size of the stack.
-template <typename T, int32 N>
-class b2GrowableStack
-{
-public:
-	b2GrowableStack()
-	{
-		m_stack = m_array;
-		m_count = 0;
-		m_capacity = N;
-	}
-
-	~b2GrowableStack()
-	{
-		if (m_stack != m_array)
-		{
-			b2Free(m_stack);
-			m_stack = NULL;
-		}
-	}
-
-	void Push(const T& element)
-	{
-		if (m_count == m_capacity)
-		{
-			T* old = m_stack;
-			m_capacity *= 2;
-			m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
-			std::memcpy(m_stack, old, m_count * sizeof(T));
-			if (old != m_array)
-			{
-				b2Free(old);
-			}
-		}
-
-		m_stack[m_count] = element;
-		++m_count;
-	}
-
-	T Pop()
-	{
-		b2Assert(m_count > 0);
-		--m_count;
-		return m_stack[m_count];
-	}
-
-	int32 GetCount()
-	{
-		return m_count;
-	}
-
-private:
-	T* m_stack;
-	T m_array[N];
-	int32 m_count;
-	int32 m_capacity;
-};
-
-
-#endif
+/*
+* Copyright (c) 2010 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_GROWABLE_STACK_H
+#define B2_GROWABLE_STACK_H
+
+#include <Box2D/Common/b2Settings.h>
+#include <string.h>
+#include <memory.h>
+
+/// This is a growable LIFO stack with an initial capacity of N.
+/// If the stack size exceeds the initial capacity, the heap is used
+/// to increase the size of the stack.
+template <typename T, int32 N>
+class b2GrowableStack
+{
+public:
+	b2GrowableStack()
+	{
+		m_stack = m_array;
+		m_count = 0;
+		m_capacity = N;
+	}
+
+	~b2GrowableStack()
+	{
+		if (m_stack != m_array)
+		{
+			b2Free(m_stack);
+			m_stack = NULL;
+		}
+	}
+
+	void Push(const T& element)
+	{
+		if (m_count == m_capacity)
+		{
+			T* old = m_stack;
+			m_capacity *= 2;
+			m_stack = (T*)b2Alloc(m_capacity * sizeof(T));
+			memcpy(m_stack, old, m_count * sizeof(T));
+			if (old != m_array)
+			{
+				b2Free(old);
+			}
+		}
+
+		m_stack[m_count] = element;
+		++m_count;
+	}
+
+	T Pop()
+	{
+		b2Assert(m_count > 0);
+		--m_count;
+		return m_stack[m_count];
+	}
+
+	int32 GetCount()
+	{
+		return m_count;
+	}
+
+private:
+	T* m_stack;
+	T m_array[N];
+	int32 m_count;
+	int32 m_capacity;
+};
+
+
+#endif

+ 369 - 0
engine/source/Box2D/Common/b2IntrusiveList.h

@@ -0,0 +1,369 @@
+/*
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef B2_INTRUSIVE_LIST
+#define B2_INTRUSIVE_LIST
+
+#include <Box2D/Common/b2Settings.h>
+
+// Whether to enable b2IntrusiveList::ValidateList().
+// Be careful when enabling this since this changes the size of
+// b2IntrusiveListNode so make sure *all* projects that include Box2D.h
+// also define this value in the same way to avoid data corruption.
+#ifndef B2_INTRUSIVE_LIST_VALIDATE
+#define B2_INTRUSIVE_LIST_VALIDATE 0
+#endif  // B2_INTRUSIVE_LIST_VALIDATE
+
+/// b2IntrusiveListNode is used to implement an intrusive doubly-linked
+/// list.
+///
+/// For example:
+///
+/// class MyClass {
+/// public:
+/// 	MyClass(const char *msg) : m_msg(msg) {}
+/// 	const char* GetMessage() const { return m_msg; }
+/// 	B2_INTRUSIVE_LIST_GET_NODE(m_node);
+/// 	B2_INTRUSIVE_LIST_NODE_GET_CLASS(MyClass, m_node);
+/// private:
+/// 	b2IntrusiveListNode m_node;
+/// 	const char *m_msg;
+/// };
+///
+/// int main(int argc, char *argv[]) {
+/// 	b2IntrusiveListNode list; // NOTE: type is NOT MyClass
+/// 	MyClass a("this");
+/// 	MyClass b("is");
+/// 	MyClass c("a");
+/// 	MyClass d("test");
+/// 	list.InsertBefore(a.GetListNode());
+/// 	list.InsertBefore(b.GetListNode());
+/// 	list.InsertBefore(c.GetListNode());
+/// 	list.InsertBefore(d.GetListNode());
+/// 	for (b2IntrusiveListNode* node = list.GetNext();
+/// 		 node != list.GetTerminator(); node = node->GetNext()) {
+/// 		MyClass *cls = MyClass::GetInstanceFromListNode(node);
+/// 		printf("%s\n", cls->GetMessage());
+/// 	}
+/// 	return 0;
+/// }
+class b2IntrusiveListNode
+{
+public:
+	/// Initialize the node.
+	b2IntrusiveListNode()
+	{
+		Initialize();
+#if B2_INTRUSIVE_LIST_VALIDATE
+		m_magic = k_magic;
+#endif // B2_INTRUSIVE_LIST_VALIDATE
+	}
+
+	/// If the node is in a list, remove it from the list.
+	~b2IntrusiveListNode()
+	{
+		Remove();
+#if B2_INTRUSIVE_LIST_VALIDATE
+		m_magic = 0;
+#endif // B2_INTRUSIVE_LIST_VALIDATE
+	}
+
+	/// Insert this node after the specified node.
+	void InsertAfter(b2IntrusiveListNode* const node)
+	{
+		b2Assert(!node->InList());
+		node->m_next = m_next;
+		node->m_prev = this;
+		m_next->m_prev = node;
+		m_next = node;
+	}
+
+	/// Insert this node before the specified node.
+	void InsertBefore(b2IntrusiveListNode* const node)
+	{
+		b2Assert(!node->InList());
+		node->m_next = this;
+		node->m_prev = m_prev;
+		m_prev->m_next = node;
+		m_prev = node;
+	}
+
+	/// Get the terminator of the list.
+	const b2IntrusiveListNode* GetTerminator() const
+	{
+		return this;
+	}
+
+	/// Remove this node from the list it's currently in.
+	b2IntrusiveListNode* Remove()
+	{
+		m_prev->m_next = m_next;
+		m_next->m_prev = m_prev;
+		Initialize();
+		return this;
+	}
+
+	/// Determine whether this list is empty or the node isn't in a list.
+	bool IsEmpty() const
+	{
+	  return GetNext() == this;
+	}
+
+	/// Determine whether this node is in a list or the list contains nodes.
+	bool InList() const
+	{
+	  return !IsEmpty();
+	}
+
+	/// Calculate the length of the list.
+	uint32 GetLength() const
+	{
+		uint32 length = 0;
+		const b2IntrusiveListNode * const terminator = GetTerminator();
+		for (const b2IntrusiveListNode* node = GetNext();
+			 node != terminator; node = node->GetNext())
+		{
+			length++;
+		}
+		return length;
+	}
+
+	/// Get the next node in the list.
+	b2IntrusiveListNode* GetNext() const
+	{
+		return m_next;
+	}
+
+	/// Get the previous node in the list.
+	b2IntrusiveListNode* GetPrevious() const
+	{
+		return m_prev;
+	}
+
+	/// If B2_INTRUSIVE_LIST_VALIDATE is 1 perform a very rough validation
+	/// of all nodes in the list.
+	bool ValidateList() const
+	{
+#if B2_INTRUSIVE_LIST_VALIDATE
+	  if (m_magic != k_magic) return false;
+	  const b2IntrusiveListNode * const terminator = GetTerminator();
+	  for (b2IntrusiveListNode *node = GetNext(); node != terminator;
+		   node = node->GetNext()) {
+		if (node->m_magic != k_magic) return false;
+	  }
+#endif  // B2_INTRUSIVE_LIST_VALIDATE
+	  return true;
+	}
+
+	/// Determine whether the specified node is present in this list.
+	bool FindNodeInList(b2IntrusiveListNode* const nodeToFind) const
+	{
+		const b2IntrusiveListNode * const terminator = GetTerminator();
+		for (b2IntrusiveListNode *node = GetNext(); node != terminator;
+			 node = node->GetNext())
+		{
+			if (nodeToFind == node) return true;
+		}
+		return false;
+	}
+
+private:
+	/// Initialize the list node.
+	void Initialize()
+	{
+		m_next = this;
+		m_prev = this;
+	}
+
+private:
+#if B2_INTRUSIVE_LIST_VALIDATE
+	uint32 m_magic;
+#endif  // B2_INTRUSIVE_LIST_VALIDATE
+	/// The next node in the list.
+	b2IntrusiveListNode *m_prev;
+	/// The previous node in the list.
+	b2IntrusiveListNode *m_next;
+
+private:
+#if B2_INTRUSIVE_LIST_VALIDATE
+	static const uint32 k_magic = 0x7157ac01;
+#endif  // B2_INTRUSIVE_LIST_VALIDATE
+};
+
+/// Declares the member function GetListNode() of Class to retrieve a pointer
+/// to NodeMemberName.
+/// See #B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR()
+#define B2_INTRUSIVE_LIST_GET_NODE(NodeMemberName) \
+	b2IntrusiveListNode* GetListNode() { return &NodeMemberName; } \
+	const b2IntrusiveListNode* GetListNode() const { return &NodeMemberName; }
+
+/// Declares the member function FunctionName of Class to retrieve a pointer
+/// to a Class instance from a list node pointer.   NodeMemberName references
+/// the name of the b2IntrusiveListNode member of Class.
+#define B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR( \
+	Class, NodeMemberName, FunctionName) \
+	static Class* FunctionName(b2IntrusiveListNode *node) \
+	{ \
+		Class *cls = NULL; \
+		/* This effectively performs offsetof(Class, NodeMemberName) */ \
+		/* which ends up in the undefined behavior realm of C++ but in */ \
+		/* practice this works with most compilers. */ \
+		return reinterpret_cast<Class*>((uint8*)(node) - \
+										(uint8*)(&cls->NodeMemberName)); \
+	} \
+	\
+	static const Class* FunctionName(const b2IntrusiveListNode *node) \
+	{ \
+		return FunctionName(const_cast<b2IntrusiveListNode*>(node)); \
+	}
+
+/// Declares the member function GetInstanceFromListNode() of Class to retrieve
+/// a pointer to a Class instance from a list node pointer.  NodeMemberName
+/// reference the name of the b2IntrusiveListNode member of Class.
+#define B2_INTRUSIVE_LIST_NODE_GET_CLASS(Class, NodeMemberName) \
+	B2_INTRUSIVE_LIST_NODE_GET_CLASS_ACCESSOR(Class, NodeMemberName, \
+											  GetInstanceFromListNode)
+
+/// b2TypedIntrusiveListNode which supports inserting an object into a single
+/// doubly linked list.  For objects that need to be inserted in multiple
+/// doubly linked lists, use b2IntrusiveListNode.
+///
+/// For example:
+///
+/// class IntegerItem : public b2TypedIntrusiveListNode<IntegerItem>
+/// {
+/// public:
+/// 	IntegerItem(int32 value) : m_value(value) { }
+/// 	~IntegerItem() { }
+/// 	int32 GetValue() const { return m_value; }
+/// private:
+/// 	int32 m_value;
+/// };
+///
+/// int main(int argc, const char *arvg[]) {
+/// 	b2TypedIntrusiveListNode<IntegerItem> list;
+/// 	IntegerItem a(1);
+/// 	IntegerItem b(2);
+/// 	IntegerItem c(3);
+/// 	list.InsertBefore(&a);
+/// 	list.InsertBefore(&b);
+/// 	list.InsertBefore(&c);
+/// 	for (IntegerItem* item = list.GetNext();
+/// 		 item != list.GetTerminator(); item = item->GetNext())
+/// 	{
+/// 		printf("%d\n", item->GetValue());
+/// 	}
+/// }
+template<typename T>
+class b2TypedIntrusiveListNode
+{
+public:
+	b2TypedIntrusiveListNode() { }
+	~b2TypedIntrusiveListNode() { }
+
+	/// Insert this object after the specified object.
+	void InsertAfter(T* const obj)
+	{
+		b2Assert(obj);
+		GetListNode()->InsertAfter(obj->GetListNode());
+	}
+
+	/// Insert this object before the specified object.
+	void InsertBefore(T* const obj)
+	{
+		b2Assert(obj);
+		GetListNode()->InsertBefore(obj->GetListNode());
+	}
+
+	/// Get the next object in the list.
+	/// Check against GetTerminator() before deferencing the object.
+	T* GetNext() const
+	{
+		return GetInstanceFromListNode(GetListNode()->GetNext());
+	}
+
+	/// Get the previous object in the list.
+	/// Check against GetTerminator() before deferencing the object.
+	T* GetPrevious() const
+	{
+		return GetInstanceFromListNode(GetListNode()->GetPrevious());
+	}
+
+	/// Get the terminator of the list.
+	/// This should not be dereferenced as it is a pointer to
+	/// b2TypedIntrusiveListNode<T> *not* T.
+	T* GetTerminator() const
+	{
+		return (T*)GetListNode();
+	}
+
+	/// Remove this object from the list it's currently in.
+	T* Remove()
+	{
+		GetListNode()->Remove();
+		return GetInstanceFromListNode(GetListNode());
+	}
+
+	/// Determine whether this object is in a list.
+	bool InList() const
+	{
+		return GetListNode()->InList();
+	}
+
+	// Determine whether this list is empty.
+	bool IsEmpty() const
+	{
+		return GetListNode()->IsEmpty();
+	}
+
+	/// Calculate the length of the list.
+	uint32 GetLength() const
+	{
+		return GetListNode()->GetLength();
+	}
+
+	B2_INTRUSIVE_LIST_GET_NODE(m_node);
+
+private:
+	// Node within an intrusive list.
+	b2IntrusiveListNode m_node;
+
+public:
+	/// Get a pointer to the instance of T that contains "node".
+	static T* GetInstanceFromListNode(b2IntrusiveListNode* const node)
+	{
+		b2Assert(node);
+		// Calculate the pointer to T from the offset.
+		return (T*)((uint8*)node - GetNodeOffset(node));
+	}
+
+private:
+	// Get the offset of m_node within this class.
+	static int32 GetNodeOffset(b2IntrusiveListNode* const node)
+	{
+		b2Assert(node);
+		// Perform some type punning to calculate the offset of m_node in T.
+		// WARNING: This could result in undefined behavior with some C++
+		// compilers.
+		T* obj = (T*)node;
+		int32 nodeOffset = (int32)((uint8*)&obj->m_node - (uint8*)obj);
+		return nodeOffset;
+	}
+};
+
+#endif // B2_INTRUSIVE_LIST
+

+ 94 - 94
engine/source/Box2D/Common/b2Math.cpp

@@ -1,94 +1,94 @@
-/*
-* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2Math.h>
-
-const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
-
-/// Solve A * x = b, where b is a column vector. This is more efficient
-/// than computing the inverse in one-shot cases.
-b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
-{
-	float32 det = b2Dot(ex, b2Cross(ey, ez));
-	if (det != 0.0f)
-	{
-		det = 1.0f / det;
-	}
-	b2Vec3 x;
-	x.x = det * b2Dot(b, b2Cross(ey, ez));
-	x.y = det * b2Dot(ex, b2Cross(b, ez));
-	x.z = det * b2Dot(ex, b2Cross(ey, b));
-	return x;
-}
-
-/// Solve A * x = b, where b is a column vector. This is more efficient
-/// than computing the inverse in one-shot cases.
-b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
-{
-	float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
-	float32 det = a11 * a22 - a12 * a21;
-	if (det != 0.0f)
-	{
-		det = 1.0f / det;
-	}
-	b2Vec2 x;
-	x.x = det * (a22 * b.x - a12 * b.y);
-	x.y = det * (a11 * b.y - a21 * b.x);
-	return x;
-}
-
-///
-void b2Mat33::GetInverse22(b2Mat33* M) const
-{
-	float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
-	float32 det = a * d - b * c;
-	if (det != 0.0f)
-	{
-		det = 1.0f / det;
-	}
-
-	M->ex.x =  det * d;	M->ey.x = -det * b; M->ex.z = 0.0f;
-	M->ex.y = -det * c;	M->ey.y =  det * a; M->ey.z = 0.0f;
-	M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f;
-}
-
-/// Returns the zero matrix if singular.
-void b2Mat33::GetSymInverse33(b2Mat33* M) const
-{
-	float32 det = b2Dot(ex, b2Cross(ey, ez));
-	if (det != 0.0f)
-	{
-		det = 1.0f / det;
-	}
-
-	float32 a11 = ex.x, a12 = ey.x, a13 = ez.x;
-	float32 a22 = ey.y, a23 = ez.y;
-	float32 a33 = ez.z;
-
-	M->ex.x = det * (a22 * a33 - a23 * a23);
-	M->ex.y = det * (a13 * a23 - a12 * a33);
-	M->ex.z = det * (a12 * a23 - a13 * a22);
-
-	M->ey.x = M->ex.y;
-	M->ey.y = det * (a11 * a33 - a13 * a13);
-	M->ey.z = det * (a13 * a12 - a11 * a23);
-
-	M->ez.x = M->ex.z;
-	M->ez.y = M->ey.z;
-	M->ez.z = det * (a11 * a22 - a12 * a12);
-}
+/*
+* Copyright (c) 2007-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Math.h>
+
+const b2Vec2 b2Vec2_zero(0.0f, 0.0f);
+
+/// Solve A * x = b, where b is a column vector. This is more efficient
+/// than computing the inverse in one-shot cases.
+b2Vec3 b2Mat33::Solve33(const b2Vec3& b) const
+{
+	float32 det = b2Dot(ex, b2Cross(ey, ez));
+	if (det != 0.0f)
+	{
+		det = 1.0f / det;
+	}
+	b2Vec3 x;
+	x.x = det * b2Dot(b, b2Cross(ey, ez));
+	x.y = det * b2Dot(ex, b2Cross(b, ez));
+	x.z = det * b2Dot(ex, b2Cross(ey, b));
+	return x;
+}
+
+/// Solve A * x = b, where b is a column vector. This is more efficient
+/// than computing the inverse in one-shot cases.
+b2Vec2 b2Mat33::Solve22(const b2Vec2& b) const
+{
+	float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
+	float32 det = a11 * a22 - a12 * a21;
+	if (det != 0.0f)
+	{
+		det = 1.0f / det;
+	}
+	b2Vec2 x;
+	x.x = det * (a22 * b.x - a12 * b.y);
+	x.y = det * (a11 * b.y - a21 * b.x);
+	return x;
+}
+
+///
+void b2Mat33::GetInverse22(b2Mat33* M) const
+{
+	float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
+	float32 det = a * d - b * c;
+	if (det != 0.0f)
+	{
+		det = 1.0f / det;
+	}
+
+	M->ex.x =  det * d;	M->ey.x = -det * b; M->ex.z = 0.0f;
+	M->ex.y = -det * c;	M->ey.y =  det * a; M->ey.z = 0.0f;
+	M->ez.x = 0.0f; M->ez.y = 0.0f; M->ez.z = 0.0f;
+}
+
+/// Returns the zero matrix if singular.
+void b2Mat33::GetSymInverse33(b2Mat33* M) const
+{
+	float32 det = b2Dot(ex, b2Cross(ey, ez));
+	if (det != 0.0f)
+	{
+		det = 1.0f / det;
+	}
+
+	float32 a11 = ex.x, a12 = ey.x, a13 = ez.x;
+	float32 a22 = ey.y, a23 = ez.y;
+	float32 a33 = ez.z;
+
+	M->ex.x = det * (a22 * a33 - a23 * a23);
+	M->ex.y = det * (a13 * a23 - a12 * a33);
+	M->ex.z = det * (a12 * a23 - a13 * a22);
+
+	M->ey.x = M->ex.y;
+	M->ey.y = det * (a11 * a33 - a13 * a13);
+	M->ey.z = det * (a13 * a12 - a11 * a23);
+
+	M->ez.x = M->ex.z;
+	M->ez.y = M->ey.z;
+	M->ez.z = det * (a11 * a22 - a12 * a12);
+}

+ 800 - 731
engine/source/Box2D/Common/b2Math.h

@@ -1,731 +1,800 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_MATH_H
-#define B2_MATH_H
-
-#include <Box2D/Common/b2Settings.h>
-
-#include <cmath>
-#include <cfloat>
-#include <cstddef>
-#include <limits>
-
-/// This function is used to ensure that a floating point number is
-/// not a NaN or infinity.
-inline bool b2IsValid(float32 x)
-{
-	if (x != x)
-	{
-		// NaN.
-		return false;
-	}
-
-	float32 infinity = std::numeric_limits<float32>::infinity();
-	return -infinity < x && x < infinity;
-}
-
-/// This is a approximate yet fast inverse square-root.
-inline float32 b2InvSqrt(float32 x)
-{
-	union
-	{
-		float32 x;
-		int32 i;
-	} convert;
-
-	convert.x = x;
-	float32 xhalf = 0.5f * x;
-	convert.i = 0x5f3759df - (convert.i >> 1);
-	x = convert.x;
-	x = x * (1.5f - xhalf * x * x);
-	return x;
-}
-
-#define	b2Sqrt(x)	std::sqrt(x)
-#define	b2Atan2(y, x)	std::atan2(y, x)
-
-/// A 2D column vector.
-struct b2Vec2
-{
-	/// Default constructor does nothing (for performance).
-	b2Vec2() {}
-
-	/// Construct using coordinates.
-	b2Vec2(float32 x, float32 y) : x(x), y(y) {}
-
-	/// Set this vector to all zeros.
-	void SetZero() { x = 0.0f; y = 0.0f; }
-
-	/// Set this vector to some specified coordinates.
-	void Set(float32 x_, float32 y_) { x = x_; y = y_; }
-
-	/// Negate this vector.
-	b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
-	
-	/// Read from and indexed element.
-	float32 operator () (int32 i) const
-	{
-		return (&x)[i];
-	}
-
-	/// Write to an indexed element.
-	float32& operator () (int32 i)
-	{
-		return (&x)[i];
-	}
-
-	/// Add a vector to this vector.
-	void operator += (const b2Vec2& v)
-	{
-		x += v.x; y += v.y;
-	}
-	
-	/// Subtract a vector from this vector.
-	void operator -= (const b2Vec2& v)
-	{
-		x -= v.x; y -= v.y;
-	}
-
-	/// Multiply this vector by a scalar.
-	void operator *= (float32 a)
-	{
-		x *= a; y *= a;
-	}
-
-	/// Get the length of this vector (the norm).
-	float32 Length() const
-	{
-		return b2Sqrt(x * x + y * y);
-	}
-
-	/// Get the length squared. For performance, use this instead of
-	/// b2Vec2::Length (if possible).
-	float32 LengthSquared() const
-	{
-		return x * x + y * y;
-	}
-
-	/// Convert this vector into a unit vector. Returns the length.
-	float32 Normalize()
-	{
-		float32 length = Length();
-		if (length < b2_epsilon)
-		{
-			return 0.0f;
-		}
-		float32 invLength = 1.0f / length;
-		x *= invLength;
-		y *= invLength;
-
-		return length;
-	}
-
-	/// Does this vector contain finite coordinates?
-	bool IsValid() const
-	{
-		return b2IsValid(x) && b2IsValid(y);
-	}
-
-	/// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
-	b2Vec2 Skew() const
-	{
-		return b2Vec2(-y, x);
-	}
-
-	float32 x, y;
-};
-
-/// A 2D column vector with 3 elements.
-struct b2Vec3
-{
-	/// Default constructor does nothing (for performance).
-	b2Vec3() {}
-
-	/// Construct using coordinates.
-	b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
-
-	/// Set this vector to all zeros.
-	void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
-
-	/// Set this vector to some specified coordinates.
-	void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
-
-	/// Negate this vector.
-	b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
-
-	/// Add a vector to this vector.
-	void operator += (const b2Vec3& v)
-	{
-		x += v.x; y += v.y; z += v.z;
-	}
-
-	/// Subtract a vector from this vector.
-	void operator -= (const b2Vec3& v)
-	{
-		x -= v.x; y -= v.y; z -= v.z;
-	}
-
-	/// Multiply this vector by a scalar.
-	void operator *= (float32 s)
-	{
-		x *= s; y *= s; z *= s;
-	}
-
-	float32 x, y, z;
-};
-
-/// A 2-by-2 matrix. Stored in column-major order.
-struct b2Mat22
-{
-	/// The default constructor does nothing (for performance).
-	b2Mat22() {}
-
-	/// Construct this matrix using columns.
-	b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
-	{
-		ex = c1;
-		ey = c2;
-	}
-
-	/// Construct this matrix using scalars.
-	b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
-	{
-		ex.x = a11; ex.y = a21;
-		ey.x = a12; ey.y = a22;
-	}
-
-	/// Initialize this matrix using columns.
-	void Set(const b2Vec2& c1, const b2Vec2& c2)
-	{
-		ex = c1;
-		ey = c2;
-	}
-
-	/// Set this to the identity matrix.
-	void SetIdentity()
-	{
-		ex.x = 1.0f; ey.x = 0.0f;
-		ex.y = 0.0f; ey.y = 1.0f;
-	}
-
-	/// Set this matrix to all zeros.
-	void SetZero()
-	{
-		ex.x = 0.0f; ey.x = 0.0f;
-		ex.y = 0.0f; ey.y = 0.0f;
-	}
-
-	b2Mat22 GetInverse() const
-	{
-		float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
-		b2Mat22 B;
-		float32 det = a * d - b * c;
-		if (det != 0.0f)
-		{
-			det = 1.0f / det;
-		}
-		B.ex.x =  det * d;	B.ey.x = -det * b;
-		B.ex.y = -det * c;	B.ey.y =  det * a;
-		return B;
-	}
-
-	/// Solve A * x = b, where b is a column vector. This is more efficient
-	/// than computing the inverse in one-shot cases.
-	b2Vec2 Solve(const b2Vec2& b) const
-	{
-		float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
-		float32 det = a11 * a22 - a12 * a21;
-		if (det != 0.0f)
-		{
-			det = 1.0f / det;
-		}
-		b2Vec2 x;
-		x.x = det * (a22 * b.x - a12 * b.y);
-		x.y = det * (a11 * b.y - a21 * b.x);
-		return x;
-	}
-
-	b2Vec2 ex, ey;
-};
-
-/// A 3-by-3 matrix. Stored in column-major order.
-struct b2Mat33
-{
-	/// The default constructor does nothing (for performance).
-	b2Mat33() {}
-
-	/// Construct this matrix using columns.
-	b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
-	{
-		ex = c1;
-		ey = c2;
-		ez = c3;
-	}
-
-	/// Set this matrix to all zeros.
-	void SetZero()
-	{
-		ex.SetZero();
-		ey.SetZero();
-		ez.SetZero();
-	}
-
-	/// Solve A * x = b, where b is a column vector. This is more efficient
-	/// than computing the inverse in one-shot cases.
-	b2Vec3 Solve33(const b2Vec3& b) const;
-
-	/// Solve A * x = b, where b is a column vector. This is more efficient
-	/// than computing the inverse in one-shot cases. Solve only the upper
-	/// 2-by-2 matrix equation.
-	b2Vec2 Solve22(const b2Vec2& b) const;
-
-	/// Get the inverse of this matrix as a 2-by-2.
-	/// Returns the zero matrix if singular.
-	void GetInverse22(b2Mat33* M) const;
-
-	/// Get the symmetric inverse of this matrix as a 3-by-3.
-	/// Returns the zero matrix if singular.
-	void GetSymInverse33(b2Mat33* M) const;
-
-	b2Vec3 ex, ey, ez;
-};
-
-/// Rotation
-struct b2Rot
-{
-	b2Rot() {}
-
-	/// Initialize from an angle in radians
-	explicit b2Rot(float32 angle)
-	{
-		/// TODO_ERIN optimize
-		s = sinf(angle);
-		c = cosf(angle);
-	}
-
-	/// Set using an angle in radians.
-	void Set(float32 angle)
-	{
-		/// TODO_ERIN optimize
-		s = sinf(angle);
-		c = cosf(angle);
-	}
-
-	/// Set to the identity rotation
-	void SetIdentity()
-	{
-		s = 0.0f;
-		c = 1.0f;
-	}
-
-	/// Get the angle in radians
-	float32 GetAngle() const
-	{
-		return b2Atan2(s, c);
-	}
-
-	/// Get the x-axis
-	b2Vec2 GetXAxis() const
-	{
-		return b2Vec2(c, s);
-	}
-
-	/// Get the u-axis
-	b2Vec2 GetYAxis() const
-	{
-		return b2Vec2(-s, c);
-	}
-
-	/// Sine and cosine
-	float32 s, c;
-};
-
-/// A transform contains translation and rotation. It is used to represent
-/// the position and orientation of rigid frames.
-struct b2Transform
-{
-	/// The default constructor does nothing.
-	b2Transform() {}
-
-	/// Initialize using a position vector and a rotation.
-	b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {}
-
-	/// Set this to the identity transform.
-	void SetIdentity()
-	{
-		p.SetZero();
-		q.SetIdentity();
-	}
-
-	/// Set this based on the position and angle.
-	void Set(const b2Vec2& position, float32 angle)
-	{
-		p = position;
-		q.Set(angle);
-	}
-
-	b2Vec2 p;
-	b2Rot q;
-};
-
-/// This describes the motion of a body/shape for TOI computation.
-/// Shapes are defined with respect to the body origin, which may
-/// no coincide with the center of mass. However, to support dynamics
-/// we must interpolate the center of mass position.
-struct b2Sweep
-{
-	/// Get the interpolated transform at a specific time.
-	/// @param beta is a factor in [0,1], where 0 indicates alpha0.
-	void GetTransform(b2Transform* xfb, float32 beta) const;
-
-	/// Advance the sweep forward, yielding a new initial state.
-	/// @param alpha the new initial time.
-	void Advance(float32 alpha);
-
-	/// Normalize the angles.
-	void Normalize();
-
-	b2Vec2 localCenter;	///< local center of mass position
-	b2Vec2 c0, c;		///< center world positions
-	float32 a0, a;		///< world angles
-
-	/// Fraction of the current time step in the range [0,1]
-	/// c0 and a0 are the positions at alpha0.
-	float32 alpha0;
-};
-
-/// Useful constant
-extern const b2Vec2 b2Vec2_zero;
-
-/// Perform the dot product on two vectors.
-inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
-{
-	return a.x * b.x + a.y * b.y;
-}
-
-/// Perform the cross product on two vectors. In 2D this produces a scalar.
-inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
-{
-	return a.x * b.y - a.y * b.x;
-}
-
-/// Perform the cross product on a vector and a scalar. In 2D this produces
-/// a vector.
-inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
-{
-	return b2Vec2(s * a.y, -s * a.x);
-}
-
-/// Perform the cross product on a scalar and a vector. In 2D this produces
-/// a vector.
-inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
-{
-	return b2Vec2(-s * a.y, s * a.x);
-}
-
-/// Multiply a matrix times a vector. If a rotation matrix is provided,
-/// then this transforms the vector from one frame to another.
-inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
-{
-	return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
-}
-
-/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
-/// then this transforms the vector from one frame to another (inverse transform).
-inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
-{
-	return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey));
-}
-
-/// Add two vectors component-wise.
-inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)
-{
-	return b2Vec2(a.x + b.x, a.y + b.y);
-}
-
-/// Subtract two vectors component-wise.
-inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
-{
-	return b2Vec2(a.x - b.x, a.y - b.y);
-}
-
-inline b2Vec2 operator * (float32 s, const b2Vec2& a)
-{
-	return b2Vec2(s * a.x, s * a.y);
-}
-
-inline bool operator == (const b2Vec2& a, const b2Vec2& b)
-{
-	return a.x == b.x && a.y == b.y;
-}
-
-inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
-{
-	b2Vec2 c = a - b;
-	return c.Length();
-}
-
-inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
-{
-	b2Vec2 c = a - b;
-	return b2Dot(c, c);
-}
-
-inline b2Vec3 operator * (float32 s, const b2Vec3& a)
-{
-	return b2Vec3(s * a.x, s * a.y, s * a.z);
-}
-
-/// Add two vectors component-wise.
-inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)
-{
-	return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
-}
-
-/// Subtract two vectors component-wise.
-inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
-{
-	return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);
-}
-
-/// Perform the dot product on two vectors.
-inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)
-{
-	return a.x * b.x + a.y * b.y + a.z * b.z;
-}
-
-/// Perform the cross product on two vectors.
-inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)
-{
-	return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
-}
-
-inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
-{
-	return b2Mat22(A.ex + B.ex, A.ey + B.ey);
-}
-
-// A * B
-inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
-{
-	return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey));
-}
-
-// A^T * B
-inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
-{
-	b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex));
-	b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey));
-	return b2Mat22(c1, c2);
-}
-
-/// Multiply a matrix times a vector.
-inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)
-{
-	return v.x * A.ex + v.y * A.ey + v.z * A.ez;
-}
-
-/// Multiply a matrix times a vector.
-inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
-{
-	return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
-}
-
-/// Multiply two rotations: q * r
-inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r)
-{
-	// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
-	// [qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]
-	// s = qs * rc + qc * rs
-	// c = qc * rc - qs * rs
-	b2Rot qr;
-	qr.s = q.s * r.c + q.c * r.s;
-	qr.c = q.c * r.c - q.s * r.s;
-	return qr;
-}
-
-/// Transpose multiply two rotations: qT * r
-inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r)
-{
-	// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
-	// [-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]
-	// s = qc * rs - qs * rc
-	// c = qc * rc + qs * rs
-	b2Rot qr;
-	qr.s = q.c * r.s - q.s * r.c;
-	qr.c = q.c * r.c + q.s * r.s;
-	return qr;
-}
-
-/// Rotate a vector
-inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v)
-{
-	return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y);
-}
-
-/// Inverse rotate a vector
-inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v)
-{
-	return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y);
-}
-
-inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)
-{
-	float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
-	float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
-
-	return b2Vec2(x, y);
-}
-
-inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)
-{
-	float32 px = v.x - T.p.x;
-	float32 py = v.y - T.p.y;
-	float32 x = (T.q.c * px + T.q.s * py);
-	float32 y = (-T.q.s * px + T.q.c * py);
-
-	return b2Vec2(x, y);
-}
-
-// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
-//    = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
-inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B)
-{
-	b2Transform C;
-	C.q = b2Mul(A.q, B.q);
-	C.p = b2Mul(A.q, B.p) + A.p;
-	return C;
-}
-
-// v2 = A.q' * (B.q * v1 + B.p - A.p)
-//    = A.q' * B.q * v1 + A.q' * (B.p - A.p)
-inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B)
-{
-	b2Transform C;
-	C.q = b2MulT(A.q, B.q);
-	C.p = b2MulT(A.q, B.p - A.p);
-	return C;
-}
-
-template <typename T>
-inline T b2Abs(T a)
-{
-	return a > T(0) ? a : -a;
-}
-
-inline b2Vec2 b2Abs(const b2Vec2& a)
-{
-	return b2Vec2(b2Abs(a.x), b2Abs(a.y));
-}
-
-inline b2Mat22 b2Abs(const b2Mat22& A)
-{
-	return b2Mat22(b2Abs(A.ex), b2Abs(A.ey));
-}
-
-template <typename T>
-inline T b2Min(T a, T b)
-{
-	return a < b ? a : b;
-}
-
-inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)
-{
-	return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y));
-}
-
-template <typename T>
-inline T b2Max(T a, T b)
-{
-	return a > b ? a : b;
-}
-
-inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)
-{
-	return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y));
-}
-
-template <typename T>
-inline T b2Clamp(T a, T low, T high)
-{
-	return b2Max(low, b2Min(a, high));
-}
-
-inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)
-{
-	return b2Max(low, b2Min(a, high));
-}
-
-template<typename T> inline void b2Swap(T& a, T& b)
-{
-	T tmp = a;
-	a = b;
-	b = tmp;
-}
-
-/// "Next Largest Power of 2
-/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
-/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
-/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
-/// largest power of 2. For a 32-bit value:"
-inline uint32 b2NextPowerOfTwo(uint32 x)
-{
-	x |= (x >> 1);
-	x |= (x >> 2);
-	x |= (x >> 4);
-	x |= (x >> 8);
-	x |= (x >> 16);
-	return x + 1;
-}
-
-inline bool b2IsPowerOfTwo(uint32 x)
-{
-	bool result = x > 0 && (x & (x - 1)) == 0;
-	return result;
-}
-
-inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const
-{
-	xf->p = (1.0f - beta) * c0 + beta * c;
-	float32 angle = (1.0f - beta) * a0 + beta * a;
-	xf->q.Set(angle);
-
-	// Shift to origin
-	xf->p -= b2Mul(xf->q, localCenter);
-}
-
-inline void b2Sweep::Advance(float32 alpha)
-{
-	b2Assert(alpha0 < 1.0f);
-	float32 beta = (alpha - alpha0) / (1.0f - alpha0);
-	c0 = (1.0f - beta) * c0 + beta * c;
-	a0 = (1.0f - beta) * a0 + beta * a;
-	alpha0 = alpha;
-}
-
-/// Normalize an angle in radians to be between -pi and pi
-inline void b2Sweep::Normalize()
-{
-	float32 twoPi = 2.0f * b2_pi;
-	float32 d =  twoPi * floorf(a0 / twoPi);
-	a0 -= d;
-	a -= d;
-}
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_MATH_H
+#define B2_MATH_H
+
+#include <Box2D/Common/b2Settings.h>
+#include <math.h>
+
+/// This function is used to ensure that a floating point number is not a NaN or infinity.
+inline bool b2IsValid(float32 x)
+{
+	union {
+		float32 f;
+		int32 i;
+	} v = { x };
+	return (v.i & 0x7f800000) != 0x7f800000;
+}
+
+/// This is a approximate yet fast inverse square-root.
+inline float32 b2InvSqrt(float32 x)
+{
+	union
+	{
+		float32 x;
+		int32 i;
+	} convert;
+
+	convert.x = x;
+	float32 xhalf = 0.5f * x;
+	convert.i = 0x5f3759df - (convert.i >> 1);
+	x = convert.x;
+	x = x * (1.5f - xhalf * x * x);
+	return x;
+}
+
+#define	b2Sqrt(x)	sqrtf(x)
+#define	b2Atan2(y, x)	atan2f(y, x)
+
+/// A 2D column vector.
+struct b2Vec2
+{
+	/// Default constructor does nothing (for performance).
+	b2Vec2() {}
+
+	/// Construct using coordinates.
+	b2Vec2(float32 x, float32 y) : x(x), y(y) {}
+
+	/// Set this vector to all zeros.
+	void SetZero() { x = 0.0f; y = 0.0f; }
+
+	/// Set this vector to some specified coordinates.
+	void Set(float32 x_, float32 y_) { x = x_; y = y_; }
+
+	/// Negate this vector.
+	b2Vec2 operator -() const { b2Vec2 v; v.Set(-x, -y); return v; }
+
+	/// Read from and indexed element.
+	float32 operator () (int32 i) const
+	{
+		return (&x)[i];
+	}
+
+	/// Write to an indexed element.
+	float32& operator () (int32 i)
+	{
+		return (&x)[i];
+	}
+
+	/// Add a vector to this vector.
+	void operator += (const b2Vec2& v)
+	{
+		x += v.x; y += v.y;
+	}
+
+	/// Subtract a vector from this vector.
+	void operator -= (const b2Vec2& v)
+	{
+		x -= v.x; y -= v.y;
+	}
+
+	/// Multiply this vector by a scalar.
+	void operator *= (float32 a)
+	{
+		x *= a; y *= a;
+	}
+
+	/// Get the length of this vector (the norm).
+	float32 Length() const
+	{
+		return b2Sqrt(x * x + y * y);
+	}
+
+	/// Get the length squared. For performance, use this instead of
+	/// b2Vec2::Length (if possible).
+	float32 LengthSquared() const
+	{
+		return x * x + y * y;
+	}
+
+	/// Convert this vector into a unit vector. Returns the length.
+	float32 Normalize()
+	{
+		float32 length = Length();
+		if (length < b2_epsilon)
+		{
+			return 0.0f;
+		}
+		float32 invLength = 1.0f / length;
+		x *= invLength;
+		y *= invLength;
+
+		return length;
+	}
+
+	/// Does this vector contain finite coordinates?
+	bool IsValid() const
+	{
+		return b2IsValid(x) && b2IsValid(y);
+	}
+
+	/// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
+	b2Vec2 Skew() const
+	{
+		return b2Vec2(-y, x);
+	}
+
+	float32 x, y;
+};
+
+/// Add a float to a vector.
+inline b2Vec2 operator + (const b2Vec2& v, float f)
+{
+	return b2Vec2(v.x + f, v.y + f);
+}
+
+/// Substract a float from a vector.
+inline b2Vec2 operator - (const b2Vec2& v, float f)
+{
+	return b2Vec2(v.x - f, v.y - f);
+}
+
+/// Multiply a float with a vector.
+inline b2Vec2 operator * (const b2Vec2& v, float f)
+{
+	return b2Vec2(v.x * f, v.y * f);
+}
+
+/// Divide a vector by a float.
+inline b2Vec2 operator / (const b2Vec2& v, float f)
+{
+	return b2Vec2(v.x / f, v.y / f);
+}
+
+/// A 3D column vector with 3 elements.
+struct b2Vec3
+{
+	/// Default constructor does nothing (for performance).
+	b2Vec3() {}
+
+	/// Construct using coordinates.
+	b2Vec3(float32 x, float32 y, float32 z) : x(x), y(y), z(z) {}
+
+	/// Set this vector to all zeros.
+	void SetZero() { x = 0.0f; y = 0.0f; z = 0.0f; }
+
+	/// Set this vector to some specified coordinates.
+	void Set(float32 x_, float32 y_, float32 z_) { x = x_; y = y_; z = z_; }
+
+	/// Negate this vector.
+	b2Vec3 operator -() const { b2Vec3 v; v.Set(-x, -y, -z); return v; }
+
+	/// Add a vector to this vector.
+	void operator += (const b2Vec3& v)
+	{
+		x += v.x; y += v.y; z += v.z;
+	}
+
+	/// Subtract a vector from this vector.
+	void operator -= (const b2Vec3& v)
+	{
+		x -= v.x; y -= v.y; z -= v.z;
+	}
+
+	/// Multiply this vector by a scalar.
+	void operator *= (float32 s)
+	{
+		x *= s; y *= s; z *= s;
+	}
+
+		/// Get the length of this vector (the norm).
+	float32 Length() const
+	{
+		return b2Sqrt(x * x + y * y + z * z);
+	}
+
+	/// Convert this vector into a unit vector. Returns the length.
+	float32 Normalize()
+	{
+		float32 length = Length();
+		if (length < b2_epsilon)
+		{
+			return 0.0f;
+		}
+		float32 invLength = 1.0f / length;
+		x *= invLength;
+		y *= invLength;
+		z *= invLength;
+
+		return length;
+	}
+
+	float32 x, y, z;
+};
+
+/// A 4D column vector with 4 elements.
+struct b2Vec4
+{
+	/// Default constructor does nothing (for performance).
+	b2Vec4() {}
+
+	/// Construct using coordinates.
+	b2Vec4(float32 x, float32 y, float32 z, float32 w) : x(x), y(y), z(z), w(w) {}
+
+	float32 x, y, z, w;
+};
+
+/// A 2-by-2 matrix. Stored in column-major order.
+struct b2Mat22
+{
+	/// The default constructor does nothing (for performance).
+	b2Mat22() {}
+
+	/// Construct this matrix using columns.
+	b2Mat22(const b2Vec2& c1, const b2Vec2& c2)
+	{
+		ex = c1;
+		ey = c2;
+	}
+
+	/// Construct this matrix using scalars.
+	b2Mat22(float32 a11, float32 a12, float32 a21, float32 a22)
+	{
+		ex.x = a11; ex.y = a21;
+		ey.x = a12; ey.y = a22;
+	}
+
+	/// Initialize this matrix using columns.
+	void Set(const b2Vec2& c1, const b2Vec2& c2)
+	{
+		ex = c1;
+		ey = c2;
+	}
+
+	/// Set this to the identity matrix.
+	void SetIdentity()
+	{
+		ex.x = 1.0f; ey.x = 0.0f;
+		ex.y = 0.0f; ey.y = 1.0f;
+	}
+
+	/// Set this matrix to all zeros.
+	void SetZero()
+	{
+		ex.x = 0.0f; ey.x = 0.0f;
+		ex.y = 0.0f; ey.y = 0.0f;
+	}
+
+	b2Mat22 GetInverse() const
+	{
+		float32 a = ex.x, b = ey.x, c = ex.y, d = ey.y;
+		b2Mat22 B;
+		float32 det = a * d - b * c;
+		if (det != 0.0f)
+		{
+			det = 1.0f / det;
+		}
+		B.ex.x =  det * d;	B.ey.x = -det * b;
+		B.ex.y = -det * c;	B.ey.y =  det * a;
+		return B;
+	}
+
+	/// Solve A * x = b, where b is a column vector. This is more efficient
+	/// than computing the inverse in one-shot cases.
+	b2Vec2 Solve(const b2Vec2& b) const
+	{
+		float32 a11 = ex.x, a12 = ey.x, a21 = ex.y, a22 = ey.y;
+		float32 det = a11 * a22 - a12 * a21;
+		if (det != 0.0f)
+		{
+			det = 1.0f / det;
+		}
+		b2Vec2 x;
+		x.x = det * (a22 * b.x - a12 * b.y);
+		x.y = det * (a11 * b.y - a21 * b.x);
+		return x;
+	}
+
+	b2Vec2 ex, ey;
+};
+
+/// A 3-by-3 matrix. Stored in column-major order.
+struct b2Mat33
+{
+	/// The default constructor does nothing (for performance).
+	b2Mat33() {}
+
+	/// Construct this matrix using columns.
+	b2Mat33(const b2Vec3& c1, const b2Vec3& c2, const b2Vec3& c3)
+	{
+		ex = c1;
+		ey = c2;
+		ez = c3;
+	}
+
+	/// Set this matrix to all zeros.
+	void SetZero()
+	{
+		ex.SetZero();
+		ey.SetZero();
+		ez.SetZero();
+	}
+
+	/// Solve A * x = b, where b is a column vector. This is more efficient
+	/// than computing the inverse in one-shot cases.
+	b2Vec3 Solve33(const b2Vec3& b) const;
+
+	/// Solve A * x = b, where b is a column vector. This is more efficient
+	/// than computing the inverse in one-shot cases. Solve only the upper
+	/// 2-by-2 matrix equation.
+	b2Vec2 Solve22(const b2Vec2& b) const;
+
+	/// Get the inverse of this matrix as a 2-by-2.
+	/// Returns the zero matrix if singular.
+	void GetInverse22(b2Mat33* M) const;
+
+	/// Get the symmetric inverse of this matrix as a 3-by-3.
+	/// Returns the zero matrix if singular.
+	void GetSymInverse33(b2Mat33* M) const;
+
+	b2Vec3 ex, ey, ez;
+};
+
+/// Rotation
+struct b2Rot
+{
+	b2Rot() {}
+
+	/// Initialize from an angle in radians
+	explicit b2Rot(float32 angle)
+	{
+		/// TODO_ERIN optimize
+		s = sinf(angle);
+		c = cosf(angle);
+	}
+
+	/// Set using an angle in radians.
+	void Set(float32 angle)
+	{
+		/// TODO_ERIN optimize
+		s = sinf(angle);
+		c = cosf(angle);
+	}
+
+	/// Set to the identity rotation
+	void SetIdentity()
+	{
+		s = 0.0f;
+		c = 1.0f;
+	}
+
+	/// Get the angle in radians
+	float32 GetAngle() const
+	{
+		return b2Atan2(s, c);
+	}
+
+	/// Get the x-axis
+	b2Vec2 GetXAxis() const
+	{
+		return b2Vec2(c, s);
+	}
+
+	/// Get the u-axis
+	b2Vec2 GetYAxis() const
+	{
+		return b2Vec2(-s, c);
+	}
+
+	/// Sine and cosine
+	float32 s, c;
+};
+
+/// A transform contains translation and rotation. It is used to represent
+/// the position and orientation of rigid frames.
+struct b2Transform
+{
+	/// The default constructor does nothing.
+	b2Transform() {}
+
+	/// Initialize using a position vector and a rotation.
+	b2Transform(const b2Vec2& position, const b2Rot& rotation) : p(position), q(rotation) {}
+
+	/// Set this to the identity transform.
+	void SetIdentity()
+	{
+		p.SetZero();
+		q.SetIdentity();
+	}
+
+	/// Set this based on the position and angle.
+	void Set(const b2Vec2& position, float32 angle)
+	{
+		p = position;
+		q.Set(angle);
+	}
+
+#if LIQUIDFUN_EXTERNAL_LANGUAGE_API
+	/// Get x-coordinate of p.
+	float32 GetPositionX() const { return p.x; }
+
+	/// Get y-coordinate of p.
+	float32 GetPositionY() const { return p.y; }
+
+	/// Get sine-component of q.
+	float32 GetRotationSin() const { return q.s; }
+
+	/// Get cosine-component of q.
+	float32 GetRotationCos() const { return q.c; }
+#endif // LIQUIDFUN_EXTERNAL_LANGUAGE_API
+
+	b2Vec2 p;
+	b2Rot q;
+};
+
+/// This describes the motion of a body/shape for TOI computation.
+/// Shapes are defined with respect to the body origin, which may
+/// no coincide with the center of mass. However, to support dynamics
+/// we must interpolate the center of mass position.
+struct b2Sweep
+{
+	/// Get the interpolated transform at a specific time.
+	/// @param beta is a factor in [0,1], where 0 indicates alpha0.
+	void GetTransform(b2Transform* xfb, float32 beta) const;
+
+	/// Advance the sweep forward, yielding a new initial state.
+	/// @param alpha the new initial time.
+	void Advance(float32 alpha);
+
+	/// Normalize the angles.
+	void Normalize();
+
+	b2Vec2 localCenter;	///< local center of mass position
+	b2Vec2 c0, c;		///< center world positions
+	float32 a0, a;		///< world angles
+
+	/// Fraction of the current time step in the range [0,1]
+	/// c0 and a0 are the positions at alpha0.
+	float32 alpha0;
+};
+
+/// Useful constant
+extern const b2Vec2 b2Vec2_zero;
+
+/// Perform the dot product on two vectors.
+inline float32 b2Dot(const b2Vec2& a, const b2Vec2& b)
+{
+	return a.x * b.x + a.y * b.y;
+}
+
+/// Perform the cross product on two vectors. In 2D this produces a scalar.
+inline float32 b2Cross(const b2Vec2& a, const b2Vec2& b)
+{
+	return a.x * b.y - a.y * b.x;
+}
+
+/// Perform the cross product on a vector and a scalar. In 2D this produces
+/// a vector.
+inline b2Vec2 b2Cross(const b2Vec2& a, float32 s)
+{
+	return b2Vec2(s * a.y, -s * a.x);
+}
+
+/// Perform the cross product on a scalar and a vector. In 2D this produces
+/// a vector.
+inline b2Vec2 b2Cross(float32 s, const b2Vec2& a)
+{
+	return b2Vec2(-s * a.y, s * a.x);
+}
+
+/// Multiply a matrix times a vector. If a rotation matrix is provided,
+/// then this transforms the vector from one frame to another.
+inline b2Vec2 b2Mul(const b2Mat22& A, const b2Vec2& v)
+{
+	return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
+}
+
+/// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
+/// then this transforms the vector from one frame to another (inverse transform).
+inline b2Vec2 b2MulT(const b2Mat22& A, const b2Vec2& v)
+{
+	return b2Vec2(b2Dot(v, A.ex), b2Dot(v, A.ey));
+}
+
+/// Add two vectors component-wise.
+inline b2Vec2 operator + (const b2Vec2& a, const b2Vec2& b)
+{
+	return b2Vec2(a.x + b.x, a.y + b.y);
+}
+
+/// Subtract two vectors component-wise.
+inline b2Vec2 operator - (const b2Vec2& a, const b2Vec2& b)
+{
+	return b2Vec2(a.x - b.x, a.y - b.y);
+}
+
+inline b2Vec2 operator * (float32 s, const b2Vec2& a)
+{
+	return b2Vec2(s * a.x, s * a.y);
+}
+
+inline bool operator == (const b2Vec2& a, const b2Vec2& b)
+{
+	return a.x == b.x && a.y == b.y;
+}
+
+inline bool operator != (const b2Vec2& a, const b2Vec2& b)
+{
+	return !operator==(a, b);
+}
+
+inline float32 b2Distance(const b2Vec2& a, const b2Vec2& b)
+{
+	b2Vec2 c = a - b;
+	return c.Length();
+}
+
+inline float32 b2DistanceSquared(const b2Vec2& a, const b2Vec2& b)
+{
+	b2Vec2 c = a - b;
+	return b2Dot(c, c);
+}
+
+inline b2Vec3 operator * (float32 s, const b2Vec3& a)
+{
+	return b2Vec3(s * a.x, s * a.y, s * a.z);
+}
+
+/// Add two vectors component-wise.
+inline b2Vec3 operator + (const b2Vec3& a, const b2Vec3& b)
+{
+	return b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z);
+}
+
+/// Subtract two vectors component-wise.
+inline b2Vec3 operator - (const b2Vec3& a, const b2Vec3& b)
+{
+	return b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z);
+}
+
+/// Perform the dot product on two vectors.
+inline float32 b2Dot(const b2Vec3& a, const b2Vec3& b)
+{
+	return a.x * b.x + a.y * b.y + a.z * b.z;
+}
+
+/// Perform the cross product on two vectors.
+inline b2Vec3 b2Cross(const b2Vec3& a, const b2Vec3& b)
+{
+	return b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
+}
+
+inline b2Mat22 operator + (const b2Mat22& A, const b2Mat22& B)
+{
+	return b2Mat22(A.ex + B.ex, A.ey + B.ey);
+}
+
+// A * B
+inline b2Mat22 b2Mul(const b2Mat22& A, const b2Mat22& B)
+{
+	return b2Mat22(b2Mul(A, B.ex), b2Mul(A, B.ey));
+}
+
+// A^T * B
+inline b2Mat22 b2MulT(const b2Mat22& A, const b2Mat22& B)
+{
+	b2Vec2 c1(b2Dot(A.ex, B.ex), b2Dot(A.ey, B.ex));
+	b2Vec2 c2(b2Dot(A.ex, B.ey), b2Dot(A.ey, B.ey));
+	return b2Mat22(c1, c2);
+}
+
+/// Multiply a matrix times a vector.
+inline b2Vec3 b2Mul(const b2Mat33& A, const b2Vec3& v)
+{
+	return v.x * A.ex + v.y * A.ey + v.z * A.ez;
+}
+
+/// Multiply a matrix times a vector.
+inline b2Vec2 b2Mul22(const b2Mat33& A, const b2Vec2& v)
+{
+	return b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y);
+}
+
+/// Multiply two rotations: q * r
+inline b2Rot b2Mul(const b2Rot& q, const b2Rot& r)
+{
+	// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
+	// [qs  qc]   [rs  rc]   [qs*rc+qc*rs -qs*rs+qc*rc]
+	// s = qs * rc + qc * rs
+	// c = qc * rc - qs * rs
+	b2Rot qr;
+	qr.s = q.s * r.c + q.c * r.s;
+	qr.c = q.c * r.c - q.s * r.s;
+	return qr;
+}
+
+/// Transpose multiply two rotations: qT * r
+inline b2Rot b2MulT(const b2Rot& q, const b2Rot& r)
+{
+	// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
+	// [-qs qc]   [rs  rc]   [-qs*rc+qc*rs qs*rs+qc*rc]
+	// s = qc * rs - qs * rc
+	// c = qc * rc + qs * rs
+	b2Rot qr;
+	qr.s = q.c * r.s - q.s * r.c;
+	qr.c = q.c * r.c + q.s * r.s;
+	return qr;
+}
+
+/// Rotate a vector
+inline b2Vec2 b2Mul(const b2Rot& q, const b2Vec2& v)
+{
+	return b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y);
+}
+
+/// Inverse rotate a vector
+inline b2Vec2 b2MulT(const b2Rot& q, const b2Vec2& v)
+{
+	return b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y);
+}
+
+inline b2Vec2 b2Mul(const b2Transform& T, const b2Vec2& v)
+{
+	float32 x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
+	float32 y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
+
+	return b2Vec2(x, y);
+}
+
+inline b2Vec2 b2MulT(const b2Transform& T, const b2Vec2& v)
+{
+	float32 px = v.x - T.p.x;
+	float32 py = v.y - T.p.y;
+	float32 x = (T.q.c * px + T.q.s * py);
+	float32 y = (-T.q.s * px + T.q.c * py);
+
+	return b2Vec2(x, y);
+}
+
+// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
+//    = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
+inline b2Transform b2Mul(const b2Transform& A, const b2Transform& B)
+{
+	b2Transform C;
+	C.q = b2Mul(A.q, B.q);
+	C.p = b2Mul(A.q, B.p) + A.p;
+	return C;
+}
+
+// v2 = A.q' * (B.q * v1 + B.p - A.p)
+//    = A.q' * B.q * v1 + A.q' * (B.p - A.p)
+inline b2Transform b2MulT(const b2Transform& A, const b2Transform& B)
+{
+	b2Transform C;
+	C.q = b2MulT(A.q, B.q);
+	C.p = b2MulT(A.q, B.p - A.p);
+	return C;
+}
+
+template <typename T>
+inline T b2Abs(T a)
+{
+	return a > T(0) ? a : -a;
+}
+
+inline b2Vec2 b2Abs(const b2Vec2& a)
+{
+	return b2Vec2(b2Abs(a.x), b2Abs(a.y));
+}
+
+inline b2Mat22 b2Abs(const b2Mat22& A)
+{
+	return b2Mat22(b2Abs(A.ex), b2Abs(A.ey));
+}
+
+template <typename T>
+inline T b2Min(T a, T b)
+{
+	return a < b ? a : b;
+}
+
+inline b2Vec2 b2Min(const b2Vec2& a, const b2Vec2& b)
+{
+	return b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y));
+}
+
+template <typename T>
+inline T b2Max(T a, T b)
+{
+	return a > b ? a : b;
+}
+
+inline b2Vec2 b2Max(const b2Vec2& a, const b2Vec2& b)
+{
+	return b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y));
+}
+
+template <typename T>
+inline T b2Clamp(T a, T low, T high)
+{
+	return b2Max(low, b2Min(a, high));
+}
+
+inline b2Vec2 b2Clamp(const b2Vec2& a, const b2Vec2& low, const b2Vec2& high)
+{
+	return b2Max(low, b2Min(a, high));
+}
+
+template<typename T> inline void b2Swap(T& a, T& b)
+{
+	T tmp = a;
+	a = b;
+	b = tmp;
+}
+
+/// "Next Largest Power of 2
+/// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
+/// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
+/// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
+/// largest power of 2. For a 32-bit value:"
+inline uint32 b2NextPowerOfTwo(uint32 x)
+{
+	x |= (x >> 1);
+	x |= (x >> 2);
+	x |= (x >> 4);
+	x |= (x >> 8);
+	x |= (x >> 16);
+	return x + 1;
+}
+
+inline bool b2IsPowerOfTwo(uint32 x)
+{
+	bool result = x > 0 && (x & (x - 1)) == 0;
+	return result;
+}
+
+inline void b2Sweep::GetTransform(b2Transform* xf, float32 beta) const
+{
+	xf->p = (1.0f - beta) * c0 + beta * c;
+	float32 angle = (1.0f - beta) * a0 + beta * a;
+	xf->q.Set(angle);
+
+	// Shift to origin
+	xf->p -= b2Mul(xf->q, localCenter);
+}
+
+inline void b2Sweep::Advance(float32 alpha)
+{
+	b2Assert(alpha0 < 1.0f);
+	float32 beta = (alpha - alpha0) / (1.0f - alpha0);
+	c0 += beta * (c - c0);
+	a0 += beta * (a - a0);
+	alpha0 = alpha;
+}
+
+/// Normalize an angle in radians to be between -pi and pi
+inline void b2Sweep::Normalize()
+{
+	float32 twoPi = 2.0f * b2_pi;
+	float32 d =  twoPi * floorf(a0 / twoPi);
+	a0 -= d;
+	a -= d;
+}
+
+#endif

+ 136 - 44
engine/source/Box2D/Common/b2Settings.cpp

@@ -1,44 +1,136 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2Settings.h>
-#include <cstdlib>
-#include <cstdio>
-#include <cstdarg>
-
-b2Version b2_version = {2, 3, 0};
-
-// Memory allocators. Modify these to use your own allocator.
-void* b2Alloc(int32 size)
-{
-	return malloc(size);
-}
-
-void b2Free(void* mem)
-{
-	free(mem);
-}
-
-// You can modify this to use your logging facility.
-void b2Log(const char* string, ...)
-{
-	va_list args;
-	va_start(args, string);
-	vprintf(string, args);
-	va_end(args);
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Settings.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+b2Version b2_version = {2, 3, 0};
+
+#define LIQUIDFUN_VERSION_MAJOR 1
+#define LIQUIDFUN_VERSION_MINOR 1
+#define LIQUIDFUN_VERSION_REVISION 0
+#define LIQUIDFUN_STRING_EXPAND(X) #X
+#define LIQUIDFUN_STRING(X) LIQUIDFUN_STRING_EXPAND(X)
+
+static void* b2AllocDefault(int32 size, void* callbackData);
+static void b2FreeDefault(void* mem, void* callbackData);
+
+const b2Version b2_liquidFunVersion = {
+	LIQUIDFUN_VERSION_MAJOR, LIQUIDFUN_VERSION_MINOR,
+	LIQUIDFUN_VERSION_REVISION,
+};
+
+const char *b2_liquidFunVersionString =
+	"LiquidFun "
+	LIQUIDFUN_STRING(LIQUIDFUN_VERSION_MAJOR) "."
+	LIQUIDFUN_STRING(LIQUIDFUN_VERSION_MINOR) "."
+	LIQUIDFUN_STRING(LIQUIDFUN_VERSION_REVISION);
+
+static int32 b2_numAllocs = 0;
+
+// Initialize default allocator.
+static b2AllocFunction b2_allocCallback = b2AllocDefault;
+static b2FreeFunction b2_freeCallback = b2FreeDefault;
+static void *b2_callbackData = NULL;
+
+// Default implementation of b2AllocFunction.
+static void* b2AllocDefault(int32 size, void* callbackData)
+{
+	B2_NOT_USED(callbackData);
+	return malloc(size);
+}
+
+// Default implementation of b2FreeFunction.
+static void b2FreeDefault(void* mem, void* callbackData)
+{
+	B2_NOT_USED(callbackData);
+	free(mem);
+}
+
+/// Set alloc and free callbacks to override the default behavior of using
+/// malloc() and free() for dynamic memory allocation.
+/// Set allocCallback and freeCallback to NULL to restore the default
+/// allocator (malloc / free).
+void b2SetAllocFreeCallbacks(b2AllocFunction allocCallback,
+							 b2FreeFunction freeCallback, void* callbackData)
+{
+	b2Assert((allocCallback && freeCallback) ||
+			 (!allocCallback && !freeCallback));
+	b2Assert(0 == b2GetNumAllocs());
+	if (allocCallback && freeCallback)
+	{
+		b2_allocCallback = allocCallback;
+		b2_freeCallback = freeCallback;
+		b2_callbackData = callbackData;
+	}
+	else
+	{
+		b2_allocCallback = b2AllocDefault;
+		b2_freeCallback = b2FreeDefault;
+		b2_callbackData = NULL;
+	}
+}
+
+// Memory allocators. Modify these to use your own allocator.
+void* b2Alloc(int32 size)
+{
+	b2_numAllocs++;
+	return b2_allocCallback(size, b2_callbackData);
+}
+
+void b2Free(void* mem)
+{
+	b2_numAllocs--;
+	b2_freeCallback(mem, b2_callbackData);
+}
+
+void b2SetNumAllocs(const int32 numAllocs)
+{
+	b2_numAllocs = numAllocs;
+}
+
+int32 b2GetNumAllocs()
+{
+	return b2_numAllocs;
+}
+
+// You can modify this to use your logging facility.
+void b2Log(const char* string, ...)
+{
+#if DEBUG
+	va_list args;
+	va_start(args, string);
+	vprintf(string, args);
+	va_end(args);
+#else
+	B2_NOT_USED(string);
+#endif
+}
+
+class Validator
+{
+public:
+	Validator()
+	{
+		b2Assert(sizeof(uint64)==8);
+		b2Assert(sizeof(int64)==8);
+	}
+} validate;

+ 267 - 150
engine/source/Box2D/Common/b2Settings.h

@@ -1,150 +1,267 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_SETTINGS_H
-#define B2_SETTINGS_H
-
-#include <cassert>
-#include <cmath>
-
-#define B2_NOT_USED(x) ((void)(x))
-#define b2Assert(A) assert(A)
-
-typedef signed char	int8;
-typedef signed short int16;
-typedef signed int int32;
-typedef unsigned char uint8;
-typedef unsigned short uint16;
-typedef unsigned int uint32;
-typedef float float32;
-typedef double float64;
-
-#define	b2_maxFloat		FLT_MAX
-#define	b2_epsilon		FLT_EPSILON
-#define b2_pi			3.14159265359f
-
-/// @file
-/// Global tuning constants based on meters-kilograms-seconds (MKS) units.
-///
-
-// Collision
-
-/// The maximum number of contact points between two convex shapes. Do
-/// not change this value.
-#define b2_maxManifoldPoints	2
-
-/// The maximum number of vertices on a convex polygon. You cannot increase
-/// this too much because b2BlockAllocator has a maximum object size.
-#define b2_maxPolygonVertices	8
-
-/// This is used to fatten AABBs in the dynamic tree. This allows proxies
-/// to move by a small amount without triggering a tree adjustment.
-/// This is in meters.
-#define b2_aabbExtension		0.1f
-
-/// This is used to fatten AABBs in the dynamic tree. This is used to predict
-/// the future position based on the current displacement.
-/// This is a dimensionless multiplier.
-#define b2_aabbMultiplier		2.0f
-
-/// A small length used as a collision and constraint tolerance. Usually it is
-/// chosen to be numerically significant, but visually insignificant.
-#define b2_linearSlop			0.005f
-
-/// A small angle used as a collision and constraint tolerance. Usually it is
-/// chosen to be numerically significant, but visually insignificant.
-#define b2_angularSlop			(2.0f / 180.0f * b2_pi)
-
-/// The radius of the polygon/edge shape skin. This should not be modified. Making
-/// this smaller means polygons will have an insufficient buffer for continuous collision.
-/// Making it larger may create artifacts for vertex collision.
-#define b2_polygonRadius		(2.0f * b2_linearSlop)
-
-/// Maximum number of sub-steps per contact in continuous physics simulation.
-#define b2_maxSubSteps			8
-
-
-// Dynamics
-
-/// Maximum number of contacts to be handled to solve a TOI impact.
-#define b2_maxTOIContacts			32
-
-/// A velocity threshold for elastic collisions. Any collision with a relative linear
-/// velocity below this threshold will be treated as inelastic.
-#define b2_velocityThreshold		1.0f
-
-/// The maximum linear position correction used when solving constraints. This helps to
-/// prevent overshoot.
-#define b2_maxLinearCorrection		0.2f
-
-/// The maximum angular position correction used when solving constraints. This helps to
-/// prevent overshoot.
-#define b2_maxAngularCorrection		(8.0f / 180.0f * b2_pi)
-
-/// The maximum linear velocity of a body. This limit is very large and is used
-/// to prevent numerical problems. You shouldn't need to adjust this.
-#define b2_maxTranslation			2.0f
-#define b2_maxTranslationSquared	(b2_maxTranslation * b2_maxTranslation)
-
-/// The maximum angular velocity of a body. This limit is very large and is used
-/// to prevent numerical problems. You shouldn't need to adjust this.
-#define b2_maxRotation				(0.5f * b2_pi)
-#define b2_maxRotationSquared		(b2_maxRotation * b2_maxRotation)
-
-/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
-/// that overlap is removed in one time step. However using values close to 1 often lead
-/// to overshoot.
-#define b2_baumgarte				0.2f
-#define b2_toiBaugarte				0.75f
-
-
-// Sleep
-
-/// The time that a body must be still before it will go to sleep.
-#define b2_timeToSleep				0.5f
-
-/// A body cannot sleep if its linear velocity is above this tolerance.
-#define b2_linearSleepTolerance		0.01f
-
-/// A body cannot sleep if its angular velocity is above this tolerance.
-#define b2_angularSleepTolerance	(2.0f / 180.0f * b2_pi)
-
-// Memory Allocation
-
-/// Implement this function to use your own memory allocator.
-void* b2Alloc(int32 size);
-
-/// If you implement b2Alloc, you should also implement this function.
-void b2Free(void* mem);
-
-/// Logging function.
-void b2Log(const char* string, ...);
-
-/// Version numbering scheme.
-/// See http://en.wikipedia.org/wiki/Software_versioning
-struct b2Version
-{
-	int32 major;		///< significant changes
-	int32 minor;		///< incremental changes
-	int32 revision;		///< bug fixes
-};
-
-/// Current version.
-extern b2Version b2_version;
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_SETTINGS_H
+#define B2_SETTINGS_H
+
+#include <stddef.h>
+#include <assert.h>
+#include <float.h>
+
+#define B2_NOT_USED(x) ((void)(x))
+#if DEBUG && !defined(NDEBUG)
+#define b2Assert(A) assert(A)
+#define B2_ASSERT_ENABLED 1
+#else
+#define b2Assert(A)
+#define B2_ASSERT_ENABLED 0
+#endif
+
+// Statement which is compiled out when DEBUG isn't defined.
+#if DEBUG
+#define B2_DEBUG_STATEMENT(A) A
+#else
+#define B2_DEBUG_STATEMENT(A)
+#endif  // DEBUG
+
+// Calculate the size of a static array.
+#define B2_ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef signed char	int8;
+typedef signed short int16;
+typedef signed int int32;
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+typedef float float32;
+typedef double float64;
+
+#ifdef WIN32
+typedef __int64   int64;
+typedef unsigned __int64   uint64;
+#else // !WIN32
+typedef long long int64;
+typedef unsigned long long uint64;
+#endif
+
+#define	b2_maxFloat		FLT_MAX
+#define	b2_epsilon		FLT_EPSILON
+#define b2_pi			3.14159265359f
+
+#if !defined(b2Inline)
+#if defined(__GNUC__)
+#define b2Inline __attribute__((always_inline))
+#else
+#define b2Inline inline
+#endif // defined(__GNUC__)
+#endif // !defined(b2Inline)
+
+// We expand the API so that other languages (e.g. Java) can call into
+// our C++ more easily. Only set if when the flag is not externally defined.
+#if !defined(LIQUIDFUN_EXTERNAL_LANGUAGE_API)
+#if SWIG || LIQUIDFUN_UNIT_TESTS
+#define LIQUIDFUN_EXTERNAL_LANGUAGE_API 1
+#else
+#define LIQUIDFUN_EXTERNAL_LANGUAGE_API 0
+#endif
+#endif
+
+/// @file
+/// Global tuning constants based on meters-kilograms-seconds (MKS) units.
+///
+
+// Collision
+
+/// The maximum number of contact points between two convex shapes. Do
+/// not change this value.
+#define b2_maxManifoldPoints	2
+
+/// The maximum number of vertices on a convex polygon. You cannot increase
+/// this too much because b2BlockAllocator has a maximum object size.
+#define b2_maxPolygonVertices	8
+
+/// This is used to fatten AABBs in the dynamic tree. This allows proxies
+/// to move by a small amount without triggering a tree adjustment.
+/// This is in meters.
+#define b2_aabbExtension		0.1f
+
+/// This is used to fatten AABBs in the dynamic tree. This is used to predict
+/// the future position based on the current displacement.
+/// This is a dimensionless multiplier.
+#define b2_aabbMultiplier		2.0f
+
+/// A small length used as a collision and constraint tolerance. Usually it is
+/// chosen to be numerically significant, but visually insignificant.
+#define b2_linearSlop			0.005f
+
+/// A small angle used as a collision and constraint tolerance. Usually it is
+/// chosen to be numerically significant, but visually insignificant.
+#define b2_angularSlop			(2.0f / 180.0f * b2_pi)
+
+/// The radius of the polygon/edge shape skin. This should not be modified. Making
+/// this smaller means polygons will have an insufficient buffer for continuous collision.
+/// Making it larger may create artifacts for vertex collision.
+#define b2_polygonRadius		(2.0f * b2_linearSlop)
+
+/// Maximum number of sub-steps per contact in continuous physics simulation.
+#define b2_maxSubSteps			8
+
+
+// Dynamics
+
+/// Maximum number of contacts to be handled to solve a TOI impact.
+#define b2_maxTOIContacts			32
+
+/// A velocity threshold for elastic collisions. Any collision with a relative linear
+/// velocity below this threshold will be treated as inelastic.
+#define b2_velocityThreshold		1.0f
+
+/// The maximum linear position correction used when solving constraints. This helps to
+/// prevent overshoot.
+#define b2_maxLinearCorrection		0.2f
+
+/// The maximum angular position correction used when solving constraints. This helps to
+/// prevent overshoot.
+#define b2_maxAngularCorrection		(8.0f / 180.0f * b2_pi)
+
+/// The maximum linear velocity of a body. This limit is very large and is used
+/// to prevent numerical problems. You shouldn't need to adjust this.
+#define b2_maxTranslation			2.0f
+#define b2_maxTranslationSquared	(b2_maxTranslation * b2_maxTranslation)
+
+/// The maximum angular velocity of a body. This limit is very large and is used
+/// to prevent numerical problems. You shouldn't need to adjust this.
+#define b2_maxRotation				(0.5f * b2_pi)
+#define b2_maxRotationSquared		(b2_maxRotation * b2_maxRotation)
+
+/// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
+/// that overlap is removed in one time step. However using values close to 1 often lead
+/// to overshoot.
+#define b2_baumgarte				0.2f
+#define b2_toiBaugarte				0.75f
+
+
+// Particle
+
+/// NEON SIMD requires 16-bit particle indices
+#if !defined(B2_USE_16_BIT_PARTICLE_INDICES) && defined(LIQUIDFUN_SIMD_NEON)
+#define B2_USE_16_BIT_PARTICLE_INDICES
+#endif
+
+/// A symbolic constant that stands for particle allocation error.
+#define b2_invalidParticleIndex		(-1)
+
+#ifdef B2_USE_16_BIT_PARTICLE_INDICES
+#define b2_maxParticleIndex			0x7FFF
+#else
+#define b2_maxParticleIndex			0x7FFFFFFF
+#endif
+
+/// The default distance between particles, multiplied by the particle diameter.
+#define b2_particleStride			0.75f
+
+/// The minimum particle weight that produces pressure.
+#define b2_minParticleWeight			1.0f
+
+/// The upper limit for particle pressure.
+#define b2_maxParticlePressure		0.25f
+
+/// The upper limit for force between particles.
+#define b2_maxParticleForce		0.5f
+
+/// The maximum distance between particles in a triad, multiplied by the
+/// particle diameter.
+#define b2_maxTriadDistance			2
+#define b2_maxTriadDistanceSquared		(b2_maxTriadDistance * b2_maxTriadDistance)
+
+/// The initial size of particle data buffers.
+#define b2_minParticleSystemBufferCapacity	256
+
+/// The time into the future that collisions against barrier particles will be detected.
+#define b2_barrierCollisionTime 2.5f
+
+// Sleep
+
+/// The time that a body must be still before it will go to sleep.
+#define b2_timeToSleep				0.5f
+
+/// A body cannot sleep if its linear velocity is above this tolerance.
+#define b2_linearSleepTolerance		0.01f
+
+/// A body cannot sleep if its angular velocity is above this tolerance.
+#define b2_angularSleepTolerance	(2.0f / 180.0f * b2_pi)
+
+// Memory Allocation
+
+/// Implement this function to use your own memory allocator.
+void* b2Alloc(int32 size);
+
+/// If you implement b2Alloc, you should also implement this function.
+void b2Free(void* mem);
+
+/// Use this function to override b2Alloc() without recompiling this library.
+typedef void* (*b2AllocFunction)(int32 size, void* callbackData);
+/// Use this function to override b2Free() without recompiling this library.
+typedef void (*b2FreeFunction)(void* mem, void* callbackData);
+
+/// Set alloc and free callbacks to override the default behavior of using
+/// malloc() and free() for dynamic memory allocation.
+/// Set allocCallback and freeCallback to NULL to restore the default
+/// allocator (malloc / free).
+void b2SetAllocFreeCallbacks(b2AllocFunction allocCallback,
+							 b2FreeFunction freeCallback,
+							 void* callbackData);
+
+/// Set the number of calls to b2Alloc minus the number of calls to b2Free.
+/// This can be used to disable the empty heap check in
+/// b2SetAllocFreeCallbacks() which can be useful for testing.
+void b2SetNumAllocs(const int32 numAllocs);
+
+/// Get number of calls to b2Alloc minus number of calls to b2Free.
+int32 b2GetNumAllocs();
+
+/// Logging function.
+void b2Log(const char* string, ...);
+
+/// Version numbering scheme.
+/// See http://en.wikipedia.org/wiki/Software_versioning
+struct b2Version
+{
+	int32 major;		///< significant changes
+	int32 minor;		///< incremental changes
+	int32 revision;		///< bug fixes
+};
+
+/// Current version.
+/// Version of Box2D, LiquidFun is based upon.
+extern b2Version b2_version;
+
+/// Global variable is used to identify the version of LiquidFun.
+extern const b2Version b2_liquidFunVersion;
+/// String which identifies the current version of LiquidFun.
+/// b2_liquidFunVersionString is used by Google developers to identify which
+/// applications uploaded to Google Play are using this library.  This allows
+/// the development team at Google to determine the popularity of the library.
+/// How it works: Applications that are uploaded to the Google Play Store are
+/// scanned for this version string.  We track which applications are using it
+/// to measure popularity.  You are free to remove it (of course) but we would
+/// appreciate if you left it in.
+extern const char *b2_liquidFunVersionString;
+
+#endif

+ 244 - 0
engine/source/Box2D/Common/b2SlabAllocator.h

@@ -0,0 +1,244 @@
+/*
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef B2_SLAB_ALLOCATOR_H
+#define B2_SLAB_ALLOCATOR_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <new>
+#include <Box2D/Common/b2IntrusiveList.h>
+#include <Box2D/Common/b2FreeList.h>
+#include <Box2D/Common/b2Settings.h>
+#include <Box2D/Common/b2TrackedBlock.h>
+
+/// Freelist based allocator for fixed sized items from slabs (memory
+/// preallocated from the heap).
+/// T should be a class which has a default constructor and implements the
+/// member function "b2IntrusiveList* GetListNode()".
+/// All objects in a slab are constructed when a slab is created and destructed
+/// when a slab is freed.
+template<typename T>
+class b2SlabAllocator
+{
+private:
+	// Information about a slab.
+	class Slab
+	{
+	public:
+		/// Initialize a slab with the number of items it contains.
+		Slab(uint32 numberOfItems) :
+			m_numberOfItems(numberOfItems)
+		{
+			B2_NOT_USED(m_padding);
+			// This assumes that this class is packed on at least a 4-byte
+			// boundary with no padding.  Verify the assumption.
+			b2Assert(sizeof(*this) == b2_mallocAlignment);
+		}
+
+		/// Empty destructor.
+		~Slab() { }
+
+		/// Get the number of items in this slab.
+		uint32 GetNumberOfItems() const { return m_numberOfItems; }
+
+		/// Get a pointer to the first item in the slab.
+		T* GetFirstItem() const
+		{
+			return (T*)((uint8*)(this + 1));
+		}
+
+		/// Get a pointer to the end of the slab.
+		/// NOTE: This is a pointer after the last byte of the slab not the
+		/// last item in the slab.
+		T* GetItemEnd() const { return GetFirstItem() + GetNumberOfItems(); }
+
+	private:
+		/// Number of items in the slab.
+		uint32 m_numberOfItems;
+		/// Padding to align the first item in the slab to b2_mallocAlignment.
+		uint8 m_padding[b2_mallocAlignment - sizeof(uint32)];
+	};
+
+public:
+	/// Initialize the allocator to allocate itemsPerSlab of type T for each
+	/// slab that is allocated.
+	b2SlabAllocator(const uint32 itemsPerSlab) :
+		m_itemsPerSlab(itemsPerSlab)
+	{
+	}
+
+	/// Free all allocated slabs.
+	~b2SlabAllocator()
+	{
+		FreeAllSlabs();
+	}
+
+	/// Set size of the next allocated slab using the number of items per
+	/// slab.  Setting this value to zero disables further slab allocation.
+	void SetItemsPerSlab(uint32 itemsPerSlab)
+	{
+		m_itemsPerSlab = itemsPerSlab;
+	}
+
+	// Get the size of the next allocated slab.
+	uint32 GetItemsPerSlab() const
+	{
+		return m_itemsPerSlab;
+	}
+
+	/// Allocate a item from the slab.
+	T* Allocate()
+	{
+		// Allocate a slab if needed here.
+		if (m_freeList.GetFreeList()->GetFreeList().IsEmpty() &&
+			!AllocateSlab())
+			return NULL;
+		return m_freeList.Allocate();
+	}
+
+	/// Free an item from the slab.
+	void Free(T *object)
+	{
+		m_freeList.Free(object);
+	}
+
+	/// Allocate a slab, construct instances of T and add them to the free
+	/// pool.
+	bool AllocateSlab()
+	{
+		if (!m_itemsPerSlab) return false;
+		const uint32 slabSize = sizeof(Slab) + (sizeof(T) * m_itemsPerSlab);
+		void* const memory = m_slabs.Allocate(slabSize);
+		if (!memory) return false;
+
+		Slab* const slab = new (BlockGetSlab(memory)) Slab(m_itemsPerSlab);
+		T* item = slab->GetFirstItem();
+		for (uint32 i = 0; i < m_itemsPerSlab; ++i, ++item)
+		{
+			m_freeList.AddToFreeList(new (item) T);
+		}
+		return true;
+	}
+
+	/// Free all slabs.
+	void FreeAllSlabs()
+	{
+		const b2TypedIntrusiveListNode<b2TrackedBlock>& slabList =
+			m_slabs.GetList();
+		while (!slabList.IsEmpty())
+		{
+			FreeSlab(BlockGetSlab(slabList.GetNext()->GetMemory()));
+		}
+	}
+
+	/// Free all empty slabs.
+	/// This method is slow - O(M^N) - since this class doesn't track
+	/// the association between each item and slab.
+	void FreeEmptySlabs()
+	{
+		const b2IntrusiveListNode& freeItemList =
+			m_freeList.GetFreeList()->GetFreeList();
+		const b2IntrusiveListNode* freeItemListTerminator =
+			freeItemList.GetTerminator();
+		const b2TypedIntrusiveListNode<b2TrackedBlock>& slabList =
+			m_slabs.GetList();
+		const b2TypedIntrusiveListNode<b2TrackedBlock>* slabListTerminator =
+			slabList.GetTerminator();
+		b2TrackedBlock* block = slabList.GetNext();
+		while (block != slabListTerminator)
+		{
+			// Get the Slab from the memory associated with the block.
+			Slab* const slab = BlockGetSlab(block->GetMemory());
+			block = block->GetNext();
+
+			// Determine the range of memory the Slab owns.
+			const uint8* const slabItemStart = (uint8*)slab->GetFirstItem();
+			const uint8* const slabItemEnd = (uint8*)slab->GetItemEnd();
+
+			// Count all free items that are owned by the current slab.
+			uint8 freeItems = 0;
+			bool empty = false;
+			for (b2IntrusiveListNode* itemNode = freeItemList.GetNext();
+				 itemNode != freeItemListTerminator;
+				 itemNode = itemNode->GetNext())
+			{
+				const uint8* itemNodeAddress = (uint8*)itemNode;
+				if (itemNodeAddress >= slabItemStart &&
+					itemNodeAddress <= slabItemEnd)
+				{
+					++freeItems;
+					if (slab->GetNumberOfItems() == freeItems)
+					{
+						empty = true;
+						break;
+					}
+				}
+			}
+			// If a slab is empty, free it.
+			if (empty)
+			{
+				FreeSlab(slab);
+			}
+		}
+	}
+
+	/// Get the item allocator freelist.
+	const b2TypedFreeList<T>& GetFreeList() const
+	{
+		return m_freeList;
+	}
+
+private:
+	/// Destroy all objects in a slab and free the slab.
+	void FreeSlab(Slab * const slab)
+	{
+		b2Assert(slab);
+		const uint32 numberOfItems = slab->GetNumberOfItems();
+		T* item = slab->GetFirstItem();
+		for (uint32 i = 0; i < numberOfItems; ++i, ++item)
+		{
+			item->~T();
+		}
+		slab->~Slab();
+		m_slabs.Free(slab);
+	}
+
+	/// Get a pointer to a Slab from a block of memory in m_slabs.
+	Slab* BlockGetSlab(void *memory)
+	{
+		return (Slab*)memory;
+	}
+
+	/// Get a pointer to the first item in the array of items referenced by a
+	/// Slab.
+	T* SlabGetFirstItem(Slab* slab)
+	{
+		return (T*)(slab + 1);
+	}
+
+private:
+	/// Contains a list of b2TrackedBlock instances where each b2TrackedBlock's
+	/// associated user memory contains a Slab followed by instances of T.
+	b2TrackedBlockAllocator m_slabs;
+	/// Number of items to allocate in the next allocated slab.
+	uint32 m_itemsPerSlab;
+	/// Freelist which contains instances of T.
+	b2TypedFreeList<T> m_freeList;
+};
+
+#endif  // B2_SLAB_ALLOCATOR_H

+ 120 - 83
engine/source/Box2D/Common/b2StackAllocator.cpp

@@ -1,83 +1,120 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2StackAllocator.h>
-#include <Box2D/Common/b2Math.h>
-
-b2StackAllocator::b2StackAllocator()
-{
-	m_index = 0;
-	m_allocation = 0;
-	m_maxAllocation = 0;
-	m_entryCount = 0;
-}
-
-b2StackAllocator::~b2StackAllocator()
-{
-	b2Assert(m_index == 0);
-	b2Assert(m_entryCount == 0);
-}
-
-void* b2StackAllocator::Allocate(int32 size)
-{
-	b2Assert(m_entryCount < b2_maxStackEntries);
-
-	b2StackEntry* entry = m_entries + m_entryCount;
-	entry->size = size;
-	if (m_index + size > b2_stackSize)
-	{
-		entry->data = (char*)b2Alloc(size);
-		entry->usedMalloc = true;
-	}
-	else
-	{
-		entry->data = m_data + m_index;
-		entry->usedMalloc = false;
-		m_index += size;
-	}
-
-	m_allocation += size;
-	m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
-	++m_entryCount;
-
-	return entry->data;
-}
-
-void b2StackAllocator::Free(void* p)
-{
-	b2Assert(m_entryCount > 0);
-	b2StackEntry* entry = m_entries + m_entryCount - 1;
-	b2Assert(p == entry->data);
-	if (entry->usedMalloc)
-	{
-		b2Free(p);
-	}
-	else
-	{
-		m_index -= entry->size;
-	}
-	m_allocation -= entry->size;
-	--m_entryCount;
-
-	p = NULL;
-}
-
-int32 b2StackAllocator::GetMaxAllocation() const
-{
-	return m_maxAllocation;
-}
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2StackAllocator.h>
+#include <Box2D/Common/b2Math.h>
+#include <string.h>
+
+b2StackAllocator::b2StackAllocator()
+{
+	m_index = 0;
+	m_allocation = 0;
+	m_maxAllocation = 0;
+	m_entryCount = 0;
+}
+
+b2StackAllocator::~b2StackAllocator()
+{
+	b2Assert(m_index == 0);
+	b2Assert(m_entryCount == 0);
+}
+
+void* b2StackAllocator::Allocate(int32 size)
+{
+	b2Assert(m_entryCount < b2_maxStackEntries);
+	const int32 roundedSize = (size + ALIGN_MASK) & ~ALIGN_MASK;
+	b2StackEntry* entry = m_entries + m_entryCount;
+	entry->size = roundedSize;
+	if (m_index + roundedSize > b2_stackSize)
+	{
+		entry->data = (char*)b2Alloc(roundedSize);
+		entry->usedMalloc = true;
+	}
+	else
+	{
+		entry->data = m_data + m_index;
+		entry->usedMalloc = false;
+		m_index += roundedSize;
+	}
+
+	m_allocation += roundedSize;
+	m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
+	++m_entryCount;
+
+	return entry->data;
+}
+
+void* b2StackAllocator::Reallocate(void* p, int32 size)
+{
+	b2Assert(m_entryCount > 0);
+	b2StackEntry* entry = m_entries + m_entryCount - 1;
+	b2Assert(p == entry->data);
+	B2_NOT_USED(p);
+	int32 incrementSize = size - entry->size;
+	if (incrementSize > 0)
+	{
+		if (entry->usedMalloc)
+		{
+			void* data = b2Alloc(size);
+			memcpy(data, entry->data, entry->size);
+			b2Free(entry->data);
+			entry->data = (char*)data;
+		}
+		else if (m_index + incrementSize > b2_stackSize)
+		{
+			void* data = b2Alloc(size);
+			memcpy(data, entry->data, entry->size);
+			m_index -= entry->size;
+			entry->data = (char*)data;
+			entry->usedMalloc = true;
+		}
+		else
+		{
+			m_index += incrementSize;
+			m_allocation += incrementSize;
+			m_maxAllocation = b2Max(m_maxAllocation, m_allocation);
+		}
+		entry->size = size;
+	}
+
+	return entry->data;
+}
+
+void b2StackAllocator::Free(void* p)
+{
+	b2Assert(m_entryCount > 0);
+	b2StackEntry* entry = m_entries + m_entryCount - 1;
+	b2Assert(p == entry->data);
+	if (entry->usedMalloc)
+	{
+		b2Free(p);
+	}
+	else
+	{
+		m_index -= entry->size;
+	}
+	m_allocation -= entry->size;
+	--m_entryCount;
+
+	p = NULL;
+}
+
+int32 b2StackAllocator::GetMaxAllocation() const
+{
+	return m_maxAllocation;
+}

+ 64 - 60
engine/source/Box2D/Common/b2StackAllocator.h

@@ -1,60 +1,64 @@
-/*
-* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_STACK_ALLOCATOR_H
-#define B2_STACK_ALLOCATOR_H
-
-#include <Box2D/Common/b2Settings.h>
-
-const int32 b2_stackSize = 100 * 1024;	// 100k
-const int32 b2_maxStackEntries = 32;
-
-struct b2StackEntry
-{
-	char* data;
-	int32 size;
-	bool usedMalloc;
-};
-
-// This is a stack allocator used for fast per step allocations.
-// You must nest allocate/free pairs. The code will assert
-// if you try to interleave multiple allocate/free pairs.
-class b2StackAllocator
-{
-public:
-	b2StackAllocator();
-	~b2StackAllocator();
-
-	void* Allocate(int32 size);
-	void Free(void* p);
-
-	int32 GetMaxAllocation() const;
-
-private:
-
-	char m_data[b2_stackSize];
-	int32 m_index;
-
-	int32 m_allocation;
-	int32 m_maxAllocation;
-
-	b2StackEntry m_entries[b2_maxStackEntries];
-	int32 m_entryCount;
-};
-
-#endif
+/*
+* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_STACK_ALLOCATOR_H
+#define B2_STACK_ALLOCATOR_H
+
+#include <Box2D/Common/b2Settings.h>
+
+const int32 b2_stackSize = 100 * 1024;	// 100k
+const int32 b2_maxStackEntries = 32;
+
+struct b2StackEntry
+{
+	char* data;
+	int32 size;
+	bool usedMalloc;
+};
+
+// This is a stack allocator used for fast per step allocations.
+// You must nest allocate/free pairs. The code will assert
+// if you try to interleave multiple allocate/free pairs.
+class b2StackAllocator
+{
+public:
+	enum { MIN_ALIGNMENT = sizeof(void*) }; // Must be a power of 2
+	enum { ALIGN_MASK = MIN_ALIGNMENT - 1 };
+
+	b2StackAllocator();
+	~b2StackAllocator();
+
+	void* Allocate(int32 size);
+	void* Reallocate(void* p, int32 size);
+	void Free(void* p);
+
+	int32 GetMaxAllocation() const;
+
+private:
+
+	char m_data[b2_stackSize];
+	int32 m_index;
+
+	int32 m_allocation;
+	int32 m_maxAllocation;
+
+	b2StackEntry m_entries[b2_maxStackEntries];
+	int32 m_entryCount;
+};
+
+#endif

+ 67 - 0
engine/source/Box2D/Common/b2Stat.cpp

@@ -0,0 +1,67 @@
+/*
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "b2Stat.h"
+
+#include <algorithm>
+#include <cfloat>
+
+b2Stat::b2Stat()
+{
+	Clear();
+}
+
+void b2Stat::Record( float32 t )
+{
+	m_total += t;
+	m_min = std::min(m_min,t);
+	m_max = std::max(m_max,t);
+	m_count++;
+}
+
+int b2Stat::GetCount() const
+{
+	return m_count;
+}
+
+float32 b2Stat::GetMean() const
+{
+	if (m_count == 0)
+	{
+		return 0.0f;
+	}
+	return (float32)(m_total / m_count);
+}
+
+float32 b2Stat::GetMin() const
+{
+	return m_min;
+}
+
+float32 b2Stat::GetMax() const
+{
+	return m_max;
+}
+
+void b2Stat::Clear()
+{
+	m_count = 0;
+	m_total = 0;
+	m_min = FLT_MAX;
+	m_max = -FLT_MAX;
+}
+

+ 57 - 0
engine/source/Box2D/Common/b2Stat.h

@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2013 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+#ifndef B2_STAT
+#define B2_STAT
+
+#include <Box2D/Common/b2Settings.h>
+
+/// Calculates min/max/mean of a set of samples
+class b2Stat
+{
+public:
+	b2Stat();
+
+	/// Record a sample
+	void Record( float32 t );
+
+	/// Returns the number of recorded samples
+	int GetCount() const;
+
+	/// Returns the mean of all recorded samples,
+	/// Returns 0 if there are no recorded samples
+	float32 GetMean() const;
+
+	/// Returns the min of all recorded samples,
+	/// FLT_MAX if there are no recorded samples
+	float32 GetMin() const;
+
+	/// Returns the max of all recorded samples,
+	/// -FLT_MAX if there are no recorded samples
+	float32 GetMax() const;
+
+	/// Erase all recorded samples
+	void Clear();
+private:
+
+	int m_count;
+	float64 m_total;
+	float32 m_min;
+	float32 m_max;
+};
+
+#endif

+ 134 - 100
engine/source/Box2D/Common/b2Timer.cpp

@@ -1,100 +1,134 @@
-/*
-* Copyright (c) 2011 Erin Catto http://box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include <Box2D/Common/b2Timer.h>
-
-#if defined(_WIN32)
-
-float64 b2Timer::s_invFrequency = 0.0f;
-
-#include <windows.h>
-
-b2Timer::b2Timer()
-{
-	LARGE_INTEGER largeInteger;
-
-	if (s_invFrequency == 0.0f)
-	{
-		QueryPerformanceFrequency(&largeInteger);
-		s_invFrequency = float64(largeInteger.QuadPart);
-		if (s_invFrequency > 0.0f)
-		{
-			s_invFrequency = 1000.0f / s_invFrequency;
-		}
-	}
-
-	QueryPerformanceCounter(&largeInteger);
-	m_start = float64(largeInteger.QuadPart);
-}
-
-void b2Timer::Reset()
-{
-	LARGE_INTEGER largeInteger;
-	QueryPerformanceCounter(&largeInteger);
-	m_start = float64(largeInteger.QuadPart);
-}
-
-float32 b2Timer::GetMilliseconds() const
-{
-	LARGE_INTEGER largeInteger;
-	QueryPerformanceCounter(&largeInteger);
-	float64 count = float64(largeInteger.QuadPart);
-	float32 ms = float32(s_invFrequency * (count - m_start));
-	return ms;
-}
-
-#elif defined(__linux__) || defined (__APPLE__)
-
-#include <sys/time.h>
-
-b2Timer::b2Timer()
-{
-    Reset();
-}
-
-void b2Timer::Reset()
-{
-    timeval t;
-    gettimeofday(&t, 0);
-    m_start_sec = t.tv_sec;
-    m_start_msec = t.tv_usec * 0.001f;
-}
-
-float32 b2Timer::GetMilliseconds() const
-{
-    timeval t;
-    gettimeofday(&t, 0);
-    return (t.tv_sec - m_start_sec) * 1000 + t.tv_usec * 0.001f - m_start_msec;
-}
-
-#else
-
-b2Timer::b2Timer()
-{
-}
-
-void b2Timer::Reset()
-{
-}
-
-float32 b2Timer::GetMilliseconds() const
-{
-	return 0.0f;
-}
-
-#endif
+/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include <Box2D/Common/b2Timer.h>
+
+#if defined(_WIN32)
+
+float64 b2Timer::s_invFrequency = 0.0f;
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+typedef BOOL (WINAPI *SystemGetTimeFunc)(_Out_ LARGE_INTEGER *lpFrequency);
+SystemGetTimeFunc systemGetTimeFunc = ::QueryPerformanceCounter;
+SystemGetTimeFunc systemGetFreqFunc = ::QueryPerformanceFrequency;
+
+int64 b2Timer::GetTicks()
+{
+	LARGE_INTEGER largeInteger;
+	systemGetTimeFunc(&largeInteger);
+	return largeInteger.QuadPart;
+}
+
+b2Timer::b2Timer()
+{
+	LARGE_INTEGER largeInteger;
+
+	if (s_invFrequency == 0.0f)
+	{
+		systemGetFreqFunc(&largeInteger);
+		s_invFrequency = float64(largeInteger.QuadPart);
+		if (s_invFrequency > 0.0f)
+		{
+			s_invFrequency = 1000.0f / s_invFrequency;
+		}
+	}
+
+	m_start = GetTicks();
+}
+
+void b2Timer::Reset()
+{
+	m_start = GetTicks();
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+	int64 elapsed = GetTicks() - m_start;
+	return (float32)(s_invFrequency * elapsed);
+}
+
+#elif defined(__linux__) || defined (__APPLE__)
+
+#include <sys/time.h>
+#include <time.h>
+
+// systemGetTimeFunc is defined with external linkage to allow unit
+// test to mock out the system time function
+
+#if defined(__linux__)
+
+typedef int (*SystemGetTimeFunc)(clockid_t clk_id, struct timespec *tp);
+SystemGetTimeFunc systemGetTimeFunc = ::clock_gettime;
+
+#elif defined(__APPLE__)
+
+typedef int (*SystemGetTimeFunc)(struct timeval * tp, void * tzp);
+SystemGetTimeFunc systemGetTimeFunc = ::gettimeofday;
+
+#endif
+
+int64 b2Timer::GetTicks()
+{
+	static const int NSEC_PER_SEC = 1000000000;
+
+#ifdef __linux__
+	timespec ts;
+	systemGetTimeFunc(CLOCK_MONOTONIC,&ts);
+	return ((int64)ts.tv_sec) * NSEC_PER_SEC + ts.tv_nsec;
+#else
+	timeval t;
+	systemGetTimeFunc(&t, 0);
+	return ((int64)t.tv_sec) * NSEC_PER_SEC + t.tv_usec * 1000;
+#endif
+}
+
+b2Timer::b2Timer()
+{
+	Reset();
+}
+
+void b2Timer::Reset()
+{
+	m_start = GetTicks();
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+	static const float32 kTicksToMs = 0.000001f;
+	return kTicksToMs * (float32)(GetTicks() - m_start);
+}
+
+#else
+
+b2Timer::b2Timer()
+{
+}
+
+void b2Timer::Reset()
+{
+}
+
+float32 b2Timer::GetMilliseconds() const
+{
+	return 0.0f;
+}
+
+#endif

+ 50 - 50
engine/source/Box2D/Common/b2Timer.h

@@ -1,50 +1,50 @@
-/*
-* Copyright (c) 2011 Erin Catto http://box2d.org
-*
-* This software is provided 'as-is', without any express or implied
-* warranty.  In no event will the authors be held liable for any damages
-* arising from the use of this software.
-* Permission is granted to anyone to use this software for any purpose,
-* including commercial applications, and to alter it and redistribute it
-* freely, subject to the following restrictions:
-* 1. The origin of this software must not be misrepresented; you must not
-* claim that you wrote the original software. If you use this software
-* in a product, an acknowledgment in the product documentation would be
-* appreciated but is not required.
-* 2. Altered source versions must be plainly marked as such, and must not be
-* misrepresented as being the original software.
-* 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef B2_TIMER_H
-#define B2_TIMER_H
-
-#include <Box2D/Common/b2Settings.h>
-
-/// Timer for profiling. This has platform specific code and may
-/// not work on every platform.
-class b2Timer
-{
-public:
-
-	/// Constructor
-	b2Timer();
-
-	/// Reset the timer.
-	void Reset();
-
-	/// Get the time since construction or the last reset.
-	float32 GetMilliseconds() const;
-
-private:
-
-#if defined(_WIN32)
-	float64 m_start;
-	static float64 s_invFrequency;
-#elif defined(__linux__) || defined (__APPLE__)
-	unsigned long m_start_sec;
-	unsigned long m_start_msec;
-#endif
-};
-
-#endif
+/*
+* Copyright (c) 2011 Erin Catto http://box2d.org
+* Copyright (c) 2014 Google, Inc.
+*
+* This software is provided 'as-is', without any express or implied
+* warranty.  In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef B2_TIMER_H
+#define B2_TIMER_H
+
+#include <Box2D/Common/b2Settings.h>
+
+/// Timer for profiling. This has platform specific code and may
+/// not work on every platform.
+class b2Timer
+{
+public:
+
+	/// Constructor
+	b2Timer();
+
+	/// Reset the timer.
+	void Reset();
+
+	/// Get the time since construction or the last reset.
+	float32 GetMilliseconds() const;
+
+private:
+	/// Get platform specific tick count
+	static int64 GetTicks();
+
+#if defined(_WIN32)
+	static float64 s_invFrequency;
+#endif
+	int64 m_start;
+};
+
+#endif

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