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_Debug.app
 linkmap.txt
-.vs/
+**/.vs/**
 
 # 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
 
 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
 
-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
 
@@ -28,7 +28,7 @@ After downloading a copy of the source code, the following project files for eac
 * **Android:** Android Studio
 * **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
 
@@ -40,7 +40,7 @@ The Sandbox is also an excellent framework for rapidly prototyping your own game
 
 ### 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
 
@@ -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)
 * [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
 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.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);
 }
@@ -47,7 +79,10 @@ function AssetAdmin::destroy(%this)
 
 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)

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

@@ -18,7 +18,7 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -247,7 +247,7 @@
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetEmitter.cc" />
     <ClCompile Include="..\..\source\2d\assets\ParticleAssetField.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\core\GroupedSceneController.cc" />
     <ClCompile Include="..\..\source\2d\controllers\core\PickingSceneController.cc" />
@@ -272,12 +272,15 @@
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.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\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.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\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\TextSprite.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Trigger.cc" />
@@ -316,10 +319,13 @@
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.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\b2Settings.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\b2TrackedBlock.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.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\b2WeldJoint.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\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
@@ -371,7 +382,7 @@
     <ClCompile Include="..\..\source\graphics\bitmapBmp.cc" />
     <ClCompile Include="..\..\source\graphics\bitmapJpeg.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\dglMatrix.cc" />
     <ClCompile Include="..\..\source\graphics\DynamicTexture.cc" />
@@ -589,6 +600,7 @@
     <ClCompile Include="..\..\source\spine\Animation.c" />
     <ClCompile Include="..\..\source\spine\AnimationState.c" />
     <ClCompile Include="..\..\source\spine\AnimationStateData.c" />
+    <ClCompile Include="..\..\source\spine\Array.c" />
     <ClCompile Include="..\..\source\spine\Atlas.c" />
     <ClCompile Include="..\..\source\spine\AtlasAttachmentLoader.c" />
     <ClCompile Include="..\..\source\spine\Attachment.c" />
@@ -596,18 +608,34 @@
     <ClCompile Include="..\..\source\spine\Bone.c" />
     <ClCompile Include="..\..\source\spine\BoneData.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\EventData.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\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\Skeleton.c" />
+    <ClCompile Include="..\..\source\spine\SkeletonBinary.c" />
     <ClCompile Include="..\..\source\spine\SkeletonBounds.c" />
+    <ClCompile Include="..\..\source\spine\SkeletonClipping.c" />
     <ClCompile Include="..\..\source\spine\SkeletonData.c" />
     <ClCompile Include="..\..\source\spine\SkeletonJson.c" />
     <ClCompile Include="..\..\source\spine\Skin.c" />
     <ClCompile Include="..\..\source\spine\Slot.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\stringBuffer.cc" />
     <ClCompile Include="..\..\source\string\stringStack.cc" />
@@ -651,8 +679,8 @@
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetField.h" />
     <ClInclude Include="..\..\source\2d\assets\ParticleAssetFieldCollection.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_ScriptBinding.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\ParticlePlayer.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\SceneObjectList.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\Scroller.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_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_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\TextSprite.h" />
@@ -768,11 +801,17 @@
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.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\b2IntrusiveList.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.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\b2Stat.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\b2ContactManager.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\b2WeldJoint.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\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
@@ -859,8 +904,8 @@
     <ClInclude Include="..\..\source\game\gameInterface.h" />
     <ClInclude Include="..\..\source\game\gameInterface_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\dglMac_Scriptbinding.h" />
     <ClInclude Include="..\..\source\graphics\dgl_ScriptBinding.h" />
@@ -1168,6 +1213,7 @@
     <ClInclude Include="..\..\source\spine\Animation.h" />
     <ClInclude Include="..\..\source\spine\AnimationState.h" />
     <ClInclude Include="..\..\source\spine\AnimationStateData.h" />
+    <ClInclude Include="..\..\source\spine\Array.h" />
     <ClInclude Include="..\..\source\spine\Atlas.h" />
     <ClInclude Include="..\..\source\spine\AtlasAttachmentLoader.h" />
     <ClInclude Include="..\..\source\spine\Attachment.h" />
@@ -1175,19 +1221,36 @@
     <ClInclude Include="..\..\source\spine\Bone.h" />
     <ClInclude Include="..\..\source\spine\BoneData.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\EventData.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\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\Skeleton.h" />
+    <ClInclude Include="..\..\source\spine\SkeletonBinary.h" />
     <ClInclude Include="..\..\source\spine\SkeletonBounds.h" />
+    <ClInclude Include="..\..\source\spine\SkeletonClipping.h" />
     <ClInclude Include="..\..\source\spine\SkeletonData.h" />
     <ClInclude Include="..\..\source\spine\SkeletonJson.h" />
     <ClInclude Include="..\..\source\spine\Skin.h" />
     <ClInclude Include="..\..\source\spine\Slot.h" />
     <ClInclude Include="..\..\source\spine\SlotData.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\stringBuffer.h" />
     <ClInclude Include="..\..\source\string\stringBuffer_ScriptBinding.h" />
@@ -1286,6 +1349,9 @@
   <ItemGroup>
     <Image Include="Torque 2D.ico" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

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

@@ -199,6 +199,9 @@
     <Filter Include="bitmapFont">
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Box2D\Particle">
+      <UniqueIdentifier>{b2903a96-6c49-4961-82a8-f1832989d4a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1173,9 +1176,6 @@
     <ClCompile Include="..\..\source\platformWin32\nativeDialogs\win32FileDialog.cc">
       <Filter>platformWin32\nativeDialogs</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\graphics\color.cc">
-      <Filter>graphics</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\2d\assets\ParticleAsset.cc">
       <Filter>2d\assets</Filter>
     </ClCompile>
@@ -1350,12 +1350,6 @@
     <ClCompile Include="..\..\source\spine\SlotData.c">
       <Filter>spine</Filter>
     </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">
       <Filter>audio</Filter>
     </ClCompile>
@@ -1384,6 +1378,99 @@
     <ClCompile Include="..\..\source\gui\guiTextCtrl.cc">
       <Filter>gui</Filter>
     </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>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -2178,9 +2265,6 @@
     <ClInclude Include="..\..\source\algorithm\hashFunction.h">
       <Filter>algorithm</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\graphics\color.h">
-      <Filter>graphics</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\collection\bitMatrix.h">
       <Filter>collection</Filter>
     </ClInclude>
@@ -2769,9 +2853,6 @@
     <ClInclude Include="..\..\source\console\expando_ScriptBinding.h">
       <Filter>console</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\graphics\color_ScriptBinding.h">
-      <Filter>graphics</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\sim\simObject_ScriptBinding.h">
       <Filter>sim</Filter>
     </ClInclude>
@@ -3031,18 +3112,6 @@
     <ClInclude Include="..\..\source\spine\spine.h">
       <Filter>spine</Filter>
     </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">
       <Filter>audio</Filter>
     </ClInclude>
@@ -3103,6 +3172,129 @@
     <ClInclude Include="..\..\source\gui\guiTextCtrl.h">
       <Filter>gui</Filter>
     </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>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
@@ -3124,4 +3316,9 @@
   <ItemGroup>
     <Image Include="Torque 2D.ico" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s">
+      <Filter>Box2D\Particle</Filter>
+    </None>
+  </ItemGroup>
 </Project>

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

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

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

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

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

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

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

@@ -46,7 +46,7 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <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
 //
 
-1 TEXTINCLUDE DISCARDABLE 
+1 TEXTINCLUDE DISCARDABLE
 BEGIN
     "resource.h\0"
 END
 
-2 TEXTINCLUDE DISCARDABLE 
+2 TEXTINCLUDE DISCARDABLE
 BEGIN
     "#include ""afxres.h""\r\n"
     "\0"
 END
 
-3 TEXTINCLUDE DISCARDABLE 
+3 TEXTINCLUDE DISCARDABLE
 BEGIN
     "\r\n"
     "\0"
@@ -107,4 +107,3 @@ END
 
 /////////////////////////////////////////////////////////////////////////////
 #endif    // not APSTUDIO_INVOKED
-

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

@@ -18,7 +18,7 @@
     <ProjectGuid>{1564A07D-230E-4C90-AEE6-52AC9A58D6C9}</ProjectGuid>
     <RootNamespace>TorqueGame</RootNamespace>
     <ProjectName>Torque2D</ProjectName>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -272,10 +272,12 @@
     <ClCompile Include="..\..\source\2d\gui\SceneWindow.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\CompositeSprite.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\SceneObjectList.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\SceneObjectSet.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\SkeletonObject.cc" />
     <ClCompile Include="..\..\source\2d\sceneobject\Sprite.cc" />
@@ -316,10 +318,13 @@
     <ClCompile Include="..\..\source\Box2D\Collision\Shapes\b2PolygonShape.cpp" />
     <ClCompile Include="..\..\source\Box2D\Common\b2BlockAllocator.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\b2Settings.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\b2TrackedBlock.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2Body.cpp" />
     <ClCompile Include="..\..\source\Box2D\Dynamics\b2ContactManager.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\b2WeldJoint.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\collection\bitTables.cc" />
     <ClCompile Include="..\..\source\collection\hashTable.cc" />
@@ -704,6 +714,8 @@
     <ClInclude Include="..\..\source\2d\sceneobject\CompositeSprite_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\ParticlePlayer.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\SceneObjectList.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\Scroller.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_ScriptBinding.h" />
     <ClInclude Include="..\..\source\2d\sceneobject\SkeletonObject.h" />
@@ -778,11 +792,17 @@
     <ClInclude Include="..\..\source\Box2D\Collision\Shapes\b2Shape.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2BlockAllocator.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\b2IntrusiveList.h" />
     <ClInclude Include="..\..\source\Box2D\Common\b2Math.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\b2Stat.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\b2ContactManager.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\b2WeldJoint.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\collection\bitMatrix.h" />
     <ClInclude Include="..\..\source\collection\bitSet.h" />
@@ -1300,7 +1326,10 @@
       <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="..\..\source\Box2D\Particle\b2ParticleAssembly.neon.s" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

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

@@ -199,6 +199,9 @@
     <Filter Include="bitmapFont">
       <UniqueIdentifier>{447ecd65-a7a2-4e18-9c55-b53356c6f7a9}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Box2D\Particle">
+      <UniqueIdentifier>{b2903a96-6c49-4961-82a8-f1832989d4a4}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\source\audio\audio.cc">
@@ -1414,6 +1417,36 @@
     <ClCompile Include="..\..\source\platform\platformNet.cpp" />
     <ClCompile Include="..\..\source\platform\platformNetAsync.cpp" />
     <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>
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -3156,6 +3189,54 @@
     <ClInclude Include="..\..\source\gui\containers\guiScrollCtrl_ScriptBinding.h">
       <Filter>gui\containers</Filter>
     </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>
     <CustomBuild Include="..\..\source\math\mMath_ASM.asm">
@@ -3174,4 +3255,9 @@
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
   </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>
     <RootNamespace>libogg</RootNamespace>
     <Keyword>Win32Proj</Keyword>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -179,4 +179,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>

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

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

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

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

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

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

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

@@ -46,7 +46,7 @@
   </ItemGroup>
   <PropertyGroup Label="Globals">
     <ProjectGuid>{86CB2525-0CF3-40D3-BF42-A0A95035EE8C}</ProjectGuid>
-    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
@@ -182,4 +182,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </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;
 }
 
+//-----------------------------------------------------------------------------
+
+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[] =
@@ -132,7 +182,11 @@ ParticleAssetEmitter::ParticleAssetEmitter() :
                             mEmitterName( StringTable->EmptyString ),
                             mOwner( NULL ),
                             mEmitterType( POINT_EMITTER ),
+                            mPhysicsParticleType(b2_waterParticle),
+                            mPhysicsParticles(false),
                             mEmitterOffset( 0.0f, 0.0f),
+                            mTargetParticle(false),
+                            mTargetPosition(0.0f, 0.0f),
                             mEmitterAngle( 0.0f ),
                             mEmitterSize( 10.0f, 10.0f ),
                             mFixedAspect( true ),
@@ -224,6 +278,14 @@ void ParticleAssetEmitter::initPersistFields()
     addProtectedField("EmitterName", TypeString, Offset(mEmitterName, ParticleAssetEmitter), &setEmitterName, &defaultProtectedGetFn, &defaultProtectedWriteFn, "");
     addProtectedField("EmitterType", TypeEnum, Offset(mEmitterType, ParticleAssetEmitter), &setEmitterType, &defaultProtectedGetFn, &writeEmitterType, 1, &EmitterTypeTable);
     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("EmitterSize", TypeVector2, Offset(mEmitterSize, ParticleAssetEmitter), &setEmitterSize, &defaultProtectedGetFn, &writeEmitterSize, "");
     addProtectedField("FixedAspect", TypeBool, Offset(mFixedAspect, ParticleAssetEmitter), &setFixedAspect, &defaultProtectedGetFn, &writeFixedAspect, "");

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

@@ -71,6 +71,26 @@ public:
         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:
     typedef SimObject Parent;
 
@@ -91,7 +111,14 @@ private:
     F32                                     mRandomArc;
     F32                                     mFixedAngleOffset;
     Vector2                                 mPivotPoint;
-
+    //Physics Particles
+    PhysicsParticleType                     mPhysicsParticleType;
+    bool                                    mPhysicsParticles;
+    //Physics Particles end---
+    //Particle Target
+    bool                                    mTargetParticle;
+    Vector2                                 mTargetPosition;
+    //Particle Target end---
     bool                                    mLinkEmissionRotation;
     bool                                    mIntenseParticles;
     bool                                    mSingleParticle;
@@ -157,6 +184,18 @@ public:
     inline const Vector2& getFixedForceDirection( void ) const { return mFixedForceDirection; }
     inline void setOrientationType( const ParticleOrientationType particleOrientationType ) { mOrientationType = particleOrientationType; refreshAsset(); }
     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 bool getKeepAligned( void ) const { return mKeepAligned; }
     inline void setAlignedAngleOffset( const F32 angleOffset ) { mAlignedAngleOffset = angleOffset; refreshAsset(); }
@@ -250,6 +289,10 @@ public:
 
     static EmitterType getEmitterTypeEnum(const char* label);
     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 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     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     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     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; }
@@ -278,6 +327,13 @@ protected:
     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     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     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; }

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

@@ -123,6 +123,63 @@ ConsoleMethodWithDocs(ParticleAssetEmitter, getEmitterOffset, ConsoleString, 2,
     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.

+ 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.
 //-----------------------------------------------------------------------------
 
-ConsoleMethodGroupBeginWithDocs(SkeletonAsset, AssetBase)
+ConsoleMethodGroupBeginWithDocs(SpineAsset, AssetBase)
 
 /*! 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.
-    @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 Vector2* pVertexArray,
         const Vector2* pTextureArray,
-        TextureHandle& texture,
-        const ColorF& color )
+		const ColorF*  pColorArray,
+		TextureHandle& texture)
 {
     // Debug Profiling.
     PROFILE_SCOPE(BatchRender_SubmitTriangles);
@@ -117,28 +117,17 @@ void BatchRender::SubmitTriangles(
     // Calculate triangle count.
     const U32 triangleCount = vertexCount / 3;
 
-    // Would we exceed the triangle buffer size?
     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 );
     }
-    // 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?
@@ -171,28 +160,19 @@ void BatchRender::SubmitTriangles(
         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 )
     {
-        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++);
-    }
+	}
 
     // Stats.
     mpDebugStats->batchTrianglesSubmitted += triangleCount;

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

@@ -44,7 +44,7 @@
 #endif
 
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 
 //-----------------------------------------------------------------------------
@@ -116,6 +116,8 @@ public:
     BatchRender();
     virtual ~BatchRender();
 
+	static const U32 maxVertexCount = BATCHRENDER_BUFFERSIZE; 
+
     /// Set the strict order mode.
     inline void setStrictOrderMode( const bool strictOrder, const bool forceFlush = false )
     {
@@ -225,12 +227,12 @@ public:
     ///   |\      |\
     ///   | \     | \
     ///  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.
     /// 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.
 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.
 
 #endif // _CORE_UTILITY_H_

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

@@ -218,43 +218,96 @@ const ImageAsset::FrameArea& ImageFrameProviderCore::getProviderImageFrameArea(
 //------------------------------------------------------------------------------
 
 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
 {
     // Validate frame provider.

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

@@ -110,7 +110,29 @@ public:
         const Vector2& vertexPos3,
         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.
     inline bool setImage( const char* pImageAssetId ) { return setImage( pImageAssetId, mImageFrame ); }
@@ -121,7 +143,7 @@ public:
     inline U32 getImageFrame( void ) const { return mImageFrame; }
     virtual bool setNamedImageFrame( const char* frame );
     inline StringTableEntry getNamedImageFrame( void ) const { return mNamedImageFrame; }
-
+	
     /// Animated-Image Frame.
     virtual bool setAnimation( const char* pAnimationAssetId );
     inline StringTableEntry getAnimation( void ) const { return mpAnimationAsset->getAssetId(); }

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

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

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

@@ -54,7 +54,9 @@ SpriteBatch::SpriteBatch() :
     mBatchTransformId = 0;
 
     // Reset local extents.
-    mLocalExtents.SetZero();
+	mLocalAABB.lowerBound.SetZero();
+	mLocalAABB.upperBound.SetZero();
+	mLocalExtents.SetZero();
     mLocalExtentsDirty = true;
 }
 
@@ -96,9 +98,6 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
     // Set the sort mode.
     pSceneRenderQueue->setSortMode( getBatchSortMode() );
 
-    // Calculate local AABB.
-    const b2AABB localAABB = calculateLocalAABB( pSceneRenderState->mRenderAABB );
-
     // Do we have a sprite batch query?
     if ( mpSpriteBatchQuery != NULL )
     {
@@ -108,8 +107,11 @@ void SpriteBatch::prepareRender( SceneRenderObject* pSceneRenderObject, const Sc
         // Yes, so fetch sprite batch query and clear results.
         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.
         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.
     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 )
         return;
 
@@ -1287,26 +1299,22 @@ void SpriteBatch::updateLocalExtents( void )
     typeSpriteBatchHash::iterator spriteItr = mSprites.begin();
 
     // 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 )
     {
-        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;
     U32                             mBatchTransformId;
 
+	b2AABB							mLocalAABB;
     Vector2                         mLocalExtents;
     bool                            mLocalExtentsDirty;
 
@@ -86,6 +87,7 @@ public:
     inline void setLocalExtentsDirty( void ) { mLocalExtentsDirty = true; }
     inline bool getLocalExtentsDirty( void ) const { return mLocalExtentsDirty; }
     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 destroyQueryProxy( SpriteBatchItem* pSpriteBatchItem );
@@ -201,7 +203,7 @@ protected:
     void integrateSprites(const F32 totalTime, const F32 elapsedTime, DebugStats* pDebugStats);
 
     void setBatchTransform( const b2Transform& batchTransform );
-    void updateLocalExtents( void );
+    void updateLocalExtents(const b2AABB *precalculatedLocalAABB = NULL);
 
     void createSpriteBatchQuery( void );
     void destroySpriteBatchQuery( void );

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

@@ -97,6 +97,7 @@ void SpriteBatchItem::resetState( void )
 
     mVisible = true;
     mExplicitMode = false;
+	mTriangleRun = false;
 
     mLocalPosition.SetZero();
     for (U32 i = 0; i < 4; i++)
@@ -222,24 +223,64 @@ void SpriteBatchItem::render( BatchRender* pBatchRenderer, const SceneRenderRequ
     pBatchRenderer->setAlphaTestMode( pSceneRenderRequest );
 
     // 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 )
         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)
     {
-        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[2].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;
 
 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
     {
         const static S32 MAX_ARGUMENTS = 6;
@@ -199,7 +217,12 @@ protected:
 
     Vector2             mLocalPosition;
     Vector2             mExplicitVerts[4];
-    F32                 mLocalAngle;
+	Vector2             mExplicitUVs[4];
+
+	bool				mTriangleRun;
+	drawData			mDrawData;
+
+	F32                 mLocalAngle;
     Vector2             mSize;
     F32                 mDepth;
     bool                mFlipX;
@@ -249,10 +272,14 @@ public:
     inline void setExplicitMode( const bool explicitMode ) { mExplicitMode = explicitMode; }
     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; }
 
-    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 F32 getLocalAngle( void ) const { return mLocalAngle; }

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

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

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

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

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

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

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

@@ -32,7 +32,7 @@
 #endif
 
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 
 // 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(),
                                                                 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.
         // NOTE:-   We're actually interested in half the emission arc!
         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
 
 #ifndef _COLOR_H_
-#include "graphics/color.h"
+#include "graphics/gColor.h"
 #endif
 
 #ifndef _BITSTREAM_H_
@@ -581,7 +581,7 @@ void SceneObject::preIntegrate( const F32 totalTime, const F32 elapsedTime, Debu
    // Finish if nothing is dirty.
     if ( !mSpatialDirty )
         return;
-
+    
     // Reset spatial changed.
     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