/PhysicsEngines/JigLib/JiglibBody.cs
C# | 560 lines | 374 code | 61 blank | 125 comment | 8 complexity | e4fe6526f69687bc95ede557ce7b8c54 MD5 | raw file
Possible License(s): Apache-2.0
- using System.Collections.Generic;
- using Delta.PhysicsEngines.Enums;
- using Delta.Rendering.Models;
- using Delta.Utilities;
- using Delta.Utilities.Datatypes;
- using Delta.Utilities.Helpers;
- using JigLibX.Collision;
- using JigLibX.Geometry;
- using JigLibX.Math;
- using JigLibX.Physics;
- using Plane = JigLibX.Geometry.Plane;
- using XnaMatrix = Microsoft.Xna.Framework.Matrix;
- using XnaVector3 = Microsoft.Xna.Framework.Vector3;
-
- namespace Delta.PhysicsEngines.JigLib
- {
- internal class JigLibBody : PhysicsBody
- {
- #region Body (Public)
- /// <summary>
- /// The Body handles all the physics of motion: position, velocity,
- /// acceleration forces, torques, etc... A body can only be added to one
- /// physics system at a time!
- /// </summary>
- public Body Body
- {
- get
- {
- return jigLibBody;
- }
- }
- #endregion
-
- #region Skin (Public)
- /// <summary>
- /// The JigLib colllision skin.
- /// </summary>
- public CollisionSkin Skin
- {
- get
- {
- return jigLibSkin;
- }
- }
- #endregion
-
- #region Position (Public)
- /// <summary>
- /// Position given in world space.
- /// </summary>
- public override Vector Position
- {
- get
- {
- JigLibDatatypesMapping.Convert(jigLibBody.Position, out position);
- return position;
- }
- set
- {
- jigLibBody.MoveTo(JigLibDatatypesMapping.Convert(ref value),
- Body.Orientation);
- }
- }
- #endregion
-
- #region Position2D (Public)
- /// <summary>
- /// Position 2D given in world space (same as Position, just easier to
- /// access for 2D code not having to convert Position to a Point anymore).
- /// </summary>
- public override Point Position2D
- {
- get
- {
- position2D.X = jigLibBody.Position.X;
- position2D.Y = jigLibBody.Position.Y;
- return position2D;
- }
- set
- {
- // This is 3D physics engine, so do nothing by default.
- }
- }
- #endregion
-
- #region RotationMatrix (Public)
- /// <summary>
- /// Rotation matrix
- /// </summary>
- public override Matrix RotationMatrix
- {
- get
- {
- JigLibDatatypesMapping.Convert(Body.Orientation, ref rotationMatrix);
- return rotationMatrix;
- }
- set
- {
- if (Body != null)
- {
- XnaMatrix xnaMatrix;
- JigLibDatatypesMapping.Convert(ref value, out xnaMatrix);
- Body.MoveTo(Body.Position, xnaMatrix);
- }
- }
- }
- #endregion
-
- #region LinearVelocity (Public)
- /// <summary>
- /// The velocity of the body.
- /// </summary>
- public override Vector LinearVelocity
- {
- get
- {
- JigLibDatatypesMapping.Convert(jigLibBody.Velocity,
- out linearVelocity);
- return linearVelocity;
- }
- set
- {
- jigLibBody.Velocity = JigLibDatatypesMapping.Convert(ref value);
- }
- }
- #endregion
-
- #region AngularVelocity (Public)
- /// <summary>
- /// The angular velocity of the body.
- /// <remarks>
- /// For 2D physics simulation only X component is used.
- /// </remarks>
- /// </summary>
- public override Vector AngularVelocity
- {
- get
- {
- JigLibDatatypesMapping.Convert(jigLibBody.AngularVelocity,
- out angularVelocity);
- return angularVelocity;
- }
- set
- {
- jigLibBody.AngularVelocity = JigLibDatatypesMapping.Convert(ref value);
- }
- }
- #endregion
-
- #region AngularVelocity2D (Public)
- /// <summary>
- /// Angular velocity 2D as a float, for 2D only the .x component is used!
- /// </summary>
- public override float AngularVelocity2D
- {
- get
- {
- return jigLibBody.AngularVelocity.X;
- }
- set
- {
- xnaAngularVelocity2D.X = value;
- jigLibBody.AngularVelocity = xnaAngularVelocity2D;
- }
- }
- #endregion
-
- #region BoundingBox (Public)
- /// <summary>
- /// Gets the BoundingBox of the body.
- /// </summary>
- /// <remarks>
- /// Used during 3D simulation.
- /// </remarks>
- public override BoundingBox BoundingBox
- {
- get
- {
- JigLibDatatypesMapping.Convert(jigLibSkin.WorldBoundingBox.Min,
- out boundingBox.Min);
- JigLibDatatypesMapping.Convert(jigLibSkin.WorldBoundingBox.Max,
- out boundingBox.Max);
- return boundingBox;
- }
- }
- #endregion
-
- #region Mass (Public)
- /// <summary>
- /// It defines how heavy is the object in kg
- /// Note: If the mass is zero or below the object will be switch to
- /// "static collision behavior".
- /// </summary>
- public override float Mass
- {
- get
- {
- return base.Mass;
- }
- set
- {
- }
- }
- #endregion
-
- #region Private
-
- #region jigLibBody (Private)
- private readonly Body jigLibBody;
- #endregion
-
- #region jigLibSkin (Private)
- private readonly CollisionSkin jigLibSkin;
- #endregion
-
- #region jiglibPrimitive (Private)
- /// <summary>
- /// The internal representation of the sphere in Delta.PhysicsEngines.JigLib.
- /// </summary>
- private Primitive jiglibPrimitive;
- #endregion
-
- #region physicsManager (Private)
- private readonly JigLibPhysics physicsManager;
- #endregion
-
- #region position (Private)
- private Vector position;
- #endregion
-
- #region position2D (Private)
- private Point position2D;
- #endregion
-
- #region rotationMatrix (Private)
- private Matrix rotationMatrix;
- #endregion
-
- #region linearVelocity (Private)
- private Vector linearVelocity;
- #endregion
-
- #region angularVelocity (Private)
- private Vector angularVelocity;
- #endregion
-
- #region xnaAngularVelocity2D (Private)
- private XnaVector3 xnaAngularVelocity2D;
- #endregion
-
- #region boundingBox (Private)
- private BoundingBox boundingBox;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Constructor
- /// </summary>
- /// <param name="physicsManager">The JigLib physics manager.</param>
- /// <param name="shape">The shape.</param>
- /// <param name="initialPosition">Body initial position.</param>
- internal JigLibBody(JigLibPhysics physicsManager,
- PhysicsShape shape, Vector initialPosition)
- : base(false, shape, initialPosition)
- {
- this.physicsManager = physicsManager;
-
- // create the body and the geometry structs
- jigLibBody = new Body();
- jigLibSkin = new CollisionSkin(jigLibBody);
- jigLibBody.CollisionSkin = jigLibSkin;
-
- CreateShape();
-
- jigLibSkin.callbackFn +=
- HandleCollisionDetection;
- }
-
- /// <summary>
- /// Internal constructor for creating ground body.
- /// </summary>
- /// <param name="physicsManager">The JigLib physics manager.</param>
- internal JigLibBody(JigLibPhysics physicsManager)
- : base(false, null, Vector.Zero)
- {
- this.physicsManager = physicsManager;
-
- // create the body and the geometry structs
- jigLibBody = new Body();
- jigLibSkin = new CollisionSkin(jigLibBody);
- jigLibBody.CollisionSkin = jigLibSkin;
-
- jiglibPrimitive = new Plane(
- XnaVector3.UnitZ, 0.0f);
-
- // Init primitive but don't add it to simulation.
- InitPrimitive(false);
-
- jigLibSkin.callbackFn += HandleCollisionDetection;
- }
- #endregion
-
- #region ApplyForce (Public)
- /// <summary>
- /// Applies a force at the center of mass.
- /// </summary>
- /// <param name="force">The force.</param>
- public override void ApplyForce(Vector force)
- {
- jigLibBody.Force = JigLibDatatypesMapping.Convert(ref force);
- }
- #endregion
-
- #region ApplyTorque (Public)
- /// <summary>
- /// Apply a torque. This affects the angular velocity without affecting the
- /// linear velocity of the center of mass.
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// </summary>
- /// <param name="torque">Vector containing torque data for both 2D and 3D
- /// shapes.</param>
- public override void ApplyTorque(Vector torque)
- {
- jigLibBody.Torque = JigLibDatatypesMapping.Convert(ref torque);
- }
- #endregion
-
- #region ApplyLinearImpulse (Public)
- /// <summary>
- /// Apply an impulse at a point. This immediately modifies the velocity.
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// </summary>
- /// <param name="impulse">Impulse vector data.</param>
- public override void ApplyLinearImpulse(Vector impulse)
- {
- Body.ApplyWorldImpulse(JigLibDatatypesMapping.Convert(ref impulse));
- }
-
- /// <summary>
- /// Apply an impulse at a point. This immediately modifies the velocity.
- /// It also modifies the angular velocity if the point of application
- /// is not at the center of mass.
- /// <remarks>
- /// This wakes up the body.
- /// </remarks>
- /// </summary>
- /// <param name="impulse">Impulse vector data.</param>
- /// <param name="position">Position in 3D where to apply impulse.</param>
- public override void ApplyLinearImpulse(Vector impulse, Vector position)
- {
- jigLibBody.ApplyWorldImpulse(
- JigLibDatatypesMapping.Convert(ref impulse),
- JigLibDatatypesMapping.Convert(ref position));
- }
- #endregion
-
- #region ApplyAngularImpulse (Public)
- /// <summary>
- /// Apply an angular impulse.
- /// </summary>
- /// <param name="impulse">Vector containing torque data for both 2D and 3D shapes.</param>
- public override void ApplyAngularImpulse(Vector impulse)
- {
- Body.ApplyWorldAngImpulse(JigLibDatatypesMapping.Convert(ref impulse));
- }
- #endregion
-
- #region Methods (Private)
-
- #region CreateShape
- /// <summary>
- /// Creates new physics shape from out cached properties.
- /// </summary>
- private void CreateShape()
- {
- Vector position = InitialPosition;
- Dictionary<PhysicsShape.PropertyType, object> properties =
- base.Shape.Properties;
-
- switch (Shape.ShapeType)
- {
- case ShapeType.Sphere:
- jiglibPrimitive = new Sphere(
- JigLibDatatypesMapping.Convert(ref position),
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
- properties, PhysicsShape.PropertyType.Radius));
- break;
- case ShapeType.Box:
- Vector size = ArrayHelper.SafeGet<PhysicsShape.PropertyType, Vector>(
- properties, PhysicsShape.PropertyType.Size);
-
- jiglibPrimitive = new Box(
- JigLibDatatypesMapping.Convert(ref position),
- XnaMatrix.Identity,
- new XnaVector3(size.Y, size.Z, size.X)
- );
- break;
-
- case ShapeType.Capsule:
- jiglibPrimitive = new Capsule(
- JigLibDatatypesMapping.Convert(ref position),
- XnaMatrix.Identity,
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
- properties, PhysicsShape.PropertyType.Radius),
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
- properties, PhysicsShape.PropertyType.Depth));
- break;
- case ShapeType.Triangle:
- jiglibPrimitive = Helpers.CreateFrom(
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, Mesh>(
- properties, PhysicsShape.PropertyType.Mesh),
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, Matrix>(
- properties, PhysicsShape.PropertyType.LocalSpaceMatrix),
- ArrayHelper.SafeGet<PhysicsShape.PropertyType, bool>(
- properties, PhysicsShape.PropertyType.InvertTriangles));
- break;
- }
-
- // Finally initialize primitive
- InitPrimitive(true);
- }
- #endregion
-
- #region InitPrimitive
- /// <summary>
- /// Init JigLib primitive.
- /// </summary>
- /// <param name="addToWorld">True to add to world.</param>
- internal void InitPrimitive(bool addToWorld)
- {
- if (jiglibPrimitive == null)
- {
- Log.Warning("Can't create JigLib body with no primitive.");
- return;
- }
-
- jigLibSkin.AddPrimitive(
- jiglibPrimitive,
- new MaterialProperties(
- 0.8f, // elasticity
- 0.8f, // static roughness
- 0.7f // dynamic roughness
- ));
-
- XnaVector3 com = GestureMass(base.mass);
-
- // Apply initial position
- Vector initPosition = InitialPosition;
- jigLibBody.MoveTo(JigLibDatatypesMapping.Convert(ref initPosition),
- XnaMatrix.Identity);
-
- // in case the com is not the same as the mesh reference system
- jigLibSkin.ApplyLocalTransform(new Transform(-com,
- XnaMatrix.Identity));
-
- if (addToWorld)
- {
- // add the body to the physics world
- Body.EnableBody();
- }
- }
- #endregion
-
- #region GestureMass
- /// <summary>
- /// Init main settings for Mass and BodyInertia.
- /// </summary>
- /// <param name="value">Mass value used for calculating body inhertia.</param>
- /// <returns>Vector3 containing body inhertia newly calculated.</returns>
- private XnaVector3 GestureMass(float value)
- {
- PrimitiveProperties primitiveProperties = new PrimitiveProperties(
- PrimitiveProperties.MassDistributionEnum.Solid,
- PrimitiveProperties.MassTypeEnum.Mass,
- value);
-
- float junk;
- XnaVector3 com;
- XnaMatrix it, itCom;
-
- jigLibSkin.GetMassProperties(
- primitiveProperties, out junk, out com, out it, out itCom);
-
- jigLibBody.BodyInertia = itCom;
- jigLibBody.Mass = junk;
-
- base.mass = junk;
-
- return com;
- }
- #endregion
-
- #region HandleCollisionDetection
- /// <summary>
- /// Fired when collision is launch.
- /// </summary>
- /// <remarks>
- /// http://jiglibx.wikidot.com/catch-collisionevents
- /// </remarks>
- /// <param name="owner">JigLib collision owner skin.</param>
- /// <param name="collidee">JigLib collidee owner skin.</param>
- /// <returns>
- /// True whether to response on collision detection.
- /// </returns>
- private bool HandleCollisionDetection(CollisionSkin owner,
- CollisionSkin collidee)
- {
- // all other coll
- PhysicsBody body;
- if (physicsManager.skinBodiesMap.TryGetValue(collidee, out body))
- {
- base.OnCollisionBegin(body);
- }
-
- return true;
- }
- #endregion
-
- #region SetIsStatic
- /// <summary>
- /// Static physics body implementation.
- /// </summary>
- /// <param name="value">True to set static, false otherwise.</param>
- protected override void SetIsStatic(bool value)
- {
- jigLibBody.Immovable = value;
- }
- #endregion
-
- #region SetIsActive
- protected override void SetIsActive(bool value)
- {
- if (value)
- {
- jigLibBody.SetActive();
- }
- }
- #endregion
-
- #region SetFriction
- protected override void SetFriction(float value)
- {
- // Multiple shapes
- foreach (CollisionInfo iter in jigLibSkin.Collisions)
- {
- iter.MatPairProperties.StaticFriction = value;
- iter.MatPairProperties.DynamicFriction = value;
- }
- }
- #endregion
-
- #endregion
- }
- }