/* * Copyright (c) Contributors, http://www.openmetaverse.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSim Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #region References using System; using System.Collections.Generic; using OpenSim.Physics.Manager; using Axiom.Math; //Specific References for BulletXPlugin using MonoXnaCompactMaths; using XnaDevRu.BulletX; using XnaDevRu.BulletX.Dynamics; #endregion namespace OpenSim.Region.Physics.BulletXPlugin { /// /// This Class converts objects and types for BulletX /// public class BulletXConversions { public static MonoXnaCompactMaths.Vector3 PhysicsVectorToXnaVector3(PhysicsVector physicsVector) { return new MonoXnaCompactMaths.Vector3(physicsVector.X, physicsVector.Y, physicsVector.Z); } public static void PhysicsVectorToXnaVector3(PhysicsVector physicsVector, out MonoXnaCompactMaths.Vector3 XnaVector3) { XnaVector3.X = physicsVector.X; XnaVector3.Y = physicsVector.Y; XnaVector3.Z = physicsVector.Z; } public static PhysicsVector XnaVector3ToPhysicsVector(MonoXnaCompactMaths.Vector3 xnaVector3) { return new PhysicsVector(xnaVector3.X, xnaVector3.Y, xnaVector3.Z); } /*public static void XnaVector3ToPhysicsVector(MonoXnaCompactMaths.Vector3 xnaVector3, out PhysicsVector physicsVector) { xnaVector3.X = physicsVector.X; xnaVector3.Y = physicsVector.Y; xnaVector3.Z = physicsVector.Z; }*/ #region Axiom and Xna ///// ///// BTW maybe some conversions will be a simply converion that it doesn't require this class, but i don't know ///// ///// ///// //public static MonoXnaCompactMaths.Vector3 Vector3AxiomToXna(Axiom.Math.Vector3 AxiomVector3) //{ // return new MonoXnaCompactMaths.Vector3(AxiomVector3.x, AxiomVector3.y, AxiomVector3.z); //} #endregion } /// /// PhysicsPlugin Class for BulletX /// public class BulletXPlugin : IPhysicsPlugin { private BulletXScene _mScene; public BulletXPlugin() { } public bool Init() { return true; } public PhysicsScene GetScene() { if (_mScene == null) { _mScene = new BulletXScene(); } return (_mScene); } public string GetName() { return ("BulletXEngine"); } public void Dispose() { } } /// /// PhysicsScene Class for BulletX /// public class BulletXScene : PhysicsScene { public DiscreteDynamicsWorld ddWorld; private CollisionDispatcher cDispatcher; private OverlappingPairCache opCache; private SequentialImpulseConstraintSolver sicSolver; private const int minXY = 0; private const int minZ = 0; private const int maxXY = 256; private const int maxZ = 4096; private const int maxHandles = 32766; //Why? I don't know private static float gravity = 9.8f; private static float heightLevel0 = 77.0f; private static float heightLevel1 = 200.0f; private static float lowGravityFactor = 0.2f; private float[] _heightmap; private List _characters = new List(); public static float Gravity { get { return gravity; } } public static float HeightLevel0 { get { return heightLevel0; } } public static float HeightLevel1 { get { return heightLevel1; } } public static float LowGravityFactor { get { return lowGravityFactor; } } public BulletXScene() { cDispatcher = new CollisionDispatcher(); MonoXnaCompactMaths.Vector3 worldMinDim = new MonoXnaCompactMaths.Vector3((float)minXY, (float)minXY, (float)minZ); MonoXnaCompactMaths.Vector3 worldMaxDim = new MonoXnaCompactMaths.Vector3((float)maxXY, (float)maxXY, (float)maxZ); opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles); sicSolver = new SequentialImpulseConstraintSolver(); ddWorld = new DiscreteDynamicsWorld(cDispatcher, opCache, sicSolver); ddWorld.Gravity = new MonoXnaCompactMaths.Vector3(0, 0, -gravity); this._heightmap = new float[65536]; } public override PhysicsActor AddAvatar(PhysicsVector position) { PhysicsVector pos = new PhysicsVector(); pos.X = position.X; pos.Y = position.Y; pos.Z = position.Z + 20; BulletXCharacter newAv = new BulletXCharacter(this, pos); this._characters.Add(newAv); return newAv; } public override void RemoveAvatar(PhysicsActor actor) { } public override PhysicsActor AddPrim(PhysicsVector position, PhysicsVector size) { PhysicsVector pos = new PhysicsVector(); pos.X = position.X; pos.Y = position.Y; pos.Z = position.Z; PhysicsVector siz = new PhysicsVector(); siz.X = size.X; siz.Y = size.Y; siz.Z = size.Z; return new BulletXPrim(); } public override void Simulate(float timeStep) { foreach (BulletXCharacter actor in _characters) { actor.Move(timeStep); } ddWorld.StepSimulation(timeStep, 0, timeStep); foreach (BulletXCharacter actor in _characters) { actor.ValidateHeight(this._heightmap[ (int)Math.Round(actor.RigidBodyHorizontalPosition.x) * 256 + (int)Math.Round(actor.RigidBodyHorizontalPosition.y)]); } foreach (BulletXCharacter actor in _characters) { actor.UpdatePosition(); } } public override void GetResults() { } public override bool IsThreaded { get { return (false); // for now we won't be multithreaded } } public override void SetTerrain(float[] heightMap) { //As the same as ODE, heightmap (x,y) must be swapped for BulletX for (int i = 0; i < 65536; i++) { // this._heightmap[i] = (double)heightMap[i]; // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...) int x = i & 0xff; int y = i >> 8; this._heightmap[i] = heightMap[x * 256 + y]; } } public override void DeleteTerrain() { } } /// /// PhysicsActor Character Class for BulletX /// public class BulletXCharacter : PhysicsActor { private PhysicsVector _position; private PhysicsVector _velocity; private PhysicsVector _acceleration; private bool flying; private RigidBody rigidBody; public Axiom.Math.Vector2 RigidBodyHorizontalPosition { get { return new Axiom.Math.Vector2(this.rigidBody.CenterOfMassPosition.X, this.rigidBody.CenterOfMassPosition.Y); } } public BulletXCharacter(BulletXScene parent_scene, PhysicsVector pos) { _velocity = new PhysicsVector(); _position = pos; _acceleration = new PhysicsVector(); float _mass = 50.0f; //This depends of avatar's dimensions Matrix _startTransform = Matrix.Identity; _startTransform.Translation = BulletXConversions.PhysicsVectorToXnaVector3(pos); Matrix _centerOfMassOffset = Matrix.Identity; CollisionShape _collisionShape = new BoxShape(new MonoXnaCompactMaths.Vector3(0.5f, 0.5f, 1.60f)); DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset); MonoXnaCompactMaths.Vector3 _localInertia = new MonoXnaCompactMaths.Vector3(); _collisionShape.CalculateLocalInertia(_mass, out _localInertia); //Always when mass > 0 //The next values might change float _linearDamping = 0.0f; float _angularDamping = 0.0f; float _friction = 0.5f; float _restitution = 0.0f; rigidBody = new RigidBody(_mass, _motionState, _collisionShape, _localInertia, _linearDamping, _angularDamping, _friction, _restitution); rigidBody.ActivationState = ActivationState.DisableDeactivation; parent_scene.ddWorld.AddRigidBody(rigidBody); } public override bool Flying { get { return flying; } set { flying = value; } } public override PhysicsVector Position { get { return _position; } set { _position = value; } } public override PhysicsVector Velocity { get { return _velocity; } set { _velocity = value; } } public override bool Kinematic { get { return false; } set { } } public override Axiom.Math.Quaternion Orientation { get { return Axiom.Math.Quaternion.Identity; } set { } } public override PhysicsVector Acceleration { get { return _acceleration; } } public void SetAcceleration(PhysicsVector accel) { this._acceleration = accel; } public override void AddForce(PhysicsVector force) { } public override void SetMomentum(PhysicsVector momentum) { } public void Move(float timeStep) { MonoXnaCompactMaths.Vector3 vec = new MonoXnaCompactMaths.Vector3(); //if (this._velocity.X == 0.0f) // vec.X = this.rigidBody.LinearVelocity.X; //current velocity //else vec.X = this._velocity.X; //overrides current velocity //if (this._velocity.Y == 0.0f) // vec.Y = this.rigidBody.LinearVelocity.Y; //current velocity //else vec.Y = this._velocity.Y; //overrides current velocity float nextZVelocity; //if (this._velocity.Z == 0.0f) // nextZVelocity = this.rigidBody.LinearVelocity.Z; //current velocity //else nextZVelocity = this._velocity.Z; //overrides current velocity if (flying) { //Antigravity with movement if (this._position.Z <= BulletXScene.HeightLevel0) { vec.Z = nextZVelocity + BulletXScene.Gravity * timeStep; } //Lowgravity with movement else if((this._position.Z > BulletXScene.HeightLevel0) && (this._position.Z <= BulletXScene.HeightLevel1)) { vec.Z = nextZVelocity + BulletXScene.Gravity * timeStep * (1.0f - BulletXScene.LowGravityFactor); } //Lowgravity with... else if (this._position.Z > BulletXScene.HeightLevel1) { if(nextZVelocity > 0) //no movement vec.Z = BulletXScene.Gravity * timeStep * (1.0f - BulletXScene.LowGravityFactor); else vec.Z = nextZVelocity + BulletXScene.Gravity * timeStep * (1.0f - BulletXScene.LowGravityFactor); } } else { vec.Z = nextZVelocity; } rigidBody.LinearVelocity = vec; } public void UpdatePosition() { this._position = BulletXConversions.XnaVector3ToPhysicsVector(rigidBody.CenterOfMassPosition); } //This validation is very basic internal void ValidateHeight(float heighmapPositionValue) { if (rigidBody.CenterOfMassPosition.Z < heighmapPositionValue) { Matrix m = rigidBody.WorldTransform; MonoXnaCompactMaths.Vector3 v3 = m.Translation; v3.Z = heighmapPositionValue; m.Translation = v3; rigidBody.WorldTransform = m; } } } /// /// PhysicsActor Prim Class for BulletX /// public class BulletXPrim : PhysicsActor { private PhysicsVector _position; private PhysicsVector _velocity; private PhysicsVector _acceleration; public BulletXPrim() { _velocity = new PhysicsVector(); _position = new PhysicsVector(); _acceleration = new PhysicsVector(); } public override bool Flying { get { return false; //no flying prims for you } set { } } public override PhysicsVector Position { get { PhysicsVector pos = new PhysicsVector(); // PhysicsVector vec = this._prim.Position; //pos.X = vec.X; //pos.Y = vec.Y; //pos.Z = vec.Z; return pos; } set { /*PhysicsVector vec = value; PhysicsVector pos = new PhysicsVector(); pos.X = vec.X; pos.Y = vec.Y; pos.Z = vec.Z; this._prim.Position = pos;*/ } } public override PhysicsVector Velocity { get { return _velocity; } set { _velocity = value; } } public override bool Kinematic { get { return false; //return this._prim.Kinematic; } set { //this._prim.Kinematic = value; } } public override Axiom.Math.Quaternion Orientation { get { Axiom.Math.Quaternion res = new Axiom.Math.Quaternion(); return res; } set { } } public override PhysicsVector Acceleration { get { return _acceleration; } } public void SetAcceleration(PhysicsVector accel) { this._acceleration = accel; } public override void AddForce(PhysicsVector force) { } public override void SetMomentum(PhysicsVector momentum) { } } }