PageRenderTime 382ms CodeModel.GetById 96ms app.highlight 195ms RepoModel.GetById 72ms app.codeStats 1ms

/PhysicsEngines/Jitter/JitterPhysics.cs

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