PageRenderTime 125ms CodeModel.GetById 50ms app.highlight 14ms RepoModel.GetById 56ms app.codeStats 0ms

/PhysicsEngines/Bullet/BulletPhysics.cs

#
C# | 388 lines | 245 code | 48 blank | 95 comment | 19 complexity | 04db6314d56431ee323b71ec6e728e4a MD5 | raw file
  1using BulletXNA;
  2using BulletXNA.BulletCollision;
  3using BulletXNA.BulletDynamics;
  4using Delta.PhysicsEngines.Enums;
  5using Delta.Utilities;
  6using Delta.Utilities.Datatypes;
  7using BulletVector3 = Microsoft.Xna.Framework.Vector3;
  8using BulletMatrix = Microsoft.Xna.Framework.Matrix;
  9
 10namespace Delta.PhysicsEngines.Bullet
 11{
 12	/// <summary>
 13	/// Bullet physics engine implementation into DeltaEngine.
 14	/// <remarks>
 15	/// Reference <see cref="http://code.google.com/p/bullet-xna/"/> for more info.
 16	/// </remarks>
 17	/// </summary>
 18	public class BulletPhysics : Physics
 19	{
 20		#region Constants
 21		private const int MaxProxies = 100000;
 22
 23		private const float PlaneHeight = 1.0f;
 24		#endregion
 25
 26		#region Internal
 27
 28		#region bulletWorld (Internal)
 29		internal DynamicsWorld bulletWorld;
 30		#endregion
 31
 32		#region bulletCollisionConf (Internal)
 33		internal ICollisionConfiguration bulletCollisionConf;
 34		#endregion
 35
 36		#region bulletDispatcher (Internal)
 37		internal CollisionDispatcher bulletDispatcher;
 38		#endregion
 39
 40		#region bulletBroadphase (Internal)
 41		internal IBroadphaseInterface bulletBroadphase;
 42		#endregion
 43
 44		#region bulletSolver (Internal)
 45		internal IConstraintSolver bulletSolver;
 46		#endregion
 47
 48		#endregion
 49
 50		#region Constructors
 51		/// <summary>
 52		/// Initializes a new instance of the <see cref="BulletPhysics"/> class.
 53		/// </summary>
 54		public BulletPhysics()
 55			: base(false, "Bullet")
 56		{
 57			// Collision configuration contains default setup for memory.
 58			bulletCollisionConf = new DefaultCollisionConfiguration();
 59			bulletDispatcher = new CollisionDispatcher(bulletCollisionConf);
 60
 61			// Now create broad phase.
 62			IOverlappingPairCache pairCache = null;
 63			bulletBroadphase = new SimpleBroadphase(MaxProxies, pairCache);
 64
 65			// Now create solver
 66			bulletSolver = new SequentialImpulseConstraintSolver();
 67
 68			// Add possibility for different world in future.
 69			bulletWorld = new DiscreteDynamicsWorld(bulletDispatcher,
 70				bulletBroadphase,
 71				bulletSolver,
 72				bulletCollisionConf);
 73
 74			var bulletVector = BulletDatatypesMapping.Convert(DefaultGravity);
 75			bulletWorld.SetGravity(ref bulletVector);
 76
 77			CreateGroundBody();
 78		}
 79		#endregion
 80
 81		#region IsShapeSupported (Public)
 82		/// <summary>
 83		/// Implementation for getting which shapes are supported by Bullet.
 84		/// </summary>
 85		/// <param name="shapeType">The type of shape to check if supported.</param>
 86		/// <returns>True if supported, false otherwise.</returns>
 87		public override bool IsShapeSupported(ShapeType shapeType)
 88		{
 89			switch (shapeType)
 90			{
 91				case ShapeType.Box:
 92				case ShapeType.Sphere:
 93				case ShapeType.Capsule:
 94				case ShapeType.Triangle:
 95					//case Enums.ShapeType.Terrain:
 96					// Bullet supports this too.
 97				case ShapeType.Cone:
 98				case ShapeType.Cylinder:
 99					return true;
100			}
101
102			return false;
103		}
104		#endregion
105
106		#region IsJointSupported (Public)
107		/// <summary>
108		/// Implementation for getting which shapes are supported by Bullet.
109		/// </summary>
110		/// <param name="jointType">The type of joint to check if supported.</param>
111		/// <returns>True if supported, false otherwise.</returns>
112		public override bool IsJointSupported(JointType jointType)
113		{
114			switch (jointType)
115			{
116					//case Enums.JointType.FixedAngle:
117					//case Enums.JointType.SingleBodyPointOnLine:
118					//case Enums.JointType.PointOnLine:
119				case JointType.PointOnPoint:
120					//case Enums.JointType.PointPointDistance:
121				case JointType.Hinge:
122					//case Enums.JointType.Prismatic:
123					return true;
124			}
125
126			return false;
127		}
128		#endregion
129
130		#region IsFeatureSupported (Public)
131		/// <summary>
132		/// Implementation for getting which features are supported by Bullet.
133		/// </summary>
134		/// <param name="support">The type of feature to check if supported.</param>
135		/// <returns>True if supported, false otherwise.</returns>
136		public override bool IsFeatureSupported(FeatureSupport support)
137		{
138			switch (support)
139			{
140				case FeatureSupport.Joint:
141					return true;
142			}
143
144			return false;
145		}
146		#endregion
147
148		#region SetGroundPlane (Public)
149		/// <summary>
150		/// Implementation of SetGroundPlane
151		/// </summary>
152		/// <param name="enable">True to enable the ground plane, false otherwise.</param>
153		/// <param name="height">The height of the plane.</param>
154		public override void SetGroundPlane(bool enable, float height)
155		{
156			RigidBody groundRigidBody = ((BulletBody)groundBody).bulletBody;
157			BulletVector3 translate = new BulletVector3(height - (PlaneHeight * 0.5f));
158			groundRigidBody.Translate(ref translate);
159
160			// Check if we need to add it
161			if (enable)
162			{
163				if (groundRigidBody.IsInWorld() == false)
164				{
165					bulletWorld.AddRigidBody(groundRigidBody);
166				}
167			}
168			else
169			{
170				if (groundRigidBody.IsInWorld())
171				{
172					bulletWorld.RemoveRigidBody(groundRigidBody);
173				}
174			}
175		}
176		#endregion
177
178		#region Methods (Private)
179
180		#region CreateBody
181		/// <summary>
182		/// Creates a BulletBody from base implementation.
183		/// </summary>
184		/// <param name="is2DBody">True if the body is 2D, false means that is 3D.</param>
185		/// <param name="shape">The shape to attach to the new create body.</param>
186		/// <param name="initialPosition">Initial position of the body.</param>
187		/// <returns>New PhysicsBody instance or null if not supported.</returns>
188		protected override PhysicsBody CreateBody(bool is2DBody,
189			PhysicsShape shape, Vector initialPosition)
190		{
191			if (is2DBody)
192			{
193				Log.Warning("Bullet does not support 2D bodies.");
194				return null;
195			}
196
197			PhysicsBody body = new BulletBody(this, shape, initialPosition);
198			bodies.Add(body);
199			return body;
200		}
201		#endregion
202
203		#region CreateJoint
204		/// <summary>
205		/// Creates a BulletJoint from base implementation.
206		/// </summary>
207		/// <param name="jointType">The type of joint to create.</param>
208		/// <param name="bodyA">The first required body.</param>
209		/// <param name="bodyB">The second [optional] body.</param>
210		/// <param name="args">Array of args to pass to Joint implementation.</param>
211		/// <returns></returns>
212		public override PhysicsJoint CreateJoint(
213			JointType jointType,
214			PhysicsBody bodyA, PhysicsBody bodyB, object[] args)
215		{
216			if (IsJointSupported(jointType) == false)
217			{
218				Log.Warning("Current module does not support " +
219				            "the type of joint " + jointType);
220				return null;
221			}
222
223			PhysicsJoint joint =
224				new BulletJoint(this, jointType, bodyA, bodyB, args);
225
226			if (joint != null)
227			{
228				joints.Add(joint);
229			}
230
231			return joint;
232		}
233		#endregion
234
235		#region CreateGroundBody
236		/// <summary>
237		/// Create the body that will be used as ground.
238		/// </summary>
239		private void CreateGroundBody()
240		{
241			BulletVector3 vectorSize =
242				new BulletVector3(20000.0f, 20000.0f, PlaneHeight / 2.0f);
243
244			CollisionShape groundShape = new BoxShape(ref vectorSize);
245			DefaultMotionState groundMotionState =
246				new DefaultMotionState(BulletMatrix.Identity, BulletMatrix.Identity);
247
248			RigidBodyConstructionInfo rbInfo = new RigidBodyConstructionInfo(
249				0.0f, groundMotionState, groundShape, BulletVector3.Zero);
250			rbInfo.m_restitution = 1.0f;
251			rbInfo.m_mass = 0.0f;
252			rbInfo.m_friction = 0.5f;
253			rbInfo.m_angularDamping = 0.3f;
254			rbInfo.m_linearDamping = 0.3f;
255
256			RigidBody groundRigidBody = new RigidBody(rbInfo);
257
258			groundBody = new BulletBody(this, groundRigidBody, groundShape);
259			groundBody.Name = "PlaneBody";
260		}
261		#endregion
262
263		#region RemoveBodyImpl
264		/// <summary>
265		/// Implementation of RemoveBody.
266		/// </summary>
267		/// <param name="body">The body to remove.</param>
268		protected override void RemoveBodyImpl(PhysicsBody body)
269		{
270			// Remove from bullet world
271			bulletWorld.RemoveRigidBody((body as BulletBody).bulletBody);
272		}
273		#endregion
274
275		#region RemoveJointImpl
276		/// <summary>
277		/// Implementation of RemoveJoint.
278		/// </summary>
279		/// <param name="body">The joint to remove.</param>
280		protected override void RemoveJointImpl(PhysicsJoint joint)
281		{
282			BulletJoint bulletJoint = joint as BulletJoint;
283
284			bulletWorld.RemoveConstraint(bulletJoint.Constraint);
285		}
286		#endregion
287
288		#region RayCastImpl
289		/// <summary>
290		/// Performs ray cast in Bullet world.
291		/// </summary>
292		/// <param name="ray"></param>
293		/// <param name="checkGround"></param>
294		/// <param name="foundBody"></param>
295		/// <param name="surfaceNormal"></param>
296		/// <param name="fraction"></param>
297		/// <param name="userData"></param>
298		/// <returns></returns>
299		protected override bool RayCastImpl(Ray ray, bool checkGround,
300			out PhysicsBody foundBody, out Vector surfaceNormal, out float fraction,
301			out object userData)
302		{
303			foundBody = null;
304			surfaceNormal = Vector.Zero;
305			fraction = 0.0f;
306			userData = null;
307
308			var rayPos = BulletDatatypesMapping.Convert(ray.Position);
309			var rayDir = BulletDatatypesMapping.Convert(ray.Direction);
310			ClosestRayResultCallback resultCallback
311				= new ClosestRayResultCallback(ref rayPos, ref rayDir);
312			bulletWorld.RayTest(ref rayPos, ref rayDir, resultCallback);
313			if (resultCallback.HasHit() == false)
314			{
315				return false;
316			}
317
318			RigidBody rigBody = RigidBody.Upcast(resultCallback.m_collisionObject);
319			BulletBody body = rigBody.GetUserPointer() as BulletBody;
320
321			if (body != null)
322			{
323				foundBody = body;
324				surfaceNormal = BulletDatatypesMapping.Convert(
325					resultCallback.m_hitNormalWorld);
326				fraction = resultCallback.m_closestHitFraction;
327				return true;
328			}
329
330			return false;
331		}
332		#endregion
333
334		#region UpdateSimulation
335		/// <summary>
336		/// Update simulation implementation of Physics.
337		/// </summary>
338		protected override void UpdateSimulation(float timeStep)
339		{
340			// http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_the_World
341			if (IsPaused == false)
342			{
343				bulletWorld.StepSimulation(timeStep, 10);
344			}
345		}
346		#endregion
347
348		#region SetGravity
349		/// <summary>
350		/// Sets gravity implementation.
351		/// </summary>
352		/// <param name="gravity">The 3D gravity vector.</param>
353		protected override void SetGravity(Vector gravity)
354		{
355			var bulletVector = BulletDatatypesMapping.Convert(gravity);
356			bulletWorld.SetGravity(ref bulletVector);
357		}
358		#endregion
359
360		#region SetMultithreading
361		/// <summary>
362		/// Sets multithreading on Bullet implementation.
363		/// </summary>
364		/// <param name="enable">True to enable, false otherwise.</param>
365		protected override void SetMultithreading(bool enable)
366		{
367			// Not supported
368			if (enable)
369			{
370				Log.Warning("BulleXNA does not support multi-threading yet!");
371			}
372		}
373		#endregion
374
375		#region GetTotalPhysicsTime
376		/// <summary>
377		/// Gets total time step of physics simulation.
378		/// </summary>
379		/// <returns></returns>
380		protected override double GetTotalPhysicsTime()
381		{
382			return bulletWorld.GetDispatchInfo().GetTimeStep();
383		}
384		#endregion
385
386		#endregion
387	}
388}