PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/PhysicsEngines/Jitter/JitterPhysics.cs

#
C# | 477 lines | 319 code | 52 blank | 106 comment | 23 complexity | e5d96d2d4c8ed130e9a176ec59a00d52 MD5 | raw file
Possible License(s): Apache-2.0
  1. using Delta.PhysicsEngines.Enums;
  2. using Delta.Utilities;
  3. using Delta.Utilities.Datatypes;
  4. using Jitter;
  5. using Jitter.Collision;
  6. using Jitter.Collision.Shapes;
  7. using Jitter.Dynamics;
  8. using Jitter.LinearMath;
  9. using NUnit.Framework;
  10. namespace Delta.PhysicsEngines.Jitter
  11. {
  12. /// <summary>
  13. /// Jitter physics implementation.
  14. /// </summary>
  15. public class JitterPhysics : Physics
  16. {
  17. #region Constants
  18. private const float PlaneHeight = 1.0f;
  19. #endregion
  20. #region Internal
  21. #region collisionSystem (Internal)
  22. internal CollisionSystem collisionSystem;
  23. #endregion
  24. #region jitterWorld (Internal)
  25. internal World jitterWorld;
  26. #endregion
  27. #endregion
  28. #region Private
  29. #region multithread (Private)
  30. private bool multithread;
  31. #endregion
  32. #endregion
  33. #region Constructors
  34. /// <summary>
  35. /// Initializes a new instance of the <see cref="JitterPhysicsManager"/> class.
  36. /// </summary>
  37. public JitterPhysics()
  38. : base(false, "Jitter")
  39. {
  40. collisionSystem = new CollisionSystemSAP();
  41. jitterWorld = new World(collisionSystem);
  42. jitterWorld.AllowDeactivation = true;
  43. jitterWorld.SetIterations(100, 100);
  44. jitterWorld.SetDampingFactors(0.95f, 0.95f);
  45. jitterWorld.SetInactivityThreshold(0.005f, 0.005f, 10);
  46. jitterWorld.Gravity = JitterDatatypesMapping.ConvertSlow(DefaultGravity);
  47. jitterWorld.Events.BodiesBeginCollide +=
  48. Events_BodiesBeginCollide;
  49. jitterWorld.Events.BodiesEndCollide +=
  50. Events_BodiesEndCollide;
  51. // Create ground body.
  52. CreateGroundBody();
  53. }
  54. #endregion
  55. #region IsShapeSupported (Public)
  56. /// <summary>
  57. /// Gets whether the current physics module supports given shape type.
  58. /// </summary>
  59. /// <param name="shapeType">Type of the shape.</param>
  60. /// <returns>
  61. /// <c>true</c> if [is shape supported] [the specified shape type]; otherwise, <c>false</c>.
  62. /// </returns>
  63. public override bool IsShapeSupported(ShapeType shapeType)
  64. {
  65. switch (shapeType)
  66. {
  67. case ShapeType.Box:
  68. case ShapeType.Sphere:
  69. case ShapeType.Capsule:
  70. case ShapeType.Triangle:
  71. case ShapeType.Terrain:
  72. // Jitter supports this too.
  73. case ShapeType.Cone:
  74. case ShapeType.Cylinder:
  75. return true;
  76. }
  77. return false;
  78. }
  79. #endregion
  80. #region IsJointSupported (Public)
  81. /// <summary>
  82. /// Gets whether the current physics module supports given joint type.
  83. /// </summary>
  84. /// <param name="jointType">Type of the shape.</param>
  85. /// <returns>
  86. /// <c>true</c> if the specified shape type is supported, <c>false</c> otherwise.
  87. /// </returns>
  88. public override bool IsJointSupported(JointType jointType)
  89. {
  90. switch (jointType)
  91. {
  92. case JointType.FixedAngle:
  93. case JointType.SingleBodyPointOnLine:
  94. case JointType.PointOnLine:
  95. case JointType.PointOnPoint:
  96. case JointType.PointPointDistance:
  97. case JointType.Hinge:
  98. case JointType.Prismatic:
  99. return true;
  100. }
  101. return false;
  102. }
  103. #endregion
  104. #region IsFeatureSupported (Public)
  105. /// <summary>
  106. /// Gets whether the current physics module supports given feature.
  107. /// </summary>
  108. /// <param name="support">The support.</param>
  109. /// <returns>
  110. /// <c>true</c> if [is feature supported] [the specified support]; otherwise, <c>false</c>.
  111. /// </returns>
  112. public override bool IsFeatureSupported(FeatureSupport support)
  113. {
  114. switch (support)
  115. {
  116. case FeatureSupport.Joint:
  117. case FeatureSupport.Multithreading:
  118. return true;
  119. }
  120. return false;
  121. }
  122. #endregion
  123. #region SetGroundPlane (Public)
  124. /// <summary>
  125. /// Implementation of SetGroundPlane
  126. /// </summary>
  127. /// <param name="enable">True to enable the ground plane, false otherwise.</param>
  128. /// <param name="height">The height of the plane.</param>
  129. public override void SetGroundPlane(bool enable, float height)
  130. {
  131. RigidBody jitterRigidBody = ((JitterBody)groundBody).Body;
  132. jitterRigidBody.Position = new JVector(0, 0, height - (PlaneHeight * 0.5f));
  133. // Check if we need to add it
  134. if (enable)
  135. {
  136. if (jitterWorld.RigidBodies.Contains(jitterRigidBody) == false)
  137. {
  138. jitterWorld.AddBody(jitterRigidBody);
  139. }
  140. }
  141. else
  142. {
  143. if (jitterWorld.RigidBodies.Contains(jitterRigidBody))
  144. {
  145. jitterWorld.RemoveBody(jitterRigidBody);
  146. }
  147. }
  148. }
  149. #endregion
  150. #region Methods (Private)
  151. #region CreateGroundBody
  152. /// <summary>
  153. /// Create the body that will be used as ground.
  154. /// </summary>
  155. private void CreateGroundBody()
  156. {
  157. RigidBody jitterGroundBody = new RigidBody(
  158. new BoxShape(20000.0f, 20000.0f, PlaneHeight));
  159. jitterGroundBody.IsStatic = true;
  160. jitterGroundBody.Material.DynamicFriction = 0.0f;
  161. groundBody = new JitterBody(this, jitterGroundBody);
  162. }
  163. #endregion
  164. #region Events_BodiesBeginCollide
  165. private void Events_BodiesBeginCollide(RigidBody arg1, RigidBody arg2)
  166. {
  167. JitterBody myBody1 = (JitterBody)arg1.Tag;
  168. JitterBody myBody2 = (JitterBody)arg2.Tag;
  169. // Fire event from both bodies.
  170. myBody1.FireCollisionBegin(myBody2);
  171. myBody2.FireCollisionBegin(myBody1);
  172. }
  173. #endregion
  174. #region Events_BodiesEndCollide
  175. private void Events_BodiesEndCollide(RigidBody arg1, RigidBody arg2)
  176. {
  177. JitterBody myBody1 = (JitterBody)arg1.Tag;
  178. JitterBody myBody2 = (JitterBody)arg2.Tag;
  179. // Fire event from both bodies.
  180. myBody1.FireCollisionEnd(myBody2);
  181. myBody2.FireCollisionEnd(myBody1);
  182. }
  183. #endregion
  184. #region CreateBody
  185. /// <summary>
  186. /// Creates a Jitter from base implementation.
  187. /// </summary>
  188. /// <param name="is2DBody">True if the body is 2D, false means that is 3D.</param>
  189. /// <param name="shape">The shape to attach to the new create body.</param>
  190. /// <param name="initialPosition">Initial position of the body.</param>
  191. /// <returns>New PhysicsBody instance or null if not supported.</returns>
  192. protected override PhysicsBody CreateBody(bool is2DBody,
  193. PhysicsShape shape, Vector initialPosition)
  194. {
  195. if (is2DBody)
  196. {
  197. Log.Warning("Jitter does not support 2D bodies.");
  198. return null;
  199. }
  200. PhysicsBody body = new JitterBody(this, shape, initialPosition);
  201. bodies.Add(body);
  202. return body;
  203. }
  204. #endregion
  205. #region CreateJoint
  206. /// <summary>
  207. /// Creates a JitterJoint from base implementation.
  208. /// </summary>
  209. /// <param name="jointType">The type of joint to create.</param>
  210. /// <param name="bodyA">The first required body.</param>
  211. /// <param name="bodyB">The second [optional] body.</param>
  212. /// <param name="args">Array of args to pass to Joint implementation.</param>
  213. /// <returns>The new created PhysicsJoint.</returns>
  214. public override PhysicsJoint CreateJoint(
  215. JointType jointType,
  216. PhysicsBody bodyA,
  217. PhysicsBody bodyB,
  218. object[] args)
  219. {
  220. if (IsJointSupported(jointType) == false)
  221. {
  222. Log.Warning("Current module does not support " +
  223. "the type of joint " + jointType);
  224. return null;
  225. }
  226. PhysicsJoint joint = new JitterJoint(this, jointType, bodyA, bodyB, args);
  227. if (joint != null)
  228. {
  229. joints.Add(joint);
  230. }
  231. return joint;
  232. }
  233. #endregion
  234. #region RemoveBodyImpl
  235. protected override void RemoveBodyImpl(PhysicsBody body)
  236. {
  237. // Remove from jitter world
  238. jitterWorld.RemoveBody(
  239. (body as JitterBody).Body
  240. );
  241. }
  242. #endregion
  243. #region RemoveJointImpl
  244. protected override void RemoveJointImpl(PhysicsJoint joint)
  245. {
  246. JitterJoint jitterJoint = joint as JitterJoint;
  247. // Can be Constraint or joint
  248. if (jitterJoint.Constraint != null)
  249. {
  250. jitterWorld.RemoveConstraint(jitterJoint.Constraint);
  251. }
  252. else
  253. {
  254. jitterJoint.Joint.Deactivate();
  255. }
  256. }
  257. #endregion
  258. #region RayCastImpl
  259. /// <summary>
  260. /// FindRayCast implementation.
  261. /// </summary>
  262. /// <param name="ray">The ray to perform.</param>
  263. /// <param name="checkGround">Whether to check agains ground too.</param>
  264. /// <param name="foundBody">PhysicsBody or null if no intersection happen.</param>
  265. /// <param name="surfaceNormal">
  266. /// The normals of the surfaces in the intersection points.
  267. /// </param>
  268. /// <param name="fraction">
  269. /// Intersection fraction value or zero if no intersection.
  270. /// </param>
  271. /// <param name="userData">Optional user data.</param>
  272. /// <returns>True if any intersection happen, false otherwise.</returns>
  273. protected override bool RayCastImpl(Ray ray, bool checkGround,
  274. out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
  275. out object userData)
  276. {
  277. foundBody = null;
  278. fraction = 0.0f;
  279. surfaceNormal = Vector.Zero;
  280. userData = null;
  281. JVector rayOrigin = JitterDatatypesMapping.Convert(ref ray.Position);
  282. JVector rayDirection = JitterDatatypesMapping.Convert(ref ray.Direction);
  283. RigidBody outBody;
  284. JVector outNormal;
  285. float outFraction;
  286. bool result =
  287. collisionSystem.Raycast(rayOrigin,
  288. rayDirection,
  289. null,
  290. out outBody, out outNormal, out outFraction);
  291. if (result)
  292. {
  293. // Iterate all bodies
  294. foreach (JitterBody body in bodies)
  295. {
  296. if (body.Body == outBody)
  297. {
  298. foundBody = body;
  299. }
  300. }
  301. if (foundBody == null)
  302. {
  303. if (checkGround)
  304. {
  305. // Then this is ground body
  306. foundBody = groundBody;
  307. }
  308. else
  309. {
  310. result = false;
  311. }
  312. }
  313. JitterDatatypesMapping.Convert(ref outNormal, out surfaceNormal);
  314. }
  315. return result;
  316. }
  317. #endregion
  318. #region SetGravity
  319. /// <summary>
  320. /// Sets gravity implementation.
  321. /// </summary>
  322. /// <param name="gravity">The 3D gravity vector.</param>
  323. protected override void SetGravity(Vector gravity)
  324. {
  325. jitterWorld.Gravity = JitterDatatypesMapping.Convert(ref gravity);
  326. }
  327. #endregion
  328. #region SetMultithreading
  329. /// <summary>
  330. /// Sets multithreading on Jitter implementation.
  331. /// </summary>
  332. /// <param name="enable">True to enable, false otherwise.</param>
  333. protected override void SetMultithreading(bool enable)
  334. {
  335. multithread = enable;
  336. }
  337. #endregion
  338. #region GetTotalPhysicsTime
  339. /// <summary>
  340. /// Gets total physics simulation time.
  341. /// </summary>
  342. /// <returns>Total physics simulation time expressed in double.</returns>
  343. protected override double GetTotalPhysicsTime()
  344. {
  345. int entries = (int)World.DebugType.Num;
  346. double total = 0;
  347. for (int i = 0; i < entries; i++)
  348. {
  349. World.DebugType type = (World.DebugType)i;
  350. total += jitterWorld.DebugTimes[i];
  351. }
  352. return total;
  353. }
  354. #endregion
  355. #region UpdateSimulation
  356. /// <summary>
  357. /// Update simulation implementation of Physics.
  358. /// </summary>
  359. protected override void UpdateSimulation(float timeStep)
  360. {
  361. if (IsPaused == false)
  362. {
  363. jitterWorld.Step(timeStep, multithread);
  364. }
  365. }
  366. #endregion
  367. #endregion
  368. /// <summary>
  369. /// Tests
  370. /// </summary>
  371. internal class JitterPhysicsTests
  372. {
  373. #region TestInitialization (Static)
  374. /// <summary>
  375. /// Test whether initialization has been done.
  376. /// </summary>
  377. [Test]
  378. public static void TestInitialization()
  379. {
  380. // check that everything has been OK with Physics initiallization
  381. Assert.NotNull(Bodies);
  382. }
  383. #endregion
  384. #region TestCreate3DBodyWithShape (Static)
  385. /// <summary>
  386. /// Test creation of 3 body with shape.
  387. /// </summary>
  388. [Test]
  389. public static void TestCreate3DBodyWithShape()
  390. {
  391. PhysicsBody body = CreateBox(Vector.Zero,
  392. 2.0f, 3.0f, 1.0f);
  393. Assert.NotNull(body);
  394. Assert.NotNull(body.Shape);
  395. }
  396. #endregion
  397. #region TestFeatureSupport (Static)
  398. /// <summary>
  399. /// Test whether given feature is supoorted.
  400. /// </summary>
  401. [Test]
  402. public static void TestFeatureSupport()
  403. {
  404. // Jitter does not support controllers. (fow now)
  405. bool isSupported = Instance.IsFeatureSupported(
  406. FeatureSupport.Controller);
  407. Assert.False(isSupported);
  408. }
  409. #endregion
  410. #region TestShapeSupport (Static)
  411. /// <summary>
  412. /// Test whether given shape is supoorted.
  413. /// </summary>
  414. [Test]
  415. public static void TestShapeSupport()
  416. {
  417. // Jitter support cone shape.
  418. bool isSupported = Instance.IsShapeSupported(
  419. ShapeType.Cone);
  420. Assert.True(isSupported);
  421. }
  422. #endregion
  423. }
  424. }
  425. }