BulletSim: unify physical objects under BSPhysObjects. Now BSScene and BSLinkset only know of BSPhysObject's and there is only one list to search in BSScene.

integration
Robert Adams 2012-08-24 12:58:42 -07:00
parent 0376b8ddbc
commit 7b6987ce83
5 changed files with 200 additions and 160 deletions

View File

@ -34,7 +34,7 @@ using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSCharacter : PhysicsActor
public class BSCharacter : BSPhysObject
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS CHAR]";
@ -74,11 +74,8 @@ public class BSCharacter : PhysicsActor
private bool _kinematic;
private float _buoyancy;
private BulletBody m_body;
public BulletBody Body {
get { return m_body; }
set { m_body = value; }
}
public override BulletBody Body { get; set; }
public override BSLinkset Linkset { get; set; }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
@ -108,6 +105,8 @@ public class BSCharacter : PhysicsActor
_density = _scene.Params.avatarDensity;
ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
Linkset = new BSLinkset(_scene, this);
ShapeData shapeData = new ShapeData();
shapeData.ID = _localID;
shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
@ -130,7 +129,7 @@ public class BSCharacter : PhysicsActor
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
// avatars get all collisions no matter what (makes walking on ground and such work)
BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
});
@ -139,7 +138,7 @@ public class BSCharacter : PhysicsActor
}
// called when this character is being destroyed and the resources should be released
public void Destroy()
public override void Destroy()
{
DetailLog("{0},BSCharacter.Destroy", LocalID);
_scene.TaintedObject("BSCharacter.destroy", delegate()
@ -245,6 +244,10 @@ public class BSCharacter : PhysicsActor
return _mass;
}
}
// used when we only want this prim's mass and not the linkset thing
public override float MassRaw { get {return _mass; } }
public override Vector3 Force {
get { return _force; }
set {
@ -448,6 +451,12 @@ public class BSCharacter : PhysicsActor
});
}
}
public override void ZeroMotion()
{
return;
}
// Stop collision events
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
@ -481,7 +490,7 @@ public class BSCharacter : PhysicsActor
// The physics engine says that properties have updated. Update same and inform
// the world that things have changed.
public void UpdateProperties(EntityProperties entprop)
public override void UpdateProperties(EntityProperties entprop)
{
_position = entprop.Position;
_orientation = entprop.Rotation;
@ -500,7 +509,7 @@ public class BSCharacter : PhysicsActor
// The collision, if it should be reported to the character, is placed in a collection
// that will later be sent to the simulator when SendCollisions() is called.
CollisionEventUpdate collisionCollection = null;
public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
public override void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
{
// m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
@ -525,7 +534,7 @@ public class BSCharacter : PhysicsActor
}
}
public void SendCollisions()
public override void SendCollisions()
{
/*
if (collisionCollection != null && collisionCollection.Count > 0)

View File

@ -36,8 +36,8 @@ public class BSLinkset
{
private static string LogHeader = "[BULLETSIM LINKSET]";
private BSPrim m_linksetRoot;
public BSPrim LinksetRoot { get { return m_linksetRoot; } }
private BSPhysObject m_linksetRoot;
public BSPhysObject LinksetRoot { get { return m_linksetRoot; } }
private BSScene m_physicsScene;
public BSScene PhysicsScene { get { return m_physicsScene; } }
@ -46,7 +46,7 @@ public class BSLinkset
public int LinksetID { get; private set; }
// The children under the root in this linkset
private List<BSPrim> m_children;
private List<BSPhysObject> m_children;
// We lock the diddling of linkset classes to prevent any badness.
// This locks the modification of the instances of this class. Changes
@ -74,7 +74,7 @@ public class BSLinkset
get { return ComputeLinksetGeometricCenter(); }
}
public BSLinkset(BSScene scene, BSPrim parent)
public BSLinkset(BSScene scene, BSPhysObject parent)
{
// A simple linkset of one (no children)
LinksetID = m_nextLinksetID++;
@ -83,14 +83,14 @@ public class BSLinkset
m_nextLinksetID = 1;
m_physicsScene = scene;
m_linksetRoot = parent;
m_children = new List<BSPrim>();
m_children = new List<BSPhysObject>();
m_mass = parent.MassRaw;
}
// Link to a linkset where the child knows the parent.
// Parent changing should not happen so do some sanity checking.
// We return the parent's linkset so the child can track its membership.
public BSLinkset AddMeToLinkset(BSPrim child)
public BSLinkset AddMeToLinkset(BSPhysObject child)
{
lock (m_linksetActivityLock)
{
@ -102,7 +102,7 @@ public class BSLinkset
// Remove a child from a linkset.
// Returns a new linkset for the child which is a linkset of one (just the
// orphened child).
public BSLinkset RemoveMeFromLinkset(BSPrim child)
public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
{
lock (m_linksetActivityLock)
{
@ -129,7 +129,7 @@ public class BSLinkset
}
// Return 'true' if the passed object is the root object of this linkset
public bool IsRoot(BSPrim requestor)
public bool IsRoot(BSPhysObject requestor)
{
return (requestor.LocalID == m_linksetRoot.LocalID);
}
@ -140,12 +140,12 @@ public class BSLinkset
public bool HasAnyChildren { get { return (m_children.Count > 0); } }
// Return 'true' if this child is in this linkset
public bool HasChild(BSPrim child)
public bool HasChild(BSPhysObject child)
{
bool ret = false;
lock (m_linksetActivityLock)
{
foreach (BSPrim bp in m_children)
foreach (BSPhysObject bp in m_children)
{
if (child.LocalID == bp.LocalID)
{
@ -160,7 +160,7 @@ public class BSLinkset
private float ComputeLinksetMass()
{
float mass = m_linksetRoot.MassRaw;
foreach (BSPrim bp in m_children)
foreach (BSPhysObject bp in m_children)
{
mass += bp.MassRaw;
}
@ -174,7 +174,7 @@ public class BSLinkset
lock (m_linksetActivityLock)
{
foreach (BSPrim bp in m_children)
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
totalMass += bp.MassRaw;
@ -192,7 +192,7 @@ public class BSLinkset
lock (m_linksetActivityLock)
{
foreach (BSPrim bp in m_children)
foreach (BSPhysObject bp in m_children)
{
com += bp.Position * bp.MassRaw;
}
@ -204,7 +204,7 @@ public class BSLinkset
// When physical properties are changed the linkset needs to recalculate
// its internal properties.
public void Refresh(BSPrim requestor)
public void Refresh(BSPhysObject requestor)
{
// If there are no children, there aren't any constraints to recompute
if (!HasAnyChildren)
@ -230,7 +230,7 @@ public class BSLinkset
float linksetMass = LinksetMass;
lock (m_linksetActivityLock)
{
foreach (BSPrim child in m_children)
foreach (BSPhysObject child in m_children)
{
BSConstraint constrain;
if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain))
@ -255,14 +255,14 @@ public class BSLinkset
// I am the root of a linkset and a new child is being added
// Called while LinkActivity is locked.
private void AddChildToLinkset(BSPrim child)
private void AddChildToLinkset(BSPhysObject child)
{
if (!HasChild(child))
{
m_children.Add(child);
BSPrim rootx = LinksetRoot; // capture the root as of now
BSPrim childx = child;
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
m_physicsScene.TaintedObject("AddChildToLinkset", delegate()
{
DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
@ -277,7 +277,7 @@ public class BSLinkset
// it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information
// has to be updated also (like pointer to prim's parent).
private void RemoveChildFromOtherLinkset(BSPrim pchild)
private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{
pchild.Linkset = new BSLinkset(m_physicsScene, pchild);
RemoveChildFromLinkset(pchild);
@ -285,12 +285,12 @@ public class BSLinkset
// I am the root of a linkset and one of my children is being removed.
// Safe to call even if the child is not really in my linkset.
private void RemoveChildFromLinkset(BSPrim child)
private void RemoveChildFromLinkset(BSPhysObject child)
{
if (m_children.Remove(child))
{
BSPrim rootx = LinksetRoot; // capture the root as of now
BSPrim childx = child;
BSPhysObject rootx = LinksetRoot; // capture the root as of now
BSPhysObject childx = child;
m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
@ -310,7 +310,7 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim)
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
// Zero motion for children so they don't interpolate
childPrim.ZeroMotion();
@ -383,7 +383,7 @@ public class BSLinkset
// Remove linkage between myself and a particular child
// Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim)
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
{
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
@ -396,7 +396,7 @@ public class BSLinkset
// Remove linkage between myself and any possible children I might have
// Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim)
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{
DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);

View File

@ -0,0 +1,58 @@
/*
* 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 copyrightD
* 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.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OMV = OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.Physics.BulletSPlugin
{
// Class to wrap all objects.
// The rest of BulletSim doesn't need to keep checking for avatars or prims
// unless the difference is significant.
public abstract class BSPhysObject : PhysicsActor
{
public abstract BSLinkset Linkset { get; set; }
public abstract void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type,
OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
public abstract void SendCollisions();
// Return the object mass without calculating it or side effects
public abstract float MassRaw { get; }
public abstract BulletBody Body { get; set; }
public abstract void ZeroMotion();
public abstract void UpdateProperties(EntityProperties entprop);
public abstract void Destroy();
}
}

View File

@ -37,7 +37,7 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
namespace OpenSim.Region.Physics.BulletSPlugin
{
[Serializable]
public sealed class BSPrim : PhysicsActor
public sealed class BSPrim : BSPhysObject
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS PRIM]";
@ -88,23 +88,14 @@ public sealed class BSPrim : PhysicsActor
private float _buoyancy;
// Membership in a linkset is controlled by this class.
private BSLinkset _linkset;
public BSLinkset Linkset
{
get { return _linkset; }
set { _linkset = value; }
}
public override BSLinkset Linkset { get; set; }
private int _subscribedEventsMs = 0;
private int _nextCollisionOkTime = 0;
long _collidingStep;
long _collidingGroundStep;
private BulletBody m_body;
public BulletBody Body {
get { return m_body; }
set { m_body = value; }
}
public override BulletBody Body { get; set; }
private BSDynamics _vehicle;
@ -139,7 +130,7 @@ public sealed class BSPrim : PhysicsActor
_friction = _scene.Params.defaultFriction; // TODO: compute based on object material
_density = _scene.Params.defaultDensity; // TODO: compute based on object material
_restitution = _scene.Params.defaultRestitution;
_linkset = new BSLinkset(Scene, this); // a linkset of one
Linkset = new BSLinkset(Scene, this); // a linkset of one
_vehicle = new BSDynamics(Scene, this); // add vehicleness
_mass = CalculateMass();
// do the actual object creation at taint time
@ -151,23 +142,23 @@ public sealed class BSPrim : PhysicsActor
// Get the pointer to the physical body for this object.
// At the moment, we're still letting BulletSim manage the creation and destruction
// of the object. Someday we'll move that into the C# code.
m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
});
}
// called when this prim is being destroyed and we should free all the resources
public void Destroy()
public override void Destroy()
{
// m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
// Undo any links between me and any other object
BSPrim parentBefore = _linkset.LinksetRoot;
int childrenBefore = _linkset.NumberOfChildren;
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
_linkset = _linkset.RemoveMeFromLinkset(this);
Linkset = Linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
// Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE;
@ -230,13 +221,13 @@ public sealed class BSPrim : PhysicsActor
BSPrim parent = obj as BSPrim;
if (parent != null)
{
BSPrim parentBefore = _linkset.LinksetRoot;
int childrenBefore = _linkset.NumberOfChildren;
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
_linkset = parent.Linkset.AddMeToLinkset(this);
Linkset = parent.Linkset.AddMeToLinkset(this);
DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
}
return;
}
@ -246,13 +237,13 @@ public sealed class BSPrim : PhysicsActor
// TODO: decide if this parent checking needs to happen at taint time
// Race condition here: if link() and delink() in same simulation tick, the delink will not happen
BSPrim parentBefore = _linkset.LinksetRoot;
int childrenBefore = _linkset.NumberOfChildren;
BSPhysObject parentBefore = Linkset.LinksetRoot;
int childrenBefore = Linkset.NumberOfChildren;
_linkset = _linkset.RemoveMeFromLinkset(this);
Linkset = Linkset.RemoveMeFromLinkset(this);
DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren);
LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
return;
}
@ -260,7 +251,7 @@ public sealed class BSPrim : PhysicsActor
// Do it to the properties so the values get set in the physics engine.
// Push the setting of the values to the viewer.
// Called at taint time!
public void ZeroMotion()
public override void ZeroMotion()
{
_velocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero;
@ -281,7 +272,7 @@ public sealed class BSPrim : PhysicsActor
public override OMV.Vector3 Position {
get {
if (!_linkset.IsRoot(this))
if (!Linkset.IsRoot(this))
// child prims move around based on their parent. Need to get the latest location
_position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
@ -306,23 +297,23 @@ public sealed class BSPrim : PhysicsActor
{
get
{
return _linkset.LinksetMass;
return Linkset.LinksetMass;
}
}
// used when we only want this prim's mass and not the linkset thing
public float MassRaw { get { return _mass; } }
public override float MassRaw { get { return _mass; } }
// Is this used?
public override OMV.Vector3 CenterOfMass
{
get { return _linkset.CenterOfMass; }
get { return Linkset.CenterOfMass; }
}
// Is this used?
public override OMV.Vector3 GeometricCenter
{
get { return _linkset.GeometricCenter; }
get { return Linkset.GeometricCenter; }
}
public override OMV.Vector3 Force {
@ -431,7 +422,7 @@ public sealed class BSPrim : PhysicsActor
}
public override OMV.Quaternion Orientation {
get {
if (!_linkset.IsRoot(this))
if (!Linkset.IsRoot(this))
{
// Children move around because tied to parent. Get a fresh value.
_orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
@ -490,7 +481,7 @@ public sealed class BSPrim : PhysicsActor
BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
// recompute any linkset parameters
_linkset.Refresh(this);
Linkset.Refresh(this);
CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr);
DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf);
@ -1299,7 +1290,7 @@ public sealed class BSPrim : PhysicsActor
const float ACCELERATION_TOLERANCE = 0.01f;
const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
public void UpdateProperties(EntityProperties entprop)
public override void UpdateProperties(EntityProperties entprop)
{
/*
UpdatedProperties changed = 0;
@ -1347,7 +1338,7 @@ public sealed class BSPrim : PhysicsActor
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
// Updates only for individual prims and for the root object of a linkset.
if (_linkset.IsRoot(this))
if (Linkset.IsRoot(this))
{
// Assign to the local variables so the normal set action does not happen
_position = entprop.Position;
@ -1375,7 +1366,7 @@ public sealed class BSPrim : PhysicsActor
// I've collided with something
// Called at taint time from within the Step() function
CollisionEventUpdate collisionCollection;
public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
public override void Collide(uint collidingWith, BSPhysObject collidee, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
{
// m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
@ -1387,18 +1378,15 @@ public sealed class BSPrim : PhysicsActor
}
// DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
BSPrim collidingWithPrim;
if (_scene.Prims.TryGetValue(collidingWith, out collidingWithPrim))
// prims in the same linkset cannot collide with each other
if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
{
// prims in the same linkset cannot collide with each other
if (this.Linkset.LinksetID == collidingWithPrim.Linkset.LinksetID)
{
return;
}
return;
}
// if someone is subscribed to collision events....
if (_subscribedEventsMs != 0) {
// if someone has subscribed for collision events....
if (SubscribedEvents()) {
// throttle the collisions to the number of milliseconds specified in the subscription
int nowTime = _scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) {
@ -1412,7 +1400,7 @@ public sealed class BSPrim : PhysicsActor
}
// The scene is telling us it's time to pass our collected collisions into the simulator
public void SendCollisions()
public override void SendCollisions()
{
if (collisionCollection != null && collisionCollection.Count > 0)
{

View File

@ -78,14 +78,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public string BulletSimVersion = "?";
private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
public Dictionary<uint, BSCharacter> Characters { get { return m_avatars; } }
private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
public Dictionary<uint, BSPrim> Prims { get { return m_prims; } }
public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>();
private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>();
// Following is a kludge and can be removed when avatar animation updating is
// moved to a better place.
private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
private List<BSPrim> m_vehicles = new List<BSPrim>();
@ -235,7 +233,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// BulletSimVersion = BulletSimAPI.GetVersion();
// m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
// if Debug, enable logging from the unmanaged code
// If Debug logging level, enable logging from the unmanaged code
if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
@ -243,13 +241,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
else
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
// the handle is saved in a variable to make sure it doesn't get freed after this call
// The handle is saved in a variable to make sure it doesn't get freed after this call
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
}
_taintedObjects = new List<TaintCallbackEntry>();
mesher = meshmerizer;
// The bounding box for the simulated world
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
@ -337,7 +336,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
if (!m_initialized) return null;
BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
lock (m_avatars) m_avatars.Add(localID, actor);
lock (PhysObjects) PhysObjects.Add(localID, actor);
// Remove kludge someday
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
return actor;
}
@ -352,7 +355,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
{
try
{
lock (m_avatars) m_avatars.Remove(actor.LocalID);
lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
// Remove kludge someday
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor);
}
catch (Exception e)
{
@ -374,7 +379,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
try
{
lock (m_prims) m_prims.Remove(bsprim.LocalID);
lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
}
catch (Exception e)
{
@ -399,7 +404,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
DetailLog("{0},AddPrimShape,call", localID);
BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
lock (m_prims) m_prims.Add(localID, prim);
lock (PhysObjects) PhysObjects.Add(localID, prim);
return prim;
}
@ -470,19 +475,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The above SendCollision's batch up the collisions on the objects.
// Now push the collisions into the simulator.
foreach (BSPrim bsp in m_primsWithCollisions)
foreach (BSPhysObject bsp in m_objectsWithCollisions)
bsp.SendCollisions();
m_primsWithCollisions.Clear();
m_objectsWithCollisions.Clear();
// This is a kludge to get avatar movement updated.
// Don't send collisions only if there were collisions -- send everytime.
// ODE sends collisions even if there are none and this is used to update
// avatar animations and stuff.
// foreach (BSCharacter bsc in m_avatarsWithCollisions)
// bsc.SendCollisions();
foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
kvp.Value.SendCollisions();
m_avatarsWithCollisions.Clear();
foreach (BSPhysObject bpo in m_avatarsWithCollisions)
bpo.SendCollisions();
// m_avatarsWithCollisions.Clear();
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0)
@ -490,16 +492,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
for (int ii = 0; ii < updatedEntityCount; ii++)
{
EntityProperties entprop = m_updateArray[ii];
BSPrim prim;
if (m_prims.TryGetValue(entprop.ID, out prim))
BSPhysObject pobj;
if (PhysObjects.TryGetValue(entprop.ID, out pobj))
{
prim.UpdateProperties(entprop);
continue;
}
BSCharacter actor;
if (m_avatars.TryGetValue(entprop.ID, out actor))
{
actor.UpdateProperties(entprop);
pobj.UpdateProperties(entprop);
continue;
}
}
@ -529,33 +525,36 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// Something has collided
private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration)
private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
{
if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID)
{
return; // don't send collisions to the terrain
}
BSPhysObject collider = PhysObjects[localID];
// TODO: as of this code, terrain was not in the physical object list.
// When BSTerrain is created and it will be in the list, we can remove
// the possibility that it's not there and just fetch the collidee.
BSPhysObject collidee = null;
ActorTypes type = ActorTypes.Prim;
if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID)
{
type = ActorTypes.Ground;
else if (m_avatars.ContainsKey(collidingWith))
type = ActorTypes.Agent;
}
else
{
collidee = PhysObjects[collidingWith];
if (collidee is BSCharacter)
type = ActorTypes.Agent;
}
// DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
BSPrim prim;
if (m_prims.TryGetValue(localID, out prim)) {
prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
m_primsWithCollisions.Add(prim);
return;
}
BSCharacter actor;
if (m_avatars.TryGetValue(localID, out actor)) {
actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
m_avatarsWithCollisions.Add(actor);
return;
}
collider.Collide(collidingWith, collidee, type, collidePoint, collideNormal, penetration);
m_objectsWithCollisions.Add(collider);
return;
}
@ -605,17 +604,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// make sure no stepping happens while we're deleting stuff
m_initialized = false;
foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
{
kvp.Value.Destroy();
}
m_avatars.Clear();
foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
{
kvp.Value.Destroy();
}
m_prims.Clear();
PhysObjects.Clear();
// Now that the prims are all cleaned up, there should be no constraints left
if (m_constraintCollection != null)
@ -996,42 +989,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters
0f,
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearDamping; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ),
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularDamping; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ),
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
0.2f,
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].deactivationTime; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ),
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
0.8f,
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1.0f,
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
0f, // set to zero to disable
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdMotionThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
0f,
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
0.1f,
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].contactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.5f,
@ -1052,32 +1045,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
0.5f,
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
60f,
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarDensity; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
0f,
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarRestitution; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
0.37f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleRadius; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1.5f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleHeight; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
0.1f,
(s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
@ -1264,18 +1257,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// check to see if we are updating a parameter for a particular or all of the prims
protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
{
List<uint> operateOn;
lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
}
// check to see if we are updating a parameter for a particular or all of the avatars
protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
{
List<uint> operateOn;
lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
}