1862 lines
62 KiB
C#
1862 lines
62 KiB
C#
/*
|
|
* Copyright (c) Contributors, http://opensimulator.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 OpenSimulator 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 OpenMetaverse;
|
|
using MonoXnaCompactMaths;
|
|
using OpenSim.Framework;
|
|
using OpenSim.Region.Physics.Manager;
|
|
using XnaDevRu.BulletX;
|
|
using XnaDevRu.BulletX.Dynamics;
|
|
using Nini.Config;
|
|
using Vector3 = MonoXnaCompactMaths.Vector3;
|
|
using Quaternion = MonoXnaCompactMaths.Quaternion;
|
|
|
|
#endregion
|
|
|
|
namespace OpenSim.Region.Physics.BulletXPlugin
|
|
{
|
|
/// <summary>
|
|
/// BulletXConversions are called now BulletXMaths
|
|
/// This Class converts objects and types for BulletX and give some operations
|
|
/// </summary>
|
|
public class BulletXMaths
|
|
{
|
|
//private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
|
|
|
//Vector3
|
|
public static Vector3 PhysicsVectorToXnaVector3(OpenMetaverse.Vector3 physicsVector)
|
|
{
|
|
return new Vector3(physicsVector.X, physicsVector.Y, physicsVector.Z);
|
|
}
|
|
|
|
public static OpenMetaverse.Vector3 XnaVector3ToPhysicsVector(Vector3 xnaVector3)
|
|
{
|
|
return new OpenMetaverse.Vector3(xnaVector3.X, xnaVector3.Y, xnaVector3.Z);
|
|
}
|
|
|
|
//Quaternion
|
|
public static Quaternion QuaternionToXnaQuaternion(OpenMetaverse.Quaternion quaternion)
|
|
{
|
|
return new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
|
|
}
|
|
|
|
public static OpenMetaverse.Quaternion XnaQuaternionToQuaternion(Quaternion xnaQuaternion)
|
|
{
|
|
return new OpenMetaverse.Quaternion(xnaQuaternion.W, xnaQuaternion.X, xnaQuaternion.Y, xnaQuaternion.Z);
|
|
}
|
|
|
|
//Next methods are extracted from XnaDevRu.BulletX(See 3rd party license):
|
|
//- SetRotation (class MatrixOperations)
|
|
//- GetRotation (class MatrixOperations)
|
|
//- GetElement (class MathHelper)
|
|
//- SetElement (class MathHelper)
|
|
internal static void SetRotation(ref Matrix m, Quaternion q)
|
|
{
|
|
float d = q.LengthSquared();
|
|
float s = 2f/d;
|
|
float xs = q.X*s, ys = q.Y*s, zs = q.Z*s;
|
|
float wx = q.W*xs, wy = q.W*ys, wz = q.W*zs;
|
|
float xx = q.X*xs, xy = q.X*ys, xz = q.X*zs;
|
|
float yy = q.Y*ys, yz = q.Y*zs, zz = q.Z*zs;
|
|
m = new Matrix(1 - (yy + zz), xy - wz, xz + wy, 0,
|
|
xy + wz, 1 - (xx + zz), yz - wx, 0,
|
|
xz - wy, yz + wx, 1 - (xx + yy), 0,
|
|
m.M41, m.M42, m.M43, 1);
|
|
}
|
|
|
|
internal static Quaternion GetRotation(Matrix m)
|
|
{
|
|
Quaternion q;
|
|
|
|
float trace = m.M11 + m.M22 + m.M33;
|
|
|
|
if (trace > 0)
|
|
{
|
|
float s = (float) Math.Sqrt(trace + 1);
|
|
q.W = s*0.5f;
|
|
s = 0.5f/s;
|
|
|
|
q.X = (m.M32 - m.M23)*s;
|
|
q.Y = (m.M13 - m.M31)*s;
|
|
q.Z = (m.M21 - m.M12)*s;
|
|
}
|
|
else
|
|
{
|
|
q.X = q.Y = q.Z = q.W = 0f;
|
|
|
|
int i = m.M11 < m.M22
|
|
?
|
|
(m.M22 < m.M33 ? 2 : 1)
|
|
:
|
|
(m.M11 < m.M33 ? 2 : 0);
|
|
int j = (i + 1)%3;
|
|
int k = (i + 2)%3;
|
|
|
|
float s = (float) Math.Sqrt(GetElement(m, i, i) - GetElement(m, j, j) - GetElement(m, k, k) + 1);
|
|
SetElement(ref q, i, s*0.5f);
|
|
s = 0.5f/s;
|
|
|
|
q.W = (GetElement(m, k, j) - GetElement(m, j, k))*s;
|
|
SetElement(ref q, j, (GetElement(m, j, i) + GetElement(m, i, j))*s);
|
|
SetElement(ref q, k, (GetElement(m, k, i) + GetElement(m, i, k))*s);
|
|
}
|
|
|
|
return q;
|
|
}
|
|
|
|
internal static float SetElement(ref Quaternion q, int index, float value)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
q.X = value;
|
|
break;
|
|
case 1:
|
|
q.Y = value;
|
|
break;
|
|
case 2:
|
|
q.Z = value;
|
|
break;
|
|
case 3:
|
|
q.W = value;
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
internal static float GetElement(Matrix mat, int row, int col)
|
|
{
|
|
switch (row)
|
|
{
|
|
case 0:
|
|
switch (col)
|
|
{
|
|
case 0:
|
|
return mat.M11;
|
|
case 1:
|
|
return mat.M12;
|
|
case 2:
|
|
return mat.M13;
|
|
}
|
|
break;
|
|
case 1:
|
|
switch (col)
|
|
{
|
|
case 0:
|
|
return mat.M21;
|
|
case 1:
|
|
return mat.M22;
|
|
case 2:
|
|
return mat.M23;
|
|
}
|
|
break;
|
|
case 2:
|
|
switch (col)
|
|
{
|
|
case 0:
|
|
return mat.M31;
|
|
case 1:
|
|
return mat.M32;
|
|
case 2:
|
|
return mat.M33;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// PhysicsPlugin Class for BulletX
|
|
/// </summary>
|
|
public class BulletXPlugin : IPhysicsPlugin
|
|
{
|
|
private BulletXScene _mScene;
|
|
|
|
public BulletXPlugin()
|
|
{
|
|
}
|
|
|
|
public bool Init()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public PhysicsScene GetScene(string sceneIdentifier)
|
|
{
|
|
if (_mScene == null)
|
|
{
|
|
_mScene = new BulletXScene(sceneIdentifier);
|
|
}
|
|
return (_mScene);
|
|
}
|
|
|
|
public string GetName()
|
|
{
|
|
return ("modified_BulletX"); //Changed!! "BulletXEngine" To "modified_BulletX"
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
// Class to detect and debug collisions
|
|
// Mainly used for debugging purposes
|
|
internal class CollisionDispatcherLocal : CollisionDispatcher
|
|
{
|
|
private BulletXScene relatedScene;
|
|
|
|
public CollisionDispatcherLocal(BulletXScene s)
|
|
: base()
|
|
{
|
|
relatedScene = s;
|
|
}
|
|
|
|
public override bool NeedsCollision(CollisionObject bodyA, CollisionObject bodyB)
|
|
{
|
|
RigidBody rb;
|
|
BulletXCharacter bxcA = null;
|
|
BulletXPrim bxpA = null;
|
|
Type t = bodyA.GetType();
|
|
if (t == typeof (RigidBody))
|
|
{
|
|
rb = (RigidBody) bodyA;
|
|
relatedScene._characters.TryGetValue(rb, out bxcA);
|
|
relatedScene._prims.TryGetValue(rb, out bxpA);
|
|
}
|
|
// String nameA;
|
|
// if (bxcA != null)
|
|
// nameA = bxcA._name;
|
|
// else if (bxpA != null)
|
|
// nameA = bxpA._name;
|
|
// else
|
|
// nameA = "null";
|
|
|
|
|
|
|
|
BulletXCharacter bxcB = null;
|
|
BulletXPrim bxpB = null;
|
|
t = bodyB.GetType();
|
|
if (t == typeof (RigidBody))
|
|
{
|
|
rb = (RigidBody) bodyB;
|
|
relatedScene._characters.TryGetValue(rb, out bxcB);
|
|
relatedScene._prims.TryGetValue(rb, out bxpB);
|
|
}
|
|
|
|
// String nameB;
|
|
// if (bxcB != null)
|
|
// nameB = bxcB._name;
|
|
// else if (bxpB != null)
|
|
// nameB = bxpB._name;
|
|
// else
|
|
// nameB = "null";
|
|
bool needsCollision;// = base.NeedsCollision(bodyA, bodyB);
|
|
int c1 = 3;
|
|
int c2 = 3;
|
|
|
|
////////////////////////////////////////////////////////
|
|
//BulletX Mesh Collisions
|
|
//added by Jed zhu
|
|
//data: May 07,2005
|
|
////////////////////////////////////////////////////////
|
|
#region BulletXMeshCollisions Fields
|
|
|
|
|
|
if (bxcA != null && bxpB != null)
|
|
c1 = Collision(bxcA, bxpB);
|
|
if (bxpA != null && bxcB != null)
|
|
c2 = Collision(bxcB, bxpA);
|
|
if (c1 < 2)
|
|
needsCollision = (c1 > 0) ? true : false;
|
|
else if (c2 < 2)
|
|
needsCollision = (c2 > 0) ? true : false;
|
|
else
|
|
needsCollision = base.NeedsCollision(bodyA, bodyB);
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
//m_log.DebugFormat("[BulletX]: A collision was detected between {0} and {1} --> {2}", nameA, nameB,
|
|
//needsCollision);
|
|
|
|
|
|
return needsCollision;
|
|
}
|
|
//added by jed zhu
|
|
//calculas the collision between the Prim and Actor
|
|
//
|
|
private int Collision(BulletXCharacter actorA, BulletXPrim primB)
|
|
{
|
|
int[] indexBase;
|
|
Vector3[] vertexBase;
|
|
Vector3 vNormal;
|
|
// Vector3 vP1;
|
|
// Vector3 vP2;
|
|
// Vector3 vP3;
|
|
IMesh mesh = primB.GetMesh();
|
|
|
|
float fdistance;
|
|
if (primB == null)
|
|
return 3;
|
|
if (mesh == null)
|
|
return 2;
|
|
if (actorA == null)
|
|
return 3;
|
|
|
|
int iVertexCount = mesh.getVertexList().Count;
|
|
int iIndexCount = mesh.getIndexListAsInt().Length;
|
|
if (iVertexCount == 0)
|
|
return 3;
|
|
if (iIndexCount == 0)
|
|
return 3;
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
indexBase = mesh.getIndexListAsInt();
|
|
vertexBase = new Vector3[iVertexCount];
|
|
|
|
for (int i = 0; i < iVertexCount; i++)
|
|
{
|
|
OpenMetaverse.Vector3 v = mesh.getVertexList()[i];
|
|
if (v != null) // Note, null has special meaning. See meshing code for details
|
|
vertexBase[i] = BulletXMaths.PhysicsVectorToXnaVector3(v);
|
|
else
|
|
vertexBase[i] = Vector3.Zero;
|
|
}
|
|
|
|
for (int ix = 0; ix < iIndexCount; ix += 3)
|
|
{
|
|
int ia = indexBase[ix + 0];
|
|
int ib = indexBase[ix + 1];
|
|
int ic = indexBase[ix + 2];
|
|
//
|
|
Vector3 v1 = vertexBase[ib] - vertexBase[ia];
|
|
Vector3 v2 = vertexBase[ic] - vertexBase[ia];
|
|
|
|
Vector3.Cross(ref v1, ref v2, out vNormal);
|
|
Vector3.Normalize(ref vNormal, out vNormal);
|
|
|
|
fdistance = Vector3.Dot(vNormal, vertexBase[ia]) + 0.50f;
|
|
if (preCheckCollision(actorA, vNormal, fdistance) == 1)
|
|
{
|
|
if (CheckCollision(actorA, ia, ib, ic, vNormal, vertexBase) == 1)
|
|
{
|
|
//PhysicsVector v = actorA.Position;
|
|
//Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v);
|
|
//Vector3 vp = vNormal * (fdistance - Vector3.Dot(vNormal, v3) + 0.2f);
|
|
//actorA.Position += BulletXMaths.XnaVector3ToPhysicsVector(vp);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
//added by jed zhu
|
|
//return value 1: need second check
|
|
//return value 0: no need check
|
|
|
|
private int preCheckCollision(BulletXActor actA, Vector3 vNormal, float fDist)
|
|
{
|
|
float fstartSide;
|
|
OpenMetaverse.Vector3 v = actA.Position;
|
|
Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v);
|
|
|
|
fstartSide = Vector3.Dot(vNormal, v3) - fDist;
|
|
if (fstartSide > 0) return 0;
|
|
else return 1;
|
|
}
|
|
//added by jed zhu
|
|
private int CheckCollision(BulletXActor actA, int ia, int ib, int ic, Vector3 vNormal, Vector3[] vertBase)
|
|
{
|
|
Vector3 perPlaneNormal;
|
|
float fPerPlaneDist;
|
|
OpenMetaverse.Vector3 v = actA.Position;
|
|
Vector3 v3 = BulletXMaths.PhysicsVectorToXnaVector3(v);
|
|
//check AB
|
|
Vector3 v1;
|
|
v1 = vertBase[ib] - vertBase[ia];
|
|
Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal);
|
|
Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal);
|
|
|
|
if (Vector3.Dot((vertBase[ic] - vertBase[ia]), perPlaneNormal) < 0)
|
|
perPlaneNormal = -perPlaneNormal;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ia]) - 0.50f;
|
|
|
|
|
|
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0)
|
|
return 0;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ic]) + 0.50f;
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0)
|
|
return 0;
|
|
|
|
//check BC
|
|
|
|
v1 = vertBase[ic] - vertBase[ib];
|
|
Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal);
|
|
Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal);
|
|
|
|
if (Vector3.Dot((vertBase[ia] - vertBase[ib]), perPlaneNormal) < 0)
|
|
perPlaneNormal = -perPlaneNormal;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ib]) - 0.50f;
|
|
|
|
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0)
|
|
return 0;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ia]) + 0.50f;
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0)
|
|
return 0;
|
|
//check CA
|
|
v1 = vertBase[ia] - vertBase[ic];
|
|
Vector3.Cross(ref vNormal, ref v1, out perPlaneNormal);
|
|
Vector3.Normalize(ref perPlaneNormal, out perPlaneNormal);
|
|
|
|
if (Vector3.Dot((vertBase[ib] - vertBase[ic]), perPlaneNormal) < 0)
|
|
perPlaneNormal = -perPlaneNormal;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ic]) - 0.50f;
|
|
|
|
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) < 0)
|
|
return 0;
|
|
fPerPlaneDist = Vector3.Dot(perPlaneNormal, vertBase[ib]) + 0.50f;
|
|
if ((Vector3.Dot(perPlaneNormal, v3) - fPerPlaneDist) > 0)
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// PhysicsScene Class for BulletX
|
|
/// </summary>
|
|
public class BulletXScene : PhysicsScene
|
|
{
|
|
#region BulletXScene Fields
|
|
|
|
public DiscreteDynamicsWorld ddWorld;
|
|
private CollisionDispatcher cDispatcher;
|
|
private OverlappingPairCache opCache;
|
|
private SequentialImpulseConstraintSolver sicSolver;
|
|
public static Object BulletXLock = new Object();
|
|
|
|
private const int minXY = 0;
|
|
private const int minZ = 0;
|
|
private const int maxXY = (int)Constants.RegionSize;
|
|
private const int maxZ = 4096;
|
|
private const int maxHandles = 32766; //Why? I don't know
|
|
private const float gravity = 9.8f;
|
|
private const float heightLevel0 = 77.0f;
|
|
private const float heightLevel1 = 200.0f;
|
|
private const float lowGravityFactor = 0.2f;
|
|
//OpenSim calls Simulate 10 times per seconds. So FPS = "Simulate Calls" * simulationSubSteps = 100 FPS
|
|
private const int simulationSubSteps = 10;
|
|
//private float[] _heightmap;
|
|
private BulletXPlanet _simFlatPlanet;
|
|
internal Dictionary<RigidBody, BulletXCharacter> _characters = new Dictionary<RigidBody, BulletXCharacter>();
|
|
internal Dictionary<RigidBody, BulletXPrim> _prims = new Dictionary<RigidBody, BulletXPrim>();
|
|
|
|
public IMesher mesher;
|
|
// private IConfigSource m_config;
|
|
|
|
// protected internal String identifier;
|
|
|
|
public BulletXScene(String sceneIdentifier)
|
|
{
|
|
//identifier = sceneIdentifier;
|
|
cDispatcher = new CollisionDispatcherLocal(this);
|
|
Vector3 worldMinDim = new Vector3((float)minXY, (float)minXY, (float)minZ);
|
|
Vector3 worldMaxDim = new Vector3((float)maxXY, (float)maxXY, (float)maxZ);
|
|
opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles);
|
|
sicSolver = new SequentialImpulseConstraintSolver();
|
|
|
|
lock (BulletXLock)
|
|
{
|
|
ddWorld = new DiscreteDynamicsWorld(cDispatcher, opCache, sicSolver);
|
|
ddWorld.Gravity = new Vector3(0, 0, -gravity);
|
|
}
|
|
//this._heightmap = new float[65536];
|
|
}
|
|
|
|
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 static int MaxXY
|
|
{
|
|
get { return maxXY; }
|
|
}
|
|
|
|
public static int MaxZ
|
|
{
|
|
get { return maxZ; }
|
|
}
|
|
|
|
private List<RigidBody> _forgottenRigidBodies = new List<RigidBody>();
|
|
internal string is_ex_message = "Can't remove rigidBody!: ";
|
|
|
|
#endregion
|
|
|
|
public BulletXScene()
|
|
{
|
|
cDispatcher = new CollisionDispatcherLocal(this);
|
|
Vector3 worldMinDim = new Vector3((float) minXY, (float) minXY, (float) minZ);
|
|
Vector3 worldMaxDim = new Vector3((float) maxXY, (float) maxXY, (float) maxZ);
|
|
opCache = new AxisSweep3(worldMinDim, worldMaxDim, maxHandles);
|
|
sicSolver = new SequentialImpulseConstraintSolver();
|
|
|
|
lock (BulletXLock)
|
|
{
|
|
ddWorld = new DiscreteDynamicsWorld(cDispatcher, opCache, sicSolver);
|
|
ddWorld.Gravity = new Vector3(0, 0, -gravity);
|
|
}
|
|
//this._heightmap = new float[65536];
|
|
}
|
|
|
|
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
|
{
|
|
mesher = meshmerizer;
|
|
// m_config = config;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
|
|
}
|
|
|
|
public override Dictionary<uint, float> GetTopColliders()
|
|
{
|
|
Dictionary<uint, float> returncolliders = new Dictionary<uint, float>();
|
|
return returncolliders;
|
|
}
|
|
|
|
public override void SetWaterLevel(float baseheight)
|
|
{
|
|
|
|
}
|
|
|
|
public override PhysicsActor AddAvatar(string avName, OpenMetaverse.Vector3 position, OpenMetaverse.Vector3 size, bool isFlying)
|
|
{
|
|
OpenMetaverse.Vector3 pos = OpenMetaverse.Vector3.Zero;
|
|
pos.X = position.X;
|
|
pos.Y = position.Y;
|
|
pos.Z = position.Z + 20;
|
|
BulletXCharacter newAv = null;
|
|
lock (BulletXLock)
|
|
{
|
|
newAv = new BulletXCharacter(avName, this, pos);
|
|
_characters.Add(newAv.RigidBody, newAv);
|
|
}
|
|
newAv.Flying = isFlying;
|
|
return newAv;
|
|
}
|
|
|
|
public override void RemoveAvatar(PhysicsActor actor)
|
|
{
|
|
if (actor is BulletXCharacter)
|
|
{
|
|
lock (BulletXLock)
|
|
{
|
|
try
|
|
{
|
|
ddWorld.RemoveRigidBody(((BulletXCharacter) actor).RigidBody);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXMessage(is_ex_message + ex.Message, true);
|
|
((BulletXCharacter) actor).RigidBody.ActivationState = ActivationState.DisableSimulation;
|
|
AddForgottenRigidBody(((BulletXCharacter) actor).RigidBody);
|
|
}
|
|
_characters.Remove(((BulletXCharacter) actor).RigidBody);
|
|
}
|
|
GC.Collect();
|
|
}
|
|
}
|
|
|
|
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, OpenMetaverse.Vector3 position,
|
|
OpenMetaverse.Vector3 size, OpenMetaverse.Quaternion rotation)
|
|
{
|
|
return AddPrimShape(primName, pbs, position, size, rotation, false);
|
|
}
|
|
|
|
public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, OpenMetaverse.Vector3 position,
|
|
OpenMetaverse.Vector3 size, OpenMetaverse.Quaternion rotation, bool isPhysical)
|
|
{
|
|
PhysicsActor result;
|
|
|
|
switch (pbs.ProfileShape)
|
|
{
|
|
case ProfileShape.Square:
|
|
/// support simple box & hollow box now; later, more shapes
|
|
if (pbs.ProfileHollow == 0)
|
|
{
|
|
result = AddPrim(primName, position, size, rotation, null, null, isPhysical);
|
|
}
|
|
else
|
|
{
|
|
IMesh mesh = mesher.CreateMesh(primName, pbs, size, 32f, isPhysical);
|
|
result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
result = AddPrim(primName, position, size, rotation, null, null, isPhysical);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public PhysicsActor AddPrim(String name, OpenMetaverse.Vector3 position, OpenMetaverse.Vector3 size, OpenMetaverse.Quaternion rotation,
|
|
IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical)
|
|
{
|
|
BulletXPrim newPrim = null;
|
|
lock (BulletXLock)
|
|
{
|
|
newPrim = new BulletXPrim(name, this, position, size, rotation, mesh, pbs, isPhysical);
|
|
_prims.Add(newPrim.RigidBody, newPrim);
|
|
}
|
|
return newPrim;
|
|
}
|
|
|
|
public override void RemovePrim(PhysicsActor prim)
|
|
{
|
|
if (prim is BulletXPrim)
|
|
{
|
|
lock (BulletXLock)
|
|
{
|
|
try
|
|
{
|
|
ddWorld.RemoveRigidBody(((BulletXPrim) prim).RigidBody);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXMessage(is_ex_message + ex.Message, true);
|
|
((BulletXPrim) prim).RigidBody.ActivationState = ActivationState.DisableSimulation;
|
|
AddForgottenRigidBody(((BulletXPrim) prim).RigidBody);
|
|
}
|
|
_prims.Remove(((BulletXPrim) prim).RigidBody);
|
|
}
|
|
GC.Collect();
|
|
}
|
|
}
|
|
|
|
public override void AddPhysicsActorTaint(PhysicsActor prim)
|
|
{
|
|
}
|
|
|
|
public override float Simulate(float timeStep)
|
|
{
|
|
float fps = 0;
|
|
lock (BulletXLock)
|
|
{
|
|
//Try to remove garbage
|
|
RemoveForgottenRigidBodies();
|
|
//End of remove
|
|
MoveAPrimitives(timeStep);
|
|
|
|
|
|
fps = (timeStep*simulationSubSteps);
|
|
|
|
ddWorld.StepSimulation(timeStep, simulationSubSteps, timeStep);
|
|
//Extra Heightmap Validation: BulletX's HeightFieldTerrain somestimes doesn't work so fine.
|
|
ValidateHeightForAll();
|
|
//End heightmap validation.
|
|
UpdateKineticsForAll();
|
|
}
|
|
return fps;
|
|
}
|
|
|
|
private void MoveAPrimitives(float timeStep)
|
|
{
|
|
foreach (BulletXCharacter actor in _characters.Values)
|
|
{
|
|
actor.Move(timeStep);
|
|
}
|
|
}
|
|
|
|
private void ValidateHeightForAll()
|
|
{
|
|
float _height;
|
|
foreach (BulletXCharacter actor in _characters.Values)
|
|
{
|
|
//_height = HeightValue(actor.RigidBodyPosition);
|
|
_height = _simFlatPlanet.HeightValue(actor.RigidBodyPosition);
|
|
actor.ValidateHeight(_height);
|
|
//if (_simFlatPlanet.heightIsNotValid(actor.RigidBodyPosition, out _height)) actor.ValidateHeight(_height);
|
|
}
|
|
foreach (BulletXPrim prim in _prims.Values)
|
|
{
|
|
//_height = HeightValue(prim.RigidBodyPosition);
|
|
_height = _simFlatPlanet.HeightValue(prim.RigidBodyPosition);
|
|
prim.ValidateHeight(_height);
|
|
//if (_simFlatPlanet.heightIsNotValid(prim.RigidBodyPosition, out _height)) prim.ValidateHeight(_height);
|
|
}
|
|
//foreach (BulletXCharacter actor in _characters)
|
|
//{
|
|
// actor.ValidateHeight(0);
|
|
//}
|
|
//foreach (BulletXPrim prim in _prims)
|
|
//{
|
|
// prim.ValidateHeight(0);
|
|
//}
|
|
}
|
|
|
|
private void UpdateKineticsForAll()
|
|
{
|
|
//UpdatePosition > UpdateKinetics.
|
|
//Not only position will be updated, also velocity cause acceleration.
|
|
foreach (BulletXCharacter actor in _characters.Values)
|
|
{
|
|
actor.UpdateKinetics();
|
|
}
|
|
foreach (BulletXPrim prim in _prims.Values)
|
|
{
|
|
prim.UpdateKinetics();
|
|
}
|
|
//if (this._simFlatPlanet!=null) this._simFlatPlanet.Restore();
|
|
}
|
|
|
|
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];
|
|
//}
|
|
|
|
//float[] swappedHeightMap = new float[65536];
|
|
////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;
|
|
// swappedHeightMap[i] = heightMap[x * 256 + y];
|
|
//}
|
|
DeleteTerrain();
|
|
//There is a BulletXLock inside the constructor of BulletXPlanet
|
|
//this._simFlatPlanet = new BulletXPlanet(this, swappedHeightMap);
|
|
_simFlatPlanet = new BulletXPlanet(this, heightMap);
|
|
//this._heightmap = heightMap;
|
|
}
|
|
|
|
public override void DeleteTerrain()
|
|
{
|
|
if (_simFlatPlanet != null)
|
|
{
|
|
lock (BulletXLock)
|
|
{
|
|
try
|
|
{
|
|
ddWorld.RemoveRigidBody(_simFlatPlanet.RigidBody);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXMessage(is_ex_message + ex.Message, true);
|
|
_simFlatPlanet.RigidBody.ActivationState = ActivationState.DisableSimulation;
|
|
AddForgottenRigidBody(_simFlatPlanet.RigidBody);
|
|
}
|
|
}
|
|
_simFlatPlanet = null;
|
|
GC.Collect();
|
|
BulletXMessage("Terrain erased!", false);
|
|
}
|
|
|
|
|
|
|
|
//this._heightmap = null;
|
|
}
|
|
|
|
|
|
|
|
internal void AddForgottenRigidBody(RigidBody forgottenRigidBody)
|
|
{
|
|
_forgottenRigidBodies.Add(forgottenRigidBody);
|
|
}
|
|
|
|
private void RemoveForgottenRigidBodies()
|
|
{
|
|
RigidBody forgottenRigidBody;
|
|
int nRigidBodies = _forgottenRigidBodies.Count;
|
|
for (int i = nRigidBodies - 1; i >= 0; i--)
|
|
{
|
|
forgottenRigidBody = _forgottenRigidBodies[i];
|
|
try
|
|
{
|
|
ddWorld.RemoveRigidBody(forgottenRigidBody);
|
|
_forgottenRigidBodies.Remove(forgottenRigidBody);
|
|
BulletXMessage("Forgotten Rigid Body Removed", false);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXMessage("Can't remove forgottenRigidBody!: " + ex.Message, false);
|
|
}
|
|
}
|
|
GC.Collect();
|
|
}
|
|
|
|
internal static void BulletXMessage(string message, bool isWarning)
|
|
{
|
|
PhysicsPluginManager.PhysicsPluginMessage("[Modified BulletX]:\t" + message, isWarning);
|
|
}
|
|
|
|
//temp
|
|
//private float HeightValue(MonoXnaCompactMaths.Vector3 position)
|
|
//{
|
|
// int li_x, li_y;
|
|
// float height;
|
|
// li_x = (int)Math.Round(position.X); if (li_x < 0) li_x = 0;
|
|
// li_y = (int)Math.Round(position.Y); if (li_y < 0) li_y = 0;
|
|
|
|
// height = this._heightmap[li_y * 256 + li_x];
|
|
// if (height < 0) height = 0;
|
|
// else if (height > maxZ) height = maxZ;
|
|
|
|
// return height;
|
|
//}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generic Physics Actor for BulletX inherit from PhysicActor
|
|
/// </summary>
|
|
public class BulletXActor : PhysicsActor
|
|
{
|
|
protected bool flying = false;
|
|
protected bool _physical = false;
|
|
protected OpenMetaverse.Vector3 _position;
|
|
protected OpenMetaverse.Vector3 _velocity;
|
|
protected OpenMetaverse.Vector3 _size;
|
|
protected OpenMetaverse.Vector3 _acceleration;
|
|
protected OpenMetaverse.Quaternion _orientation;
|
|
protected OpenMetaverse.Vector3 m_rotationalVelocity;
|
|
protected RigidBody rigidBody;
|
|
protected int m_PhysicsActorType;
|
|
private Boolean iscolliding = false;
|
|
internal string _name;
|
|
|
|
public BulletXActor(String name)
|
|
{
|
|
_name = name;
|
|
}
|
|
|
|
public override bool Stopped
|
|
{
|
|
get { return false; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Position
|
|
{
|
|
get { return _position; }
|
|
set
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_position = value;
|
|
Translate();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 RotationalVelocity
|
|
{
|
|
get { return m_rotationalVelocity; }
|
|
set { m_rotationalVelocity = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Velocity
|
|
{
|
|
get { return _velocity; }
|
|
set
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
//Static objects don' have linear velocity
|
|
if (_physical)
|
|
{
|
|
_velocity = value;
|
|
Speed();
|
|
}
|
|
else
|
|
{
|
|
_velocity = OpenMetaverse.Vector3.Zero;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
public override float CollisionScore
|
|
{
|
|
get { return 0f; }
|
|
set { }
|
|
}
|
|
public override OpenMetaverse.Vector3 Size
|
|
{
|
|
get { return _size; }
|
|
set
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_size = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Force
|
|
{
|
|
get { return OpenMetaverse.Vector3.Zero; }
|
|
set { return; }
|
|
}
|
|
|
|
public override int VehicleType
|
|
{
|
|
get { return 0; }
|
|
set { return; }
|
|
}
|
|
|
|
public override void VehicleFloatParam(int param, float value)
|
|
{
|
|
|
|
}
|
|
|
|
public override void VehicleVectorParam(int param, OpenMetaverse.Vector3 value)
|
|
{
|
|
|
|
}
|
|
|
|
public override void VehicleRotationParam(int param, OpenMetaverse.Quaternion rotation)
|
|
{
|
|
|
|
}
|
|
|
|
public override void VehicleFlags(int param, bool remove)
|
|
{
|
|
|
|
}
|
|
|
|
public override void SetVolumeDetect(int param)
|
|
{
|
|
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 CenterOfMass
|
|
{
|
|
get { return OpenMetaverse.Vector3.Zero; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 GeometricCenter
|
|
{
|
|
get { return OpenMetaverse.Vector3.Zero; }
|
|
}
|
|
|
|
public override PrimitiveBaseShape Shape
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override bool SetAlwaysRun
|
|
{
|
|
get { return false; }
|
|
set { return; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Acceleration
|
|
{
|
|
get { return _acceleration; }
|
|
}
|
|
|
|
public override OpenMetaverse.Quaternion Orientation
|
|
{
|
|
get { return _orientation; }
|
|
set
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_orientation = value;
|
|
ReOrient();
|
|
}
|
|
}
|
|
}
|
|
public override void link(PhysicsActor obj)
|
|
{
|
|
|
|
}
|
|
|
|
public override void delink()
|
|
{
|
|
|
|
}
|
|
|
|
public override void LockAngularMotion(OpenMetaverse.Vector3 axis)
|
|
{
|
|
|
|
}
|
|
|
|
public override float Mass
|
|
{
|
|
get { return ActorMass; }
|
|
}
|
|
|
|
public virtual float ActorMass
|
|
{
|
|
get { return 0; }
|
|
}
|
|
|
|
public override int PhysicsActorType
|
|
{
|
|
get { return (int) m_PhysicsActorType; }
|
|
set { m_PhysicsActorType = value; }
|
|
}
|
|
|
|
public RigidBody RigidBody
|
|
{
|
|
get { return rigidBody; }
|
|
}
|
|
|
|
public Vector3 RigidBodyPosition
|
|
{
|
|
get { return rigidBody.CenterOfMassPosition; }
|
|
}
|
|
|
|
public override bool IsPhysical
|
|
{
|
|
get { return _physical; }
|
|
set { _physical = value; }
|
|
}
|
|
|
|
public override bool Flying
|
|
{
|
|
get { return flying; }
|
|
set { flying = value; }
|
|
}
|
|
|
|
public override bool ThrottleUpdates
|
|
{
|
|
get { return false; }
|
|
set { return; }
|
|
}
|
|
|
|
public override bool IsColliding
|
|
{
|
|
get { return iscolliding; }
|
|
set { iscolliding = value; }
|
|
}
|
|
|
|
public override bool CollidingGround
|
|
{
|
|
get { return false; }
|
|
set { return; }
|
|
}
|
|
|
|
public override bool CollidingObj
|
|
{
|
|
get { return false; }
|
|
set { return; }
|
|
}
|
|
|
|
public override uint LocalID
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override bool Grabbed
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override bool Selected
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override float Buoyancy
|
|
{
|
|
get { return 0f; }
|
|
set { return; }
|
|
}
|
|
|
|
public override bool FloatOnWater
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public virtual void SetAcceleration(OpenMetaverse.Vector3 accel)
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_acceleration = accel;
|
|
}
|
|
}
|
|
|
|
public override bool Kinematic
|
|
{
|
|
get { return false; }
|
|
set { }
|
|
}
|
|
|
|
public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce)
|
|
{
|
|
}
|
|
public override OpenMetaverse.Vector3 Torque
|
|
{
|
|
get { return OpenMetaverse.Vector3.Zero; }
|
|
set { return; }
|
|
}
|
|
public override void AddAngularForce(OpenMetaverse.Vector3 force, bool pushforce)
|
|
{
|
|
}
|
|
|
|
public override void SetMomentum(OpenMetaverse.Vector3 momentum)
|
|
{
|
|
}
|
|
|
|
internal virtual void ValidateHeight(float heighmapPositionValue)
|
|
{
|
|
}
|
|
|
|
internal virtual void UpdateKinetics()
|
|
{
|
|
}
|
|
|
|
#region Methods for updating values of RigidBody
|
|
|
|
protected internal void Translate()
|
|
{
|
|
Translate(_position);
|
|
}
|
|
|
|
protected internal void Translate(OpenMetaverse.Vector3 _newPos)
|
|
{
|
|
Vector3 _translation;
|
|
_translation = BulletXMaths.PhysicsVectorToXnaVector3(_newPos) - rigidBody.CenterOfMassPosition;
|
|
rigidBody.Translate(_translation);
|
|
}
|
|
|
|
protected internal void Speed()
|
|
{
|
|
Speed(_velocity);
|
|
}
|
|
|
|
protected internal void Speed(OpenMetaverse.Vector3 _newSpeed)
|
|
{
|
|
Vector3 _speed;
|
|
_speed = BulletXMaths.PhysicsVectorToXnaVector3(_newSpeed);
|
|
rigidBody.LinearVelocity = _speed;
|
|
}
|
|
|
|
protected internal void ReOrient()
|
|
{
|
|
ReOrient(_orientation);
|
|
}
|
|
|
|
protected internal void ReOrient(OpenMetaverse.Quaternion _newOrient)
|
|
{
|
|
Quaternion _newOrientation;
|
|
_newOrientation = BulletXMaths.QuaternionToXnaQuaternion(_newOrient);
|
|
Matrix _comTransform = rigidBody.CenterOfMassTransform;
|
|
BulletXMaths.SetRotation(ref _comTransform, _newOrientation);
|
|
rigidBody.CenterOfMassTransform = _comTransform;
|
|
}
|
|
|
|
protected internal void ReSize()
|
|
{
|
|
ReSize(_size);
|
|
}
|
|
|
|
protected internal virtual void ReSize(OpenMetaverse.Vector3 _newSize)
|
|
{
|
|
}
|
|
|
|
public virtual void ScheduleTerseUpdate()
|
|
{
|
|
base.RequestPhysicsterseUpdate();
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override void CrossingFailure()
|
|
{
|
|
|
|
}
|
|
public override OpenMetaverse.Vector3 PIDTarget { set { return; } }
|
|
public override bool PIDActive { set { return; } }
|
|
public override float PIDTau { set { return; } }
|
|
|
|
public override float PIDHoverHeight { set { return; } }
|
|
public override bool PIDHoverActive { set { return; } }
|
|
public override PIDHoverType PIDHoverType { set { return; } }
|
|
public override float PIDHoverTau { set { return; } }
|
|
|
|
public override OpenMetaverse.Quaternion APIDTarget
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override bool APIDActive
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override float APIDStrength
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
public override float APIDDamping
|
|
{
|
|
set { return; }
|
|
}
|
|
|
|
|
|
public override void SubscribeEvents(int ms)
|
|
{
|
|
|
|
}
|
|
public override void UnSubscribeEvents()
|
|
{
|
|
|
|
}
|
|
public override bool SubscribedEvents()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// PhysicsActor Character Class for BulletX
|
|
/// </summary>
|
|
public class BulletXCharacter : BulletXActor
|
|
{
|
|
public BulletXCharacter(BulletXScene parent_scene, OpenMetaverse.Vector3 pos)
|
|
: this(String.Empty, parent_scene, pos)
|
|
{
|
|
}
|
|
|
|
public BulletXCharacter(String avName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos)
|
|
: this(avName, parent_scene, pos, OpenMetaverse.Vector3.Zero, OpenMetaverse.Vector3.Zero, OpenMetaverse.Vector3.Zero,
|
|
OpenMetaverse.Quaternion.Identity)
|
|
{
|
|
}
|
|
|
|
public BulletXCharacter(String avName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 velocity,
|
|
OpenMetaverse.Vector3 size, OpenMetaverse.Vector3 acceleration, OpenMetaverse.Quaternion orientation)
|
|
: base(avName)
|
|
{
|
|
//This fields will be removed. They're temporal
|
|
float _sizeX = 0.5f;
|
|
float _sizeY = 0.5f;
|
|
float _sizeZ = 1.6f;
|
|
//.
|
|
_position = pos;
|
|
_velocity = velocity;
|
|
_size = size;
|
|
//---
|
|
_size.X = _sizeX;
|
|
_size.Y = _sizeY;
|
|
_size.Z = _sizeZ;
|
|
//.
|
|
_acceleration = acceleration;
|
|
_orientation = orientation;
|
|
_physical = true;
|
|
|
|
float _mass = 50.0f; //This depends of avatar's dimensions
|
|
//For RigidBody Constructor. The next values might change
|
|
float _linearDamping = 0.0f;
|
|
float _angularDamping = 0.0f;
|
|
float _friction = 0.5f;
|
|
float _restitution = 0.0f;
|
|
Matrix _startTransform = Matrix.Identity;
|
|
Matrix _centerOfMassOffset = Matrix.Identity;
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos);
|
|
//CollisionShape _collisionShape = new BoxShape(new MonoXnaCompactMaths.Vector3(1.0f, 1.0f, 1.60f));
|
|
//For now, like ODE, collisionShape = sphere of radious = 1.0
|
|
CollisionShape _collisionShape = new SphereShape(1.0f);
|
|
DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset);
|
|
Vector3 _localInertia = new Vector3();
|
|
_collisionShape.CalculateLocalInertia(_mass, out _localInertia); //Always when mass > 0
|
|
rigidBody =
|
|
new RigidBody(_mass, _motionState, _collisionShape, _localInertia, _linearDamping, _angularDamping,
|
|
_friction, _restitution);
|
|
//rigidBody.ActivationState = ActivationState.DisableDeactivation;
|
|
//It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition
|
|
Vector3 _vDebugTranslation;
|
|
_vDebugTranslation = _startTransform.Translation - rigidBody.CenterOfMassPosition;
|
|
rigidBody.Translate(_vDebugTranslation);
|
|
parent_scene.ddWorld.AddRigidBody(rigidBody);
|
|
}
|
|
}
|
|
|
|
public override int PhysicsActorType
|
|
{
|
|
get { return (int) ActorTypes.Agent; }
|
|
set { return; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Position
|
|
{
|
|
get { return base.Position; }
|
|
set { base.Position = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Velocity
|
|
{
|
|
get { return base.Velocity; }
|
|
set { base.Velocity = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Size
|
|
{
|
|
get { return base.Size; }
|
|
set { base.Size = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Acceleration
|
|
{
|
|
get { return base.Acceleration; }
|
|
}
|
|
|
|
public override OpenMetaverse.Quaternion Orientation
|
|
{
|
|
get { return base.Orientation; }
|
|
set { base.Orientation = value; }
|
|
}
|
|
|
|
public override bool Flying
|
|
{
|
|
get { return base.Flying; }
|
|
set { base.Flying = value; }
|
|
}
|
|
|
|
public override bool IsColliding
|
|
{
|
|
get { return base.IsColliding; }
|
|
set { base.IsColliding = value; }
|
|
}
|
|
|
|
public override bool Kinematic
|
|
{
|
|
get { return base.Kinematic; }
|
|
set { base.Kinematic = value; }
|
|
}
|
|
|
|
public override void SetAcceleration(OpenMetaverse.Vector3 accel)
|
|
{
|
|
base.SetAcceleration(accel);
|
|
}
|
|
|
|
public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce)
|
|
{
|
|
base.AddForce(force, pushforce);
|
|
}
|
|
|
|
public override void SetMomentum(OpenMetaverse.Vector3 momentum)
|
|
{
|
|
base.SetMomentum(momentum);
|
|
}
|
|
|
|
internal void Move(float timeStep)
|
|
{
|
|
Vector3 vec = new Vector3();
|
|
//At this point it's supossed that:
|
|
//_velocity == rigidBody.LinearVelocity
|
|
vec.X = _velocity.X;
|
|
vec.Y = _velocity.Y;
|
|
vec.Z = _velocity.Z;
|
|
if ((vec.X != 0.0f) || (vec.Y != 0.0f) || (vec.Z != 0.0f)) rigidBody.Activate();
|
|
if (flying)
|
|
{
|
|
//Antigravity with movement
|
|
if (_position.Z <= BulletXScene.HeightLevel0)
|
|
{
|
|
vec.Z += BulletXScene.Gravity*timeStep;
|
|
}
|
|
//Lowgravity with movement
|
|
else if ((_position.Z > BulletXScene.HeightLevel0)
|
|
&& (_position.Z <= BulletXScene.HeightLevel1))
|
|
{
|
|
vec.Z += BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor);
|
|
}
|
|
//Lowgravity with...
|
|
else if (_position.Z > BulletXScene.HeightLevel1)
|
|
{
|
|
if (vec.Z > 0) //no movement
|
|
vec.Z = BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor);
|
|
else
|
|
vec.Z += BulletXScene.Gravity*timeStep*(1.0f - BulletXScene.LowGravityFactor);
|
|
}
|
|
}
|
|
rigidBody.LinearVelocity = vec;
|
|
}
|
|
|
|
//This validation is very basic
|
|
internal override void ValidateHeight(float heighmapPositionValue)
|
|
{
|
|
if (rigidBody.CenterOfMassPosition.Z < heighmapPositionValue + _size.Z/2.0f)
|
|
{
|
|
Matrix m = rigidBody.WorldTransform;
|
|
Vector3 v3 = m.Translation;
|
|
v3.Z = heighmapPositionValue + _size.Z/2.0f;
|
|
m.Translation = v3;
|
|
rigidBody.WorldTransform = m;
|
|
//When an Avie touch the ground it's vertical velocity it's reduced to ZERO
|
|
Speed(new OpenMetaverse.Vector3(rigidBody.LinearVelocity.X, rigidBody.LinearVelocity.Y, 0.0f));
|
|
}
|
|
}
|
|
|
|
internal override void UpdateKinetics()
|
|
{
|
|
_position = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.CenterOfMassPosition);
|
|
_velocity = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.LinearVelocity);
|
|
//Orientation it seems that it will be the default.
|
|
ReOrient();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// PhysicsActor Prim Class for BulletX
|
|
/// </summary>
|
|
public class BulletXPrim : BulletXActor
|
|
{
|
|
//Density it will depends of material.
|
|
//For now all prims have the same density, all prims are made of water. Be water my friend! :D
|
|
private const float _density = 1000.0f;
|
|
private BulletXScene _parent_scene;
|
|
private OpenMetaverse.Vector3 m_prev_position;
|
|
private bool m_lastUpdateSent = false;
|
|
//added by jed zhu
|
|
private IMesh _mesh;
|
|
public IMesh GetMesh() { return _mesh; }
|
|
|
|
|
|
|
|
public BulletXPrim(String primName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 size,
|
|
OpenMetaverse.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool isPhysical)
|
|
: this(
|
|
primName, parent_scene, pos, OpenMetaverse.Vector3.Zero, size, OpenMetaverse.Vector3.Zero, rotation, mesh, pbs,
|
|
isPhysical)
|
|
{
|
|
}
|
|
|
|
public BulletXPrim(String primName, BulletXScene parent_scene, OpenMetaverse.Vector3 pos, OpenMetaverse.Vector3 velocity,
|
|
OpenMetaverse.Vector3 size,
|
|
OpenMetaverse.Vector3 acceleration, OpenMetaverse.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs,
|
|
bool isPhysical)
|
|
: base(primName)
|
|
{
|
|
if ((size.X == 0) || (size.Y == 0) || (size.Z == 0))
|
|
throw new Exception("Size 0");
|
|
if (OpenMetaverse.Quaternion.Normalize(rotation).Length() == 0f)
|
|
rotation = OpenMetaverse.Quaternion.Identity;
|
|
|
|
_position = pos;
|
|
_physical = isPhysical;
|
|
_velocity = _physical ? velocity : OpenMetaverse.Vector3.Zero;
|
|
_size = size;
|
|
_acceleration = acceleration;
|
|
_orientation = rotation;
|
|
|
|
_parent_scene = parent_scene;
|
|
|
|
CreateRigidBody(parent_scene, mesh, pos, size);
|
|
}
|
|
|
|
public override int PhysicsActorType
|
|
{
|
|
get { return (int) ActorTypes.Prim; }
|
|
set { return; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Position
|
|
{
|
|
get { return base.Position; }
|
|
set { base.Position = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Velocity
|
|
{
|
|
get { return base.Velocity; }
|
|
set { base.Velocity = value; }
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Size
|
|
{
|
|
get { return _size; }
|
|
set
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_size = value;
|
|
ReSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
public override OpenMetaverse.Vector3 Acceleration
|
|
{
|
|
get { return base.Acceleration; }
|
|
}
|
|
|
|
public override OpenMetaverse.Quaternion Orientation
|
|
{
|
|
get { return base.Orientation; }
|
|
set { base.Orientation = value; }
|
|
}
|
|
|
|
public override float ActorMass
|
|
{
|
|
get
|
|
{
|
|
//For now all prims are boxes
|
|
return (_physical ? 1 : 0)*_density*_size.X*_size.Y*_size.Z;
|
|
}
|
|
}
|
|
|
|
public override bool IsPhysical
|
|
{
|
|
get { return base.IsPhysical; }
|
|
set
|
|
{
|
|
base.IsPhysical = value;
|
|
if (value)
|
|
{
|
|
//---
|
|
PhysicsPluginManager.PhysicsPluginMessage("Physical - Recreate", true);
|
|
//---
|
|
ReCreateRigidBody(_size);
|
|
}
|
|
else
|
|
{
|
|
//---
|
|
PhysicsPluginManager.PhysicsPluginMessage("Physical - SetMassProps", true);
|
|
//---
|
|
rigidBody.SetMassProps(Mass, new Vector3());
|
|
}
|
|
}
|
|
}
|
|
|
|
public override bool Flying
|
|
{
|
|
get { return base.Flying; }
|
|
set { base.Flying = value; }
|
|
}
|
|
|
|
public override bool IsColliding
|
|
{
|
|
get { return base.IsColliding; }
|
|
set { base.IsColliding = value; }
|
|
}
|
|
|
|
public override bool Kinematic
|
|
{
|
|
get { return base.Kinematic; }
|
|
set { base.Kinematic = value; }
|
|
}
|
|
|
|
public override void SetAcceleration(OpenMetaverse.Vector3 accel)
|
|
{
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_acceleration = accel;
|
|
}
|
|
}
|
|
|
|
public override void AddForce(OpenMetaverse.Vector3 force, bool pushforce)
|
|
{
|
|
base.AddForce(force,pushforce);
|
|
}
|
|
|
|
public override void SetMomentum(OpenMetaverse.Vector3 momentum)
|
|
{
|
|
base.SetMomentum(momentum);
|
|
}
|
|
|
|
internal override void ValidateHeight(float heighmapPositionValue)
|
|
{
|
|
if (rigidBody.CenterOfMassPosition.Z < heighmapPositionValue + _size.Z/2.0f)
|
|
{
|
|
Matrix m = rigidBody.WorldTransform;
|
|
Vector3 v3 = m.Translation;
|
|
v3.Z = heighmapPositionValue + _size.Z/2.0f;
|
|
m.Translation = v3;
|
|
rigidBody.WorldTransform = m;
|
|
//When a Prim touch the ground it's vertical velocity it's reduced to ZERO
|
|
//Static objects don't have linear velocity
|
|
if (_physical)
|
|
Speed(new OpenMetaverse.Vector3(rigidBody.LinearVelocity.X, rigidBody.LinearVelocity.Y, 0.0f));
|
|
}
|
|
}
|
|
|
|
internal override void UpdateKinetics()
|
|
{
|
|
if (_physical) //Updates properties. Prim updates its properties physically
|
|
{
|
|
_position = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.CenterOfMassPosition);
|
|
|
|
_velocity = BulletXMaths.XnaVector3ToPhysicsVector(rigidBody.LinearVelocity);
|
|
_orientation = BulletXMaths.XnaQuaternionToQuaternion(rigidBody.Orientation);
|
|
|
|
if ((Math.Abs(m_prev_position.X - _position.X) < 0.03)
|
|
&& (Math.Abs(m_prev_position.Y - _position.Y) < 0.03)
|
|
&& (Math.Abs(m_prev_position.Z - _position.Z) < 0.03))
|
|
{
|
|
if (!m_lastUpdateSent)
|
|
{
|
|
_velocity = OpenMetaverse.Vector3.Zero;
|
|
base.ScheduleTerseUpdate();
|
|
m_lastUpdateSent = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_lastUpdateSent = false;
|
|
base.ScheduleTerseUpdate();
|
|
}
|
|
m_prev_position = _position;
|
|
}
|
|
else //Doesn't updates properties. That's a cancel
|
|
{
|
|
Translate();
|
|
//Speed(); //<- Static objects don't have linear velocity
|
|
ReOrient();
|
|
}
|
|
}
|
|
|
|
#region Methods for updating values of RigidBody
|
|
|
|
protected internal void CreateRigidBody(BulletXScene parent_scene, IMesh mesh, OpenMetaverse.Vector3 pos,
|
|
OpenMetaverse.Vector3 size)
|
|
{
|
|
//For RigidBody Constructor. The next values might change
|
|
float _linearDamping = 0.0f;
|
|
float _angularDamping = 0.0f;
|
|
float _friction = 1.0f;
|
|
float _restitution = 0.0f;
|
|
Matrix _startTransform = Matrix.Identity;
|
|
Matrix _centerOfMassOffset = Matrix.Identity;
|
|
//added by jed zhu
|
|
_mesh = mesh;
|
|
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
_startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(pos);
|
|
//For now all prims are boxes
|
|
CollisionShape _collisionShape;
|
|
if (mesh == null)
|
|
{
|
|
_collisionShape = new BoxShape(BulletXMaths.PhysicsVectorToXnaVector3(size)/2.0f);
|
|
}
|
|
else
|
|
{
|
|
int iVertexCount = mesh.getVertexList().Count;
|
|
int[] indices = mesh.getIndexListAsInt();
|
|
Vector3[] v3Vertices = new Vector3[iVertexCount];
|
|
for (int i = 0; i < iVertexCount; i++)
|
|
{
|
|
OpenMetaverse.Vector3 v = mesh.getVertexList()[i];
|
|
if (v != null) // Note, null has special meaning. See meshing code for details
|
|
v3Vertices[i] = BulletXMaths.PhysicsVectorToXnaVector3(v);
|
|
else
|
|
v3Vertices[i] = Vector3.Zero;
|
|
}
|
|
TriangleIndexVertexArray triMesh = new TriangleIndexVertexArray(indices, v3Vertices);
|
|
|
|
_collisionShape = new TriangleMeshShape(triMesh);
|
|
}
|
|
DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset);
|
|
Vector3 _localInertia = new Vector3();
|
|
if (_physical) _collisionShape.CalculateLocalInertia(Mass, out _localInertia); //Always when mass > 0
|
|
rigidBody =
|
|
new RigidBody(Mass, _motionState, _collisionShape, _localInertia, _linearDamping, _angularDamping,
|
|
_friction, _restitution);
|
|
//rigidBody.ActivationState = ActivationState.DisableDeactivation;
|
|
//It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition
|
|
Vector3 _vDebugTranslation;
|
|
_vDebugTranslation = _startTransform.Translation - rigidBody.CenterOfMassPosition;
|
|
rigidBody.Translate(_vDebugTranslation);
|
|
//---
|
|
parent_scene.ddWorld.AddRigidBody(rigidBody);
|
|
}
|
|
}
|
|
|
|
protected internal void ReCreateRigidBody(OpenMetaverse.Vector3 size)
|
|
{
|
|
//There is a bug when trying to remove a rigidBody that is colliding with something..
|
|
try
|
|
{
|
|
_parent_scene.ddWorld.RemoveRigidBody(rigidBody);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXScene.BulletXMessage(_parent_scene.is_ex_message + ex.Message, true);
|
|
rigidBody.ActivationState = ActivationState.DisableSimulation;
|
|
_parent_scene.AddForgottenRigidBody(rigidBody);
|
|
}
|
|
CreateRigidBody(_parent_scene, null, _position, size);
|
|
// Note, null for the meshing definitely is wrong. It's here for the moment to apease the compiler
|
|
if (_physical) Speed(); //Static objects don't have linear velocity
|
|
ReOrient();
|
|
GC.Collect();
|
|
}
|
|
|
|
protected internal override void ReSize(OpenMetaverse.Vector3 _newSize)
|
|
{
|
|
//I wonder to know how to resize with a simple instruction in BulletX. It seems that for now there isn't
|
|
//so i have to do it manually. That's recreating rigidbody
|
|
ReCreateRigidBody(_newSize);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// This Class manage a HeighField as a RigidBody. This is for to be added in the BulletXScene
|
|
/// </summary>
|
|
internal class BulletXPlanet
|
|
{
|
|
private OpenMetaverse.Vector3 _staticPosition;
|
|
// private Vector3 _staticVelocity;
|
|
// private OpenMetaverse.Quaternion _staticOrientation;
|
|
private float _mass;
|
|
// private BulletXScene _parentscene;
|
|
internal float[] _heightField;
|
|
private RigidBody _flatPlanet;
|
|
|
|
internal RigidBody RigidBody
|
|
{
|
|
get { return _flatPlanet; }
|
|
}
|
|
|
|
internal BulletXPlanet(BulletXScene parent_scene, float[] heightField)
|
|
{
|
|
_staticPosition = new OpenMetaverse.Vector3(BulletXScene.MaxXY / 2, BulletXScene.MaxXY / 2, 0);
|
|
// _staticVelocity = new PhysicsVector();
|
|
// _staticOrientation = OpenMetaverse.Quaternion.Identity;
|
|
_mass = 0; //No active
|
|
// _parentscene = parent_scene;
|
|
_heightField = heightField;
|
|
|
|
float _linearDamping = 0.0f;
|
|
float _angularDamping = 0.0f;
|
|
float _friction = 0.5f;
|
|
float _restitution = 0.0f;
|
|
Matrix _startTransform = Matrix.Identity;
|
|
Matrix _centerOfMassOffset = Matrix.Identity;
|
|
|
|
lock (BulletXScene.BulletXLock)
|
|
{
|
|
try
|
|
{
|
|
_startTransform.Translation = BulletXMaths.PhysicsVectorToXnaVector3(_staticPosition);
|
|
CollisionShape _collisionShape =
|
|
new HeightfieldTerrainShape(BulletXScene.MaxXY, BulletXScene.MaxXY, _heightField,
|
|
(float) BulletXScene.MaxZ, 2, true, false);
|
|
DefaultMotionState _motionState = new DefaultMotionState(_startTransform, _centerOfMassOffset);
|
|
Vector3 _localInertia = new Vector3();
|
|
//_collisionShape.CalculateLocalInertia(_mass, out _localInertia); //Always when mass > 0
|
|
_flatPlanet =
|
|
new RigidBody(_mass, _motionState, _collisionShape, _localInertia, _linearDamping,
|
|
_angularDamping, _friction, _restitution);
|
|
//It's seems that there are a bug with rigidBody constructor and its CenterOfMassPosition
|
|
Vector3 _vDebugTranslation;
|
|
_vDebugTranslation = _startTransform.Translation - _flatPlanet.CenterOfMassPosition;
|
|
_flatPlanet.Translate(_vDebugTranslation);
|
|
parent_scene.ddWorld.AddRigidBody(_flatPlanet);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
BulletXScene.BulletXMessage(ex.Message, true);
|
|
}
|
|
}
|
|
BulletXScene.BulletXMessage("BulletXPlanet created.", false);
|
|
}
|
|
|
|
internal float HeightValue(Vector3 position)
|
|
{
|
|
int li_x, li_y;
|
|
float height;
|
|
li_x = (int) Math.Round(position.X);
|
|
if (li_x < 0) li_x = 0;
|
|
if (li_x >= BulletXScene.MaxXY) li_x = BulletXScene.MaxXY - 1;
|
|
li_y = (int) Math.Round(position.Y);
|
|
if (li_y < 0) li_y = 0;
|
|
if (li_y >= BulletXScene.MaxXY) li_y = BulletXScene.MaxXY - 1;
|
|
|
|
height = ((HeightfieldTerrainShape) _flatPlanet.CollisionShape).getHeightFieldValue(li_x, li_y);
|
|
if (height < 0) height = 0;
|
|
else if (height > BulletXScene.MaxZ) height = BulletXScene.MaxZ;
|
|
|
|
return height;
|
|
}
|
|
}
|
|
}
|