PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/starLiGHT.Engine/starLiGHT.Physic2D/starLiGHT.Physic2D/Collision/BroadPhase.cs

#
C# | 423 lines | 230 code | 58 blank | 135 comment | 42 complexity | 96a5f90ee45ea70b3784cc987c560b24 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0
  1. #region Using directives
  2. using System;
  3. using Microsoft.Xna.Framework;
  4. using System.Diagnostics;
  5. #endregion
  6. #region COPYRIGHT
  7. /*
  8. Copyright (c) 2008, 2009, 2010
  9. Roland Rosenkranz (Glatzemann@email.de)
  10. */
  11. #endregion
  12. #region LICENSE
  13. /*
  14. This file is part of starLiGHT.Collision.
  15. starLiGHT.Collision is free software: you can redistribute it and/or modify
  16. it under the terms of the GNU Lesser General Public License as published by
  17. the Free Software Foundation, either version 3 of the License, or
  18. (at your option) any later version.
  19. starLiGHT.Collision is distributed in the hope that it will be useful,
  20. but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. GNU Lesser General Public License for more details.
  23. You should have received a copy of the GNU Lesser General Public License
  24. along with starLiGHT.Collision. If not, see <http://www.gnu.org/licenses/>.
  25. ADDITIONAL (commercial) LICENSES for starLiGHT.Collision are available on request.
  26. */
  27. #endregion
  28. #region Box2D Copyright
  29. /*
  30. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  31. *
  32. * This software is provided 'as-is', without any express or implied
  33. * warranty. In no event will the authors be held liable for any damages
  34. * arising from the use of this software.
  35. * Permission is granted to anyone to use this software for any purpose,
  36. * including commercial applications, and to alter it and redistribute it
  37. * freely, subject to the following restrictions:
  38. * 1. The origin of this software must not be misrepresented; you must not
  39. * claim that you wrote the original software. If you use this software
  40. * in a product, an acknowledgment in the product documentation would be
  41. * appreciated but is not required.
  42. * 2. Altered source versions must be plainly marked as such, and must not be
  43. * misrepresented as being the original software.
  44. * 3. This notice may not be removed or altered from any source distribution.
  45. */
  46. #endregion
  47. #region Version Stuff
  48. // **************[ starLiGHT.Engine SVN ]**********************
  49. // * $Rev:: 1486 $: Revision of last commit *
  50. // * $Author:: glatzemann $: Author of last commit *
  51. // * $Date:: 2010-10-08 15:55:47 #$: Date of last commit *
  52. // ************************************************************
  53. // **************[ Box2D-Repository Info ]*********************
  54. // Header-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/b2BroadPhase.h
  55. // Revision : r142
  56. // Change-Date: 2011-02-03
  57. //
  58. // Source-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/b2BroadPhase.cpp
  59. // Revision : r142
  60. // Change-Date: 2011-02-03
  61. //
  62. // Status : Finished!
  63. #endregion
  64. namespace starLiGHT.Physic.TwoD
  65. {
  66. public struct Pair : IComparable<Pair>, IEquatable<Pair>
  67. {
  68. public Int32 proxyIdA;
  69. public Int32 proxyIdB;
  70. public Int32 next;
  71. public int CompareTo(Pair other)
  72. {
  73. if (proxyIdA < other.proxyIdA)
  74. {
  75. return -1;
  76. }
  77. else if (proxyIdA == other.proxyIdA)
  78. {
  79. if (proxyIdB < other.proxyIdB)
  80. {
  81. return -1;
  82. }
  83. else if (proxyIdB == other.proxyIdB)
  84. {
  85. return 0;
  86. }
  87. }
  88. return 1;
  89. }
  90. public static bool operator == (Pair me, Pair other)
  91. {
  92. return (me.proxyIdA == other.proxyIdB && me.proxyIdB == other.proxyIdB);
  93. }
  94. public static bool operator !=(Pair me, Pair other)
  95. {
  96. return (me.proxyIdA != other.proxyIdB || me.proxyIdB != other.proxyIdB);
  97. }
  98. public override bool Equals(object obj)
  99. {
  100. return this == (Pair)obj;
  101. }
  102. public override int GetHashCode()
  103. {
  104. return base.GetHashCode();
  105. }
  106. #region IEquatable<b2Pair> Member
  107. public bool Equals(Pair other)
  108. {
  109. return (proxyIdA == other.proxyIdA && proxyIdB == other.proxyIdB);
  110. }
  111. #endregion
  112. }
  113. /// <summary>
  114. /// The broad-phase is used for computing pairs and performing volume queries and ray casts.
  115. /// This broad-phase does not persist pairs. Instead, this reports potentially new pairs.
  116. /// It is up to the client to consume the new pairs and to track subsequent overlap.
  117. /// </summary>
  118. public class BroadPhase : WorldQueryWrapper
  119. {
  120. internal static int e_nullProxy = -1;
  121. #region Member variables
  122. DynamicTree m_tree = new DynamicTree();
  123. Int32 m_proxyCount;
  124. Int32[] m_moveBuffer;
  125. Int32 m_moveCapacity;
  126. Int32 m_moveCount;
  127. Pair[] m_pairBuffer;
  128. Int32 m_pairCapacity;
  129. Int32 m_pairCount;
  130. Int32 m_queryProxyId;
  131. #endregion
  132. public BroadPhase()
  133. {
  134. m_proxyCount = 0;
  135. m_pairCapacity = 16;
  136. m_pairCount = 0;
  137. m_pairBuffer = new Pair[m_pairCapacity];
  138. m_moveCapacity = 16;
  139. m_moveCount = 0;
  140. m_moveBuffer = new Int32[m_moveCapacity];
  141. }
  142. ~BroadPhase()
  143. {
  144. m_moveBuffer = null;
  145. m_pairBuffer = null;
  146. }
  147. ///<summary>
  148. /// Create a proxy with an initial AABB. Pairs are not reported until UpdatePairs is called.
  149. ///</summary>
  150. ///<param name="aabb"></param>
  151. ///<param name="userData"></param>
  152. public Int32 CreateProxy(AABB aabb, object userData)
  153. {
  154. Int32 proxyId = m_tree.CreateProxy(aabb, userData);
  155. ++m_proxyCount;
  156. BufferMove(proxyId);
  157. return proxyId;
  158. }
  159. /// <summary>
  160. /// Destroy a proxy. It is up to the client to remove any pairs.
  161. /// </summary>
  162. /// <param name="proxyId"></param>
  163. public void DestroyProxy(Int32 proxyId)
  164. {
  165. UnBufferMove(proxyId);
  166. --m_proxyCount;
  167. m_tree.DestroyProxy(proxyId);
  168. }
  169. ///<summary>
  170. ///Call MoveProxy as many times as you like, then when you are done.
  171. ///call UpdatePairs to finalize the proxy pairs (for your time step).
  172. ///</summary>
  173. ///<param name="aabb"></param>
  174. ///<param name="proxyId"></param>
  175. public void MoveProxy(Int32 proxyId, ref AABB aabb, Vector2 displacement)
  176. {
  177. bool buffer = m_tree.MoveProxy(proxyId, ref aabb, displacement);
  178. if (buffer)
  179. {
  180. BufferMove(proxyId);
  181. }
  182. }
  183. /// <summary>
  184. /// Call to trigger a re-processing of it's pairs on the next call to UpdatePairs.
  185. /// </summary>
  186. /// <param name="proxyId"></param>
  187. public void TouchProxy(int proxyId)
  188. {
  189. BufferMove(proxyId);
  190. }
  191. /// <summary>
  192. /// Get the fat AABB for a proxy.
  193. /// </summary>
  194. /// <param name="proxyId"></param>
  195. /// <returns></returns>
  196. public AABB GetFatAABB(Int32 proxyId)
  197. {
  198. return m_tree.GetFatAABB(proxyId);
  199. }
  200. /// <summary>
  201. /// Get user data from a proxy. Returns NULL if the id is invalid.
  202. /// </summary>
  203. /// <param name="proxyId"></param>
  204. /// <returns></returns>
  205. public Object GetUserData(Int32 proxyId)
  206. {
  207. return m_tree.GetUserData(proxyId);
  208. }
  209. /// <summary>
  210. /// Test overlap of fat AABBs.
  211. /// </summary>
  212. /// <param name="p1"></param>
  213. /// <param name="p2"></param>
  214. /// <returns></returns>
  215. public bool TestOverlap(Int32 proxyIdA, Int32 proxyIdB)
  216. {
  217. AABB aabbA = m_tree.GetFatAABB(proxyIdA);
  218. AABB aabbB = m_tree.GetFatAABB(proxyIdB);
  219. //return TestOverlap(aabbA, aabbB);
  220. // manual inline
  221. Vector2 d1 = aabbB.lowerBound - aabbA.upperBound;
  222. Vector2 d2 = aabbA.lowerBound - aabbB.upperBound;
  223. if (d1.X > 0.0f || d1.Y > 0.0f) return false;
  224. if (d2.X > 0.0f || d2.Y > 0.0f) return false;
  225. return true;
  226. }
  227. /// <summary>
  228. /// Get the number of proxies.
  229. /// </summary>
  230. /// <returns></returns>
  231. public Int32 GetProxyCount()
  232. {
  233. return m_proxyCount;
  234. }
  235. /// <summary>
  236. /// Update the pairs. This results in pair callbacks. This can only add pairs.
  237. /// </summary>
  238. /// <param name="callback"></param>
  239. public void UpdatePairs(ContactManager callback)
  240. {
  241. // Reset pair buffer
  242. m_pairCount = 0;
  243. Int32 i;
  244. // Perform tree queries for all moving proxies.
  245. for (i = 0; i < m_moveCount; ++i)
  246. {
  247. m_queryProxyId = m_moveBuffer[i];
  248. if (m_queryProxyId == e_nullProxy)
  249. {
  250. continue;
  251. }
  252. // We have to query the tree with the fat AABB so that
  253. // we don't fail to create a pair that may touch later.
  254. AABB fatAABB = m_tree.GetFatAABB(m_queryProxyId);
  255. // Query tree, create pairs and add them pair buffer.
  256. m_tree.Query(this, ref fatAABB);
  257. }
  258. // Reset move buffer
  259. m_moveCount = 0;
  260. // Sort the pair buffer to expose duplicates.
  261. Array.Sort(m_pairBuffer, 0, m_pairCount);
  262. // Send the pairs back to the client.
  263. i = 0;
  264. while (i < m_pairCount)
  265. {
  266. Pair primaryPair = m_pairBuffer[i];
  267. Object userDataA = m_tree.GetUserData(primaryPair.proxyIdA);
  268. Object userDataB = m_tree.GetUserData(primaryPair.proxyIdB);
  269. callback.AddPair(userDataA, userDataB);
  270. ++i;
  271. // Skip any duplicate pairs.
  272. while (i < m_pairCount)
  273. {
  274. Pair pair = m_pairBuffer[i];
  275. if (pair.proxyIdA != primaryPair.proxyIdA || pair.proxyIdB != primaryPair.proxyIdB)
  276. {
  277. break;
  278. }
  279. ++i;
  280. }
  281. }
  282. // Try to keep the tree balanced.
  283. m_tree.Rebalance(4);
  284. }
  285. /// <summary>
  286. /// Query an AABB for overlapping proxies. The callback class is called for each proxy that overlaps the supplied AABB.
  287. /// </summary>
  288. /// <param name="callback"></param>
  289. /// <param name="aabb"></param>
  290. public void Query(WorldQueryWrapper callback, ref AABB aabb)
  291. {
  292. m_tree.Query(callback, ref aabb);
  293. }
  294. ///<summary>
  295. /// Ray-cast against the proxies in the tree. This relies on the callback
  296. /// to perform a exact ray-cast in the case were the proxy contains a shape.
  297. /// The callback also performs the any collision filtering. This has performance
  298. /// roughly equal to k * log(n), where k is the number of collisions and n is the
  299. /// number of proxies in the tree.
  300. /// <param name="input">the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
  301. /// <param name="callback">a callback class that is called for each proxy that is hit by the ray. </param>
  302. /// </summary>
  303. internal void RayCast(RayCastCallbackInternal callback, ref RayCastInput input)
  304. {
  305. m_tree.RayCast(callback, ref input);
  306. }
  307. /// <summary>
  308. /// Compute the height of the embedded tree.
  309. /// </summary>
  310. /// <returns></returns>
  311. public Int32 ComputeHeight()
  312. {
  313. return m_tree.ComputeHeight();
  314. }
  315. void BufferMove(Int32 proxyId)
  316. {
  317. if (m_moveCount == m_moveCapacity)
  318. {
  319. Int32[] oldBuffer = m_moveBuffer;
  320. m_moveCapacity *= 2;
  321. m_moveBuffer = new Int32[m_moveCapacity];
  322. Array.Copy(oldBuffer, m_moveBuffer, m_moveCount);
  323. }
  324. m_moveBuffer[m_moveCount] = proxyId;
  325. ++m_moveCount;
  326. }
  327. void UnBufferMove(Int32 proxyId)
  328. {
  329. for (Int32 i = 0; i < m_moveCount; ++i)
  330. {
  331. if (m_moveBuffer[i] == proxyId)
  332. {
  333. m_moveBuffer[i] = e_nullProxy;
  334. return;
  335. }
  336. }
  337. }
  338. public override bool QueryCallback(Int32 proxyId)
  339. {
  340. // A proxy cannot form a pair with itself.
  341. if (proxyId == m_queryProxyId)
  342. {
  343. return true;
  344. }
  345. // Grow the pair buffer as needed.
  346. if (m_pairCount == m_pairCapacity)
  347. {
  348. Pair[] oldBuffer = m_pairBuffer;
  349. m_pairCapacity *= 2;
  350. m_pairBuffer = new Pair[m_pairCapacity];
  351. Array.Copy(oldBuffer, m_pairBuffer, m_pairCount);
  352. oldBuffer = null;
  353. }
  354. m_pairBuffer[m_pairCount].proxyIdA = System.Math.Min(proxyId, m_queryProxyId);
  355. m_pairBuffer[m_pairCount].proxyIdB = System.Math.Max(proxyId, m_queryProxyId);
  356. ++m_pairCount;
  357. return true;
  358. }
  359. }
  360. }