PageRenderTime 115ms CodeModel.GetById 60ms app.highlight 18ms RepoModel.GetById 32ms app.codeStats 0ms

/PhysicsEngines/JigLib/JiglibBody.cs

#
C# | 560 lines | 374 code | 61 blank | 125 comment | 8 complexity | e4fe6526f69687bc95ede557ce7b8c54 MD5 | raw file
  1using System.Collections.Generic;
  2using Delta.PhysicsEngines.Enums;
  3using Delta.Rendering.Models;
  4using Delta.Utilities;
  5using Delta.Utilities.Datatypes;
  6using Delta.Utilities.Helpers;
  7using JigLibX.Collision;
  8using JigLibX.Geometry;
  9using JigLibX.Math;
 10using JigLibX.Physics;
 11using Plane = JigLibX.Geometry.Plane;
 12using XnaMatrix = Microsoft.Xna.Framework.Matrix;
 13using XnaVector3 = Microsoft.Xna.Framework.Vector3;
 14
 15namespace Delta.PhysicsEngines.JigLib
 16{
 17	internal class JigLibBody : PhysicsBody
 18	{
 19		#region Body (Public)
 20		/// <summary>
 21		/// The Body handles all the physics of motion: position, velocity,
 22		/// acceleration forces, torques, etc... A body can only be added to one
 23		/// physics system at a time!
 24		/// </summary>
 25		public Body Body
 26		{
 27			get
 28			{
 29				return jigLibBody;
 30			}
 31		}
 32		#endregion
 33
 34		#region Skin (Public)
 35		/// <summary>
 36		/// The JigLib colllision skin.
 37		/// </summary>
 38		public CollisionSkin Skin
 39		{
 40			get
 41			{
 42				return jigLibSkin;
 43			}
 44		}
 45		#endregion
 46
 47		#region Position (Public)
 48		/// <summary>
 49		/// Position given in world space.
 50		/// </summary>
 51		public override Vector Position
 52		{
 53			get
 54			{
 55				JigLibDatatypesMapping.Convert(jigLibBody.Position, out position);
 56				return position;
 57			}
 58			set
 59			{
 60				jigLibBody.MoveTo(JigLibDatatypesMapping.Convert(ref value),
 61					Body.Orientation);
 62			}
 63		}
 64		#endregion
 65
 66		#region Position2D (Public)
 67		/// <summary>
 68		/// Position 2D given in world space (same as Position, just easier to
 69		/// access for 2D code not having to convert Position to a Point anymore).
 70		/// </summary>
 71		public override Point Position2D
 72		{
 73			get
 74			{
 75				position2D.X = jigLibBody.Position.X;
 76				position2D.Y = jigLibBody.Position.Y;
 77				return position2D;
 78			}
 79			set
 80			{
 81				// This is 3D physics engine, so do nothing by default.
 82			}
 83		}
 84		#endregion
 85
 86		#region RotationMatrix (Public)
 87		/// <summary>
 88		/// Rotation matrix
 89		/// </summary>
 90		public override Matrix RotationMatrix
 91		{
 92			get
 93			{
 94				JigLibDatatypesMapping.Convert(Body.Orientation, ref rotationMatrix);
 95				return rotationMatrix;
 96			}
 97			set
 98			{
 99				if (Body != null)
100				{
101					XnaMatrix xnaMatrix;
102					JigLibDatatypesMapping.Convert(ref value, out xnaMatrix);
103					Body.MoveTo(Body.Position, xnaMatrix);
104				}
105			}
106		}
107		#endregion
108
109		#region LinearVelocity (Public)
110		/// <summary>
111		/// The velocity of the body.
112		/// </summary>
113		public override Vector LinearVelocity
114		{
115			get
116			{
117				JigLibDatatypesMapping.Convert(jigLibBody.Velocity,
118					out linearVelocity);
119				return linearVelocity;
120			}
121			set
122			{
123				jigLibBody.Velocity = JigLibDatatypesMapping.Convert(ref value);
124			}
125		}
126		#endregion
127
128		#region AngularVelocity (Public)
129		/// <summary>
130		/// The angular velocity of the body.
131		/// <remarks>
132		/// For 2D physics simulation only X component is used.
133		/// </remarks>
134		/// </summary>
135		public override Vector AngularVelocity
136		{
137			get
138			{
139				JigLibDatatypesMapping.Convert(jigLibBody.AngularVelocity,
140					out angularVelocity);
141				return angularVelocity;
142			}
143			set
144			{
145				jigLibBody.AngularVelocity = JigLibDatatypesMapping.Convert(ref value);
146			}
147		}
148		#endregion
149
150		#region AngularVelocity2D (Public)
151		/// <summary>
152		/// Angular velocity 2D as a float, for 2D only the .x component is used!
153		/// </summary>
154		public override float AngularVelocity2D
155		{
156			get
157			{
158				return jigLibBody.AngularVelocity.X;
159			}
160			set
161			{
162				xnaAngularVelocity2D.X = value;
163				jigLibBody.AngularVelocity = xnaAngularVelocity2D;
164			}
165		}
166		#endregion
167
168		#region BoundingBox (Public)
169		/// <summary>
170		/// Gets the BoundingBox of the body.
171		/// </summary>
172		/// <remarks>
173		/// Used during 3D simulation.
174		/// </remarks>
175		public override BoundingBox BoundingBox
176		{
177			get
178			{
179				JigLibDatatypesMapping.Convert(jigLibSkin.WorldBoundingBox.Min,
180					out boundingBox.Min);
181				JigLibDatatypesMapping.Convert(jigLibSkin.WorldBoundingBox.Max,
182					out boundingBox.Max);
183				return boundingBox;
184			}
185		}
186		#endregion
187
188		#region Mass (Public)
189		/// <summary>
190		/// It defines how heavy is the object in kg
191		/// Note: If the mass is zero or below the object will be switch to
192		/// "static collision behavior".
193		/// </summary>
194		public override float Mass
195		{
196			get
197			{
198				return base.Mass;
199			}
200			set
201			{
202			}
203		}
204		#endregion
205
206		#region Private
207
208		#region jigLibBody (Private)
209		private readonly Body jigLibBody;
210		#endregion
211
212		#region jigLibSkin (Private)
213		private readonly CollisionSkin jigLibSkin;
214		#endregion
215
216		#region jiglibPrimitive (Private)
217		/// <summary>
218		/// The internal representation of the sphere in Delta.PhysicsEngines.JigLib.
219		/// </summary>
220		private Primitive jiglibPrimitive;
221		#endregion
222
223		#region physicsManager (Private)
224		private readonly JigLibPhysics physicsManager;
225		#endregion
226
227		#region position (Private)
228		private Vector position;
229		#endregion
230
231		#region position2D (Private)
232		private Point position2D;
233		#endregion
234
235		#region rotationMatrix (Private)
236		private Matrix rotationMatrix;
237		#endregion
238
239		#region linearVelocity (Private)
240		private Vector linearVelocity;
241		#endregion
242
243		#region angularVelocity (Private)
244		private Vector angularVelocity;
245		#endregion
246
247		#region xnaAngularVelocity2D (Private)
248		private XnaVector3 xnaAngularVelocity2D;
249		#endregion
250
251		#region boundingBox (Private)
252		private BoundingBox boundingBox;
253		#endregion
254
255		#endregion
256
257		#region Constructors
258		/// <summary>
259		/// Constructor
260		/// </summary>
261		/// <param name="physicsManager">The JigLib physics manager.</param>
262		/// <param name="shape">The shape.</param>
263		/// <param name="initialPosition">Body initial position.</param>
264		internal JigLibBody(JigLibPhysics physicsManager,
265			PhysicsShape shape, Vector initialPosition)
266			: base(false, shape, initialPosition)
267		{
268			this.physicsManager = physicsManager;
269
270			// create the body and the geometry structs
271			jigLibBody = new Body();
272			jigLibSkin = new CollisionSkin(jigLibBody);
273			jigLibBody.CollisionSkin = jigLibSkin;
274
275			CreateShape();
276
277			jigLibSkin.callbackFn +=
278				HandleCollisionDetection;
279		}
280
281		/// <summary>
282		/// Internal constructor for creating ground body.
283		/// </summary>
284		/// <param name="physicsManager">The JigLib physics manager.</param>
285		internal JigLibBody(JigLibPhysics physicsManager)
286			: base(false, null, Vector.Zero)
287		{
288			this.physicsManager = physicsManager;
289
290			// create the body and the geometry structs
291			jigLibBody = new Body();
292			jigLibSkin = new CollisionSkin(jigLibBody);
293			jigLibBody.CollisionSkin = jigLibSkin;
294
295			jiglibPrimitive = new Plane(
296				XnaVector3.UnitZ, 0.0f);
297
298			// Init primitive but don't add it to simulation.
299			InitPrimitive(false);
300
301			jigLibSkin.callbackFn += HandleCollisionDetection;
302		}
303		#endregion
304
305		#region ApplyForce (Public)
306		/// <summary>
307		/// Applies a force at the center of mass.
308		/// </summary>
309		/// <param name="force">The force.</param>
310		public override void ApplyForce(Vector force)
311		{
312			jigLibBody.Force = JigLibDatatypesMapping.Convert(ref force);
313		}
314		#endregion
315
316		#region ApplyTorque (Public)
317		/// <summary>
318		/// Apply a torque. This affects the angular velocity without affecting the
319		/// linear velocity of the center of mass.
320		/// <remarks>
321		/// This wakes up the body.
322		/// </remarks>
323		/// </summary>
324		/// <param name="torque">Vector containing torque data for both 2D and 3D
325		/// shapes.</param>
326		public override void ApplyTorque(Vector torque)
327		{
328			jigLibBody.Torque = JigLibDatatypesMapping.Convert(ref torque);
329		}
330		#endregion
331
332		#region ApplyLinearImpulse (Public)
333		/// <summary>
334		/// Apply an impulse at a point. This immediately modifies the velocity.
335		/// <remarks>
336		/// This wakes up the body.
337		/// </remarks>
338		/// </summary>
339		/// <param name="impulse">Impulse vector data.</param>
340		public override void ApplyLinearImpulse(Vector impulse)
341		{
342			Body.ApplyWorldImpulse(JigLibDatatypesMapping.Convert(ref impulse));
343		}
344
345		/// <summary>
346		/// Apply an impulse at a point. This immediately modifies the velocity.
347		/// It also modifies the angular velocity if the point of application
348		/// is not at the center of mass.
349		/// <remarks>
350		/// This wakes up the body.
351		/// </remarks>
352		/// </summary>
353		/// <param name="impulse">Impulse vector data.</param>
354		/// <param name="position">Position in 3D where to apply impulse.</param>
355		public override void ApplyLinearImpulse(Vector impulse, Vector position)
356		{
357			jigLibBody.ApplyWorldImpulse(
358				JigLibDatatypesMapping.Convert(ref impulse),
359				JigLibDatatypesMapping.Convert(ref position));
360		}
361		#endregion
362
363		#region ApplyAngularImpulse (Public)
364		/// <summary>
365		/// Apply an angular impulse.
366		/// </summary>
367		/// <param name="impulse">Vector containing torque data for both 2D and 3D shapes.</param>
368		public override void ApplyAngularImpulse(Vector impulse)
369		{
370			Body.ApplyWorldAngImpulse(JigLibDatatypesMapping.Convert(ref impulse));
371		}
372		#endregion
373
374		#region Methods (Private)
375
376		#region CreateShape
377		/// <summary>
378		/// Creates new physics shape from out cached properties.
379		/// </summary>
380		private void CreateShape()
381		{
382			Vector position = InitialPosition;
383			Dictionary<PhysicsShape.PropertyType, object> properties =
384				base.Shape.Properties;
385
386			switch (Shape.ShapeType)
387			{
388				case ShapeType.Sphere:
389					jiglibPrimitive = new Sphere(
390						JigLibDatatypesMapping.Convert(ref position),
391						ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
392							properties, PhysicsShape.PropertyType.Radius));
393					break;
394				case ShapeType.Box:
395					Vector size = ArrayHelper.SafeGet<PhysicsShape.PropertyType, Vector>(
396						properties, PhysicsShape.PropertyType.Size);
397
398					jiglibPrimitive = new Box(
399						JigLibDatatypesMapping.Convert(ref position),
400						XnaMatrix.Identity,
401						new XnaVector3(size.Y, size.Z, size.X)
402						);
403					break;
404
405				case ShapeType.Capsule:
406					jiglibPrimitive = new Capsule(
407						JigLibDatatypesMapping.Convert(ref position),
408						XnaMatrix.Identity,
409						ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
410							properties, PhysicsShape.PropertyType.Radius),
411						ArrayHelper.SafeGet<PhysicsShape.PropertyType, float>(
412							properties, PhysicsShape.PropertyType.Depth));
413					break;
414				case ShapeType.Triangle:
415					jiglibPrimitive = Helpers.CreateFrom(
416						ArrayHelper.SafeGet<PhysicsShape.PropertyType, Mesh>(
417							properties, PhysicsShape.PropertyType.Mesh),
418						ArrayHelper.SafeGet<PhysicsShape.PropertyType, Matrix>(
419							properties, PhysicsShape.PropertyType.LocalSpaceMatrix),
420						ArrayHelper.SafeGet<PhysicsShape.PropertyType, bool>(
421							properties, PhysicsShape.PropertyType.InvertTriangles));
422					break;
423			}
424
425			// Finally initialize primitive
426			InitPrimitive(true);
427		}
428		#endregion
429
430		#region InitPrimitive
431		/// <summary>
432		/// Init JigLib primitive.
433		/// </summary>
434		/// <param name="addToWorld">True to add to world.</param>
435		internal void InitPrimitive(bool addToWorld)
436		{
437			if (jiglibPrimitive == null)
438			{
439				Log.Warning("Can't create JigLib body with no primitive.");
440				return;
441			}
442
443			jigLibSkin.AddPrimitive(
444				jiglibPrimitive,
445				new MaterialProperties(
446					0.8f, // elasticity
447					0.8f, // static roughness
448					0.7f // dynamic roughness
449					));
450
451			XnaVector3 com = GestureMass(base.mass);
452
453			// Apply initial position
454			Vector initPosition = InitialPosition;
455			jigLibBody.MoveTo(JigLibDatatypesMapping.Convert(ref initPosition),
456				XnaMatrix.Identity);
457
458			// in case the com is not the same as the mesh reference system
459			jigLibSkin.ApplyLocalTransform(new Transform(-com,
460				XnaMatrix.Identity));
461
462			if (addToWorld)
463			{
464				// add the body to the physics world
465				Body.EnableBody();
466			}
467		}
468		#endregion
469
470		#region GestureMass
471		/// <summary>
472		/// Init main settings for Mass and BodyInertia.
473		/// </summary>
474		/// <param name="value">Mass value used for calculating body inhertia.</param>
475		/// <returns>Vector3 containing body inhertia newly calculated.</returns>
476		private XnaVector3 GestureMass(float value)
477		{
478			PrimitiveProperties primitiveProperties = new PrimitiveProperties(
479				PrimitiveProperties.MassDistributionEnum.Solid,
480				PrimitiveProperties.MassTypeEnum.Mass,
481				value);
482
483			float junk;
484			XnaVector3 com;
485			XnaMatrix it, itCom;
486
487			jigLibSkin.GetMassProperties(
488				primitiveProperties, out junk, out com, out it, out itCom);
489
490			jigLibBody.BodyInertia = itCom;
491			jigLibBody.Mass = junk;
492
493			base.mass = junk;
494
495			return com;
496		}
497		#endregion
498
499		#region HandleCollisionDetection
500		/// <summary>
501		/// Fired when collision is launch.
502		/// </summary>
503		/// <remarks>
504		/// http://jiglibx.wikidot.com/catch-collisionevents
505		/// </remarks>
506		/// <param name="owner">JigLib collision owner skin.</param>
507		/// <param name="collidee">JigLib collidee owner skin.</param>
508		/// <returns>
509		/// True whether to response on collision detection.
510		/// </returns>
511		private bool HandleCollisionDetection(CollisionSkin owner,
512			CollisionSkin collidee)
513		{
514			// all other coll
515			PhysicsBody body;
516			if (physicsManager.skinBodiesMap.TryGetValue(collidee, out body))
517			{
518				base.OnCollisionBegin(body);
519			}
520
521			return true;
522		}
523		#endregion
524
525		#region SetIsStatic
526		/// <summary>
527		/// Static physics body implementation.
528		/// </summary>
529		/// <param name="value">True to set static, false otherwise.</param>
530		protected override void SetIsStatic(bool value)
531		{
532			jigLibBody.Immovable = value;
533		}
534		#endregion
535
536		#region SetIsActive
537		protected override void SetIsActive(bool value)
538		{
539			if (value)
540			{
541				jigLibBody.SetActive();
542			}
543		}
544		#endregion
545
546		#region SetFriction
547		protected override void SetFriction(float value)
548		{
549			// Multiple shapes
550			foreach (CollisionInfo iter in jigLibSkin.Collisions)
551			{
552				iter.MatPairProperties.StaticFriction = value;
553				iter.MatPairProperties.DynamicFriction = value;
554			}
555		}
556		#endregion
557
558		#endregion
559	}
560}