/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
- using Delta.PhysicsEngines.Enums;
- using Delta.Utilities;
- using Delta.Utilities.Datatypes;
- using Jitter;
- using Jitter.Collision;
- using Jitter.Collision.Shapes;
- using Jitter.Dynamics;
- using Jitter.LinearMath;
- using NUnit.Framework;
-
- namespace Delta.PhysicsEngines.Jitter
- {
- /// <summary>
- /// Jitter physics implementation.
- /// </summary>
- public class JitterPhysics : Physics
- {
- #region Constants
- private const float PlaneHeight = 1.0f;
- #endregion
-
- #region Internal
-
- #region collisionSystem (Internal)
- internal CollisionSystem collisionSystem;
- #endregion
-
- #region jitterWorld (Internal)
- internal World jitterWorld;
- #endregion
-
- #endregion
-
- #region Private
-
- #region multithread (Private)
- private bool multithread;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Initializes a new instance of the <see cref="JitterPhysicsManager"/> class.
- /// </summary>
- public JitterPhysics()
- : base(false, "Jitter")
- {
- collisionSystem = new CollisionSystemSAP();
- jitterWorld = new World(collisionSystem);
- jitterWorld.AllowDeactivation = true;
- jitterWorld.SetIterations(100, 100);
- jitterWorld.SetDampingFactors(0.95f, 0.95f);
- jitterWorld.SetInactivityThreshold(0.005f, 0.005f, 10);
- jitterWorld.Gravity = JitterDatatypesMapping.ConvertSlow(DefaultGravity);
- jitterWorld.Events.BodiesBeginCollide +=
- Events_BodiesBeginCollide;
- jitterWorld.Events.BodiesEndCollide +=
- Events_BodiesEndCollide;
-
- // Create ground body.
- CreateGroundBody();
- }
- #endregion
-
- #region IsShapeSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given shape type.
- /// </summary>
- /// <param name="shapeType">Type of the shape.</param>
- /// <returns>
- /// <c>true</c> if [is shape supported] [the specified shape type]; otherwise, <c>false</c>.
- /// </returns>
- public override bool IsShapeSupported(ShapeType shapeType)
- {
- switch (shapeType)
- {
- case ShapeType.Box:
- case ShapeType.Sphere:
- case ShapeType.Capsule:
- case ShapeType.Triangle:
- case ShapeType.Terrain:
- // Jitter supports this too.
- case ShapeType.Cone:
- case ShapeType.Cylinder:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region IsJointSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given joint type.
- /// </summary>
- /// <param name="jointType">Type of the shape.</param>
- /// <returns>
- /// <c>true</c> if the specified shape type is supported, <c>false</c> otherwise.
- /// </returns>
- public override bool IsJointSupported(JointType jointType)
- {
- switch (jointType)
- {
- case JointType.FixedAngle:
- case JointType.SingleBodyPointOnLine:
- case JointType.PointOnLine:
- case JointType.PointOnPoint:
- case JointType.PointPointDistance:
- case JointType.Hinge:
- case JointType.Prismatic:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region IsFeatureSupported (Public)
- /// <summary>
- /// Gets whether the current physics module supports given feature.
- /// </summary>
- /// <param name="support">The support.</param>
- /// <returns>
- /// <c>true</c> if [is feature supported] [the specified support]; otherwise, <c>false</c>.
- /// </returns>
- public override bool IsFeatureSupported(FeatureSupport support)
- {
- switch (support)
- {
- case FeatureSupport.Joint:
- case FeatureSupport.Multithreading:
- return true;
- }
-
- return false;
- }
- #endregion
-
- #region SetGroundPlane (Public)
- /// <summary>
- /// Implementation of SetGroundPlane
- /// </summary>
- /// <param name="enable">True to enable the ground plane, false otherwise.</param>
- /// <param name="height">The height of the plane.</param>
- public override void SetGroundPlane(bool enable, float height)
- {
- RigidBody jitterRigidBody = ((JitterBody)groundBody).Body;
- jitterRigidBody.Position = new JVector(0, 0, height - (PlaneHeight * 0.5f));
-
- // Check if we need to add it
- if (enable)
- {
- if (jitterWorld.RigidBodies.Contains(jitterRigidBody) == false)
- {
- jitterWorld.AddBody(jitterRigidBody);
- }
- }
- else
- {
- if (jitterWorld.RigidBodies.Contains(jitterRigidBody))
- {
- jitterWorld.RemoveBody(jitterRigidBody);
- }
- }
- }
- #endregion
-
- #region Methods (Private)
-
- #region CreateGroundBody
- /// <summary>
- /// Create the body that will be used as ground.
- /// </summary>
- private void CreateGroundBody()
- {
- RigidBody jitterGroundBody = new RigidBody(
- new BoxShape(20000.0f, 20000.0f, PlaneHeight));
-
- jitterGroundBody.IsStatic = true;
- jitterGroundBody.Material.DynamicFriction = 0.0f;
-
- groundBody = new JitterBody(this, jitterGroundBody);
- }
- #endregion
-
- #region Events_BodiesBeginCollide
- private void Events_BodiesBeginCollide(RigidBody arg1, RigidBody arg2)
- {
- JitterBody myBody1 = (JitterBody)arg1.Tag;
- JitterBody myBody2 = (JitterBody)arg2.Tag;
-
- // Fire event from both bodies.
- myBody1.FireCollisionBegin(myBody2);
- myBody2.FireCollisionBegin(myBody1);
- }
- #endregion
-
- #region Events_BodiesEndCollide
- private void Events_BodiesEndCollide(RigidBody arg1, RigidBody arg2)
- {
- JitterBody myBody1 = (JitterBody)arg1.Tag;
- JitterBody myBody2 = (JitterBody)arg2.Tag;
-
- // Fire event from both bodies.
- myBody1.FireCollisionEnd(myBody2);
- myBody2.FireCollisionEnd(myBody1);
- }
- #endregion
-
- #region CreateBody
- /// <summary>
- /// Creates a Jitter from base implementation.
- /// </summary>
- /// <param name="is2DBody">True if the body is 2D, false means that is 3D.</param>
- /// <param name="shape">The shape to attach to the new create body.</param>
- /// <param name="initialPosition">Initial position of the body.</param>
- /// <returns>New PhysicsBody instance or null if not supported.</returns>
- protected override PhysicsBody CreateBody(bool is2DBody,
- PhysicsShape shape, Vector initialPosition)
- {
- if (is2DBody)
- {
- Log.Warning("Jitter does not support 2D bodies.");
- return null;
- }
-
- PhysicsBody body = new JitterBody(this, shape, initialPosition);
- bodies.Add(body);
- return body;
- }
- #endregion
-
- #region CreateJoint
- /// <summary>
- /// Creates a JitterJoint from base implementation.
- /// </summary>
- /// <param name="jointType">The type of joint to create.</param>
- /// <param name="bodyA">The first required body.</param>
- /// <param name="bodyB">The second [optional] body.</param>
- /// <param name="args">Array of args to pass to Joint implementation.</param>
- /// <returns>The new created PhysicsJoint.</returns>
- public override PhysicsJoint CreateJoint(
- JointType jointType,
- PhysicsBody bodyA,
- PhysicsBody bodyB,
- object[] args)
- {
- if (IsJointSupported(jointType) == false)
- {
- Log.Warning("Current module does not support " +
- "the type of joint " + jointType);
- return null;
- }
-
- PhysicsJoint joint = new JitterJoint(this, jointType, bodyA, bodyB, args);
- if (joint != null)
- {
- joints.Add(joint);
- }
- return joint;
- }
- #endregion
-
- #region RemoveBodyImpl
- protected override void RemoveBodyImpl(PhysicsBody body)
- {
- // Remove from jitter world
- jitterWorld.RemoveBody(
- (body as JitterBody).Body
- );
- }
- #endregion
-
- #region RemoveJointImpl
- protected override void RemoveJointImpl(PhysicsJoint joint)
- {
- JitterJoint jitterJoint = joint as JitterJoint;
-
- // Can be Constraint or joint
- if (jitterJoint.Constraint != null)
- {
- jitterWorld.RemoveConstraint(jitterJoint.Constraint);
- }
- else
- {
- jitterJoint.Joint.Deactivate();
- }
- }
- #endregion
-
- #region RayCastImpl
- /// <summary>
- /// FindRayCast implementation.
- /// </summary>
- /// <param name="ray">The ray to perform.</param>
- /// <param name="checkGround">Whether to check agains ground too.</param>
- /// <param name="foundBody">PhysicsBody or null if no intersection happen.</param>
- /// <param name="surfaceNormal">
- /// The normals of the surfaces in the intersection points.
- /// </param>
- /// <param name="fraction">
- /// Intersection fraction value or zero if no intersection.
- /// </param>
- /// <param name="userData">Optional user data.</param>
- /// <returns>True if any intersection happen, false otherwise.</returns>
- protected override bool RayCastImpl(Ray ray, bool checkGround,
- out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
- out object userData)
- {
- foundBody = null;
- fraction = 0.0f;
- surfaceNormal = Vector.Zero;
- userData = null;
-
- JVector rayOrigin = JitterDatatypesMapping.Convert(ref ray.Position);
- JVector rayDirection = JitterDatatypesMapping.Convert(ref ray.Direction);
- RigidBody outBody;
- JVector outNormal;
- float outFraction;
- bool result =
- collisionSystem.Raycast(rayOrigin,
- rayDirection,
- null,
- out outBody, out outNormal, out outFraction);
-
- if (result)
- {
- // Iterate all bodies
- foreach (JitterBody body in bodies)
- {
- if (body.Body == outBody)
- {
- foundBody = body;
- }
- }
-
- if (foundBody == null)
- {
- if (checkGround)
- {
- // Then this is ground body
- foundBody = groundBody;
- }
- else
- {
- result = false;
- }
- }
-
- JitterDatatypesMapping.Convert(ref outNormal, out surfaceNormal);
- }
- return result;
- }
- #endregion
-
- #region SetGravity
- /// <summary>
- /// Sets gravity implementation.
- /// </summary>
- /// <param name="gravity">The 3D gravity vector.</param>
- protected override void SetGravity(Vector gravity)
- {
- jitterWorld.Gravity = JitterDatatypesMapping.Convert(ref gravity);
- }
- #endregion
-
- #region SetMultithreading
- /// <summary>
- /// Sets multithreading on Jitter implementation.
- /// </summary>
- /// <param name="enable">True to enable, false otherwise.</param>
- protected override void SetMultithreading(bool enable)
- {
- multithread = enable;
- }
- #endregion
-
- #region GetTotalPhysicsTime
- /// <summary>
- /// Gets total physics simulation time.
- /// </summary>
- /// <returns>Total physics simulation time expressed in double.</returns>
- protected override double GetTotalPhysicsTime()
- {
- int entries = (int)World.DebugType.Num;
- double total = 0;
-
- for (int i = 0; i < entries; i++)
- {
- World.DebugType type = (World.DebugType)i;
-
- total += jitterWorld.DebugTimes[i];
- }
-
- return total;
- }
- #endregion
-
- #region UpdateSimulation
- /// <summary>
- /// Update simulation implementation of Physics.
- /// </summary>
- protected override void UpdateSimulation(float timeStep)
- {
- if (IsPaused == false)
- {
- jitterWorld.Step(timeStep, multithread);
- }
- }
- #endregion
-
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class JitterPhysicsTests
- {
- #region TestInitialization (Static)
- /// <summary>
- /// Test whether initialization has been done.
- /// </summary>
- [Test]
- public static void TestInitialization()
- {
- // check that everything has been OK with Physics initiallization
- Assert.NotNull(Bodies);
- }
- #endregion
-
- #region TestCreate3DBodyWithShape (Static)
- /// <summary>
- /// Test creation of 3 body with shape.
- /// </summary>
- [Test]
- public static void TestCreate3DBodyWithShape()
- {
- PhysicsBody body = CreateBox(Vector.Zero,
- 2.0f, 3.0f, 1.0f);
- Assert.NotNull(body);
- Assert.NotNull(body.Shape);
- }
- #endregion
-
- #region TestFeatureSupport (Static)
- /// <summary>
- /// Test whether given feature is supoorted.
- /// </summary>
- [Test]
- public static void TestFeatureSupport()
- {
- // Jitter does not support controllers. (fow now)
- bool isSupported = Instance.IsFeatureSupported(
- FeatureSupport.Controller);
-
- Assert.False(isSupported);
- }
- #endregion
-
- #region TestShapeSupport (Static)
- /// <summary>
- /// Test whether given shape is supoorted.
- /// </summary>
- [Test]
- public static void TestShapeSupport()
- {
- // Jitter support cone shape.
- bool isSupported = Instance.IsShapeSupported(
- ShapeType.Cone);
-
- Assert.True(isSupported);
- }
- #endregion
- }
- }
- }