Compare commits

...

21 Commits

Author SHA1 Message Date
BlueWall
5eb2526e88 0006270: Warp3D leaks memory on mono based systems
Thanks Hiro Lecker for a patch to reduce memory useage with Warp3D map module
2012-09-06 05:18:08 -04:00
Mic Bowman
641b08aa78 Enables cast from int to float for MOD* functions;
Thanks SignpostMarv!
2012-09-05 09:13:16 -07:00
Justin Clark-Casey (justincc)
15d5f3d09d Bump master code up to 0.7.5 now that 0.7.4 is out. 2012-09-04 00:11:14 +01:00
SignpostMarv
07dbe46ba3 wrapping attachment functions in a region 2012-09-04 00:03:44 +01:00
SignpostMarv
ff867b59cf Implementing functing to send messages directly to attachments 2012-09-04 00:03:44 +01:00
SignpostMarv
d4b8a13a1d refactoring the grunt work of MessageObject into a private method with a UUID argument 2012-09-04 00:03:44 +01:00
SignpostMarv
a858c5daee implementing a function to get the number of attachments worn 2012-09-04 00:03:43 +01:00
SignpostMarv
8d431c6359 formatting 2012-09-04 00:03:43 +01:00
SignpostMarv
663bfbb372 although the attachmentPoint argument is a uint, zero is not a valid attachment point 2012-09-04 00:03:43 +01:00
Melanie
d297eb39e5 Revert "made setting rotation match Second Life"
Second Life seems to have introduced a bug, as we have confirmation that SL
behavior changed recently and changed in contradiction to their stated intention
This appears to be another of the bugs SL is notorious for. Signpost and I have
decided to back this out until SL's intention becomes clear.

This reverts commit f7b88d1c40.
2012-09-03 21:52:12 +01:00
Melanie
29218cdb31 Revert "no need to assign rotation to a variable now"
This reverts commit a3d140b57c.
2012-09-03 21:52:03 +01:00
Melanie
359f9efc76 Revert "formatting"
This reverts commit fb211c64fd.
2012-09-03 21:51:54 +01:00
SignpostMarv
fb211c64fd formatting 2012-09-03 13:55:41 +01:00
SignpostMarv
a3d140b57c no need to assign rotation to a variable now 2012-09-03 13:55:40 +01:00
SignpostMarv
f7b88d1c40 made setting rotation match Second Life 2012-09-03 13:55:40 +01:00
Robert Adams
32b534f324 BulletSim: update the SOs and DLLs 2012-08-31 11:41:39 -07:00
Robert Adams
ffdc798720 BulletSim: Update BulletSimAPI to match the DLL interface.
Major rework of terrain management which finally makes mega-regions work.
Update heightmap of terrain by rebuilding the terrain's body and shape.
    There is a problem with just replacing the shape so this workaround
    will do for the moment but it will need to be resolved for
    mesh and hull switching.
2012-08-31 11:41:33 -07:00
Robert Adams
ae852bb873 BulletSim: clean up some variable naming for consistancy.
Update DLL API for new terrain and shape/body pattern methods.
Terrain creation and modification uses new shape/body pattern.
Move debug logging callback set to initialization call so logging
   is per physics engine.
2012-08-31 11:41:28 -07:00
Robert Adams
d3adf9b2b3 BulletSim: fix line endings. 2012-08-31 11:41:23 -07:00
Robert Adams
7c140570db BulletSim: Changes to terrain storage and management so mega-regions work.
Moved all terrain code out of BSScene and into new BSTerrainManager.
Added logic to manage multiple terrains for mega-regions.
Added new functions to BulletSimAPI to match the library.
Moved all of the terrain creation and setup logic from C++ code to C# code.
    The unused code has not yet been removed from either place. Soon.
Moved checks for avatar above ground and in bounds into BSCharacter.
2012-08-31 11:41:18 -07:00
Robert Adams
7b6987ce83 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. 2012-08-31 11:41:12 -07:00
22 changed files with 1232 additions and 335 deletions

View File

@@ -92,6 +92,7 @@ what it is today.
* Flyte Xevious
* Garmin Kawaguichi
* Gryc Ueusp
* Hiro Lecker
* Imaze Rhiano
* Intimidated
* Jeremy Bongio (IBM)

View File

@@ -29,7 +29,7 @@ namespace OpenSim
{
public class VersionInfo
{
private const string VERSION_NUMBER = "0.7.4";
private const string VERSION_NUMBER = "0.7.5";
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
public enum Flavour

View File

@@ -208,6 +208,9 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height);
}
GC.Collect();
m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
return bitmap;
}
@@ -673,4 +676,4 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
return result;
}
}
}
}

View File

@@ -3418,13 +3418,16 @@ namespace OpenSim.Region.Framework.Scenes
public List<SceneObjectGroup> GetAttachments(uint attachmentPoint)
{
List<SceneObjectGroup> attachments = new List<SceneObjectGroup>();
lock (m_attachments)
if (attachmentPoint >= 0)
{
foreach (SceneObjectGroup so in m_attachments)
lock (m_attachments)
{
if (attachmentPoint == so.AttachmentPoint)
attachments.Add(so);
foreach (SceneObjectGroup so in m_attachments)
{
if (attachmentPoint == so.AttachmentPoint)
attachments.Add(so);
}
}
}

View File

@@ -34,13 +34,12 @@ 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]";
private BSScene _scene;
public BSScene Scene { get { return _scene; } }
public BSScene Scene { get; private set; }
private String _avName;
// private bool _stopped;
private Vector3 _size;
@@ -74,11 +73,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;
@@ -95,7 +91,7 @@ public class BSCharacter : PhysicsActor
{
_localID = localID;
_avName = avName;
_scene = parent_scene;
Scene = parent_scene;
_position = pos;
_size = size;
_flying = isFlying;
@@ -104,10 +100,12 @@ public class BSCharacter : PhysicsActor
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
// The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine.
_scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z);
_density = _scene.Params.avatarDensity;
_scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z);
_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;
@@ -118,19 +116,19 @@ public class BSCharacter : PhysicsActor
shapeData.Mass = _mass;
shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = _scene.Params.avatarFriction;
shapeData.Restitution = _scene.Params.avatarRestitution;
shapeData.Friction = Scene.Params.avatarFriction;
shapeData.Restitution = Scene.Params.avatarRestitution;
// do actual create at taint time
_scene.TaintedObject("BSCharacter.create", delegate()
Scene.TaintedObject("BSCharacter.create", delegate()
{
DetailLog("{0},BSCharacter.create", _localID);
BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
BulletSimAPI.CreateObject(Scene.WorldID, shapeData);
// Set the buoyancy for flying. This will be refactored when all the settings happen in C#
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
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,12 +137,12 @@ 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()
Scene.TaintedObject("BSCharacter.destroy", delegate()
{
BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
BulletSimAPI.DestroyObject(Scene.WorldID, _localID);
});
}
@@ -173,9 +171,9 @@ public class BSCharacter : PhysicsActor
ComputeAvatarVolumeAndMass();
_scene.TaintedObject("BSCharacter.setSize", delegate()
Scene.TaintedObject("BSCharacter.setSize", delegate()
{
BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true);
BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true);
});
}
@@ -204,17 +202,17 @@ public class BSCharacter : PhysicsActor
public override Vector3 Position {
get {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
return _position;
}
set {
_position = value;
PositionSanityCheck();
_scene.TaintedObject("BSCharacter.setPosition", delegate()
Scene.TaintedObject("BSCharacter.setPosition", delegate()
{
DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
});
}
}
@@ -227,16 +225,35 @@ public class BSCharacter : PhysicsActor
bool ret = false;
// If below the ground, move the avatar up
float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position);
if (_position.Z < terrainHeight)
float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position);
if (Position.Z < terrainHeight)
{
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation);
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
_position.Z = terrainHeight + 2.0f;
ret = true;
}
// TODO: check for out of bounds
return ret;
}
// A version of the sanity check that also makes sure a new position value is
// pushed back to the physics engine. This routine would be used by anyone
// who is not already pushing the value.
private bool PositionSanityCheck2()
{
bool ret = false;
if (PositionSanityCheck())
{
// The new position value must be pushed into the physics engine but we can't
// just assign to "Position" because of potential call loops.
Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
{
DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
});
ret = true;
}
return ret;
}
@@ -245,6 +262,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 {
@@ -277,10 +298,10 @@ public class BSCharacter : PhysicsActor
set {
_velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
_scene.TaintedObject("BSCharacter.setVelocity", delegate()
Scene.TaintedObject("BSCharacter.setVelocity", delegate()
{
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity);
});
}
}
@@ -303,10 +324,10 @@ public class BSCharacter : PhysicsActor
set {
_orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
_scene.TaintedObject("BSCharacter.setOrientation", delegate()
Scene.TaintedObject("BSCharacter.setOrientation", delegate()
{
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
// _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation);
});
}
}
@@ -343,11 +364,11 @@ public class BSCharacter : PhysicsActor
set { _throttleUpdates = value; }
}
public override bool IsColliding {
get { return (_collidingStep == _scene.SimulationStep); }
get { return (_collidingStep == Scene.SimulationStep); }
set { _isColliding = value; }
}
public override bool CollidingGround {
get { return (_collidingGroundStep == _scene.SimulationStep); }
get { return (_collidingGroundStep == Scene.SimulationStep); }
set { _collidingGround = value; }
}
public override bool CollidingObj {
@@ -369,10 +390,10 @@ public class BSCharacter : PhysicsActor
public override float Buoyancy {
get { return _buoyancy; }
set { _buoyancy = value;
_scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
Scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
{
DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy);
});
}
}
@@ -416,7 +437,7 @@ public class BSCharacter : PhysicsActor
_force.Y += force.Y;
_force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
_scene.TaintedObject("BSCharacter.AddForce", delegate()
Scene.TaintedObject("BSCharacter.AddForce", delegate()
{
DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
BulletSimAPI.AddObjectForce2(Body.Ptr, _force);
@@ -448,6 +469,12 @@ public class BSCharacter : PhysicsActor
});
}
}
public override void ZeroMotion()
{
return;
}
// Stop collision events
public override void UnSubscribeEvents() {
_subscribedEventsMs = 0;
@@ -481,7 +508,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;
@@ -491,30 +518,33 @@ public class BSCharacter : PhysicsActor
// Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
// base.RequestPhysicsterseUpdate();
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
PositionSanityCheck2();
float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
}
// Called by the scene when a collision with this object is reported
// 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);
// The following makes IsColliding() and IsCollidingGround() work
_collidingStep = _scene.SimulationStep;
_collidingStep = Scene.SimulationStep;
if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
{
_collidingGroundStep = _scene.SimulationStep;
_collidingGroundStep = Scene.SimulationStep;
}
// DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
// throttle collisions to the rate specified in the subscription
if (_subscribedEventsMs != 0) {
int nowTime = _scene.SimulationNowTime;
int nowTime = Scene.SimulationNowTime;
if (nowTime >= _nextCollisionOkTime) {
_nextCollisionOkTime = nowTime + _subscribedEventsMs;
@@ -525,7 +555,7 @@ public class BSCharacter : PhysicsActor
}
}
public void SendCollisions()
public override void SendCollisions()
{
/*
if (collisionCollection != null && collisionCollection.Count > 0)

View File

@@ -48,11 +48,10 @@ public abstract class BSConstraint : IDisposable
{
if (m_enabled)
{
// BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
m_enabled = false;
bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
m_constraint.Ptr = System.IntPtr.Zero;
m_enabled = false;
}
}

View File

@@ -465,6 +465,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
}//end SetDefaultsForType
// One step of the vehicle properties for the next 'pTimestep' seconds.
internal void Step(float pTimestep)
{
if (m_type == Vehicle.TYPE_NONE) return;
@@ -592,9 +593,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
// If below the terrain, move us above the ground a little.
if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos))
if (pos.Z < m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos))
{
pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2;
pos.Z = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2;
m_prim.Position = pos;
VDetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos);
}
@@ -609,7 +610,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
}
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
m_VhoverTargetHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight;
}
if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
{
@@ -673,7 +674,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
grav.Z = (float)(grav.Z * 1.125);
}
float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos);
float terraintemp = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos);
float postemp = (pos.Z - terraintemp);
if (postemp > 2.5f)
{

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,60 @@
/*
* 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 virtual void StepVehicle(float timeStep) { }
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 {
@@ -386,7 +377,7 @@ public sealed class BSPrim : PhysicsActor
// Called each simulation step to advance vehicle characteristics.
// Called from Scene when doing simulation step so we're in taint processing time.
public void StepVehicle(float timeStep)
public override void StepVehicle(float timeStep)
{
if (IsPhysical)
_vehicle.Step(timeStep);
@@ -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

@@ -39,8 +39,6 @@ using log4net;
using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Debug linkset
// Test with multiple regions in one simulator
// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
// Test sculpties
// Compute physics FPS reasonably
@@ -54,10 +52,8 @@ using OpenMetaverse;
// Use collision masks for collision with terrain and phantom objects
// Check out llVolumeDetect. Must do something for that.
// Should prim.link() and prim.delink() membership checking happen at taint time?
// changing the position and orientation of a linked prim must rebuild the constraint with the root.
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
// Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
// Does NeedsMeshing() really need to exclude all the different shapes?
@@ -78,27 +74,22 @@ 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>();
private float[] m_heightMap;
private float m_waterLevel;
private uint m_worldID;
public uint WorldID { get { return m_worldID; } }
// List of all the objects that have vehicle properties and should be called
// to update each physics step.
private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
// let my minuions use my logger
public ILog Logger { get { return m_log; } }
private bool m_initialized = false;
// If non-zero, the number of simulation steps between calls to the physics
// engine to output detailed physics stats. Debug logging level must be on also.
private int m_detailedStatsStep = 0;
public IMesher mesher;
@@ -108,29 +99,31 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public float MeshMegaPrimThreshold { get; private set; }
public float SculptLOD { get; private set; }
private BulletSim m_worldSim;
public BulletSim World
{
get { return m_worldSim; }
}
private BSConstraintCollection m_constraintCollection;
public BSConstraintCollection Constraints
{
get { return m_constraintCollection; }
}
public uint WorldID { get; private set; }
public BulletSim World { get; private set; }
// All the constraints that have been allocated in this instance.
public BSConstraintCollection Constraints { get; private set; }
// Simulation parameters
private int m_maxSubSteps;
private float m_fixedTimeStep;
private long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } }
// The length of the last timestep we were asked to simulate.
// This is used by the vehicle code. Since the vehicle code is called
// once per simulation step, its constants need to be scaled by this.
public float LastSimulatedTimestep { get; private set; }
// A value of the time now so all the collision and update routines do not have to get their own
// Set to 'now' just before all the prims and actors are called for collisions and updates
private int m_simulationNowTime;
public int SimulationNowTime { get { return m_simulationNowTime; } }
public int SimulationNowTime { get; private set; }
// True if initialized and ready to do simulation steps
private bool m_initialized = false;
// Pinned memory used to pass step information between managed and unmanaged
private int m_maxCollisionsPerFrame;
private CollisionDesc[] m_collisionArray;
private GCHandle m_collisionArrayPinnedHandle;
@@ -147,6 +140,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
public const uint GROUNDPLANE_ID = 1;
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
private float m_waterLevel;
public BSTerrainManager TerrainManager { get; private set; }
public ConfigurationParameters Params
{
@@ -157,12 +154,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
get { return new Vector3(0f, 0f, Params.gravity); }
}
private float m_maximumObjectMass;
public float MaximumObjectMass
{
get { return m_maximumObjectMass; }
}
public float MaximumObjectMass { get; private set; }
// When functions in the unmanaged code must be called, it is only
// done at a known time just before the simulation step. The taint
// system saves all these function calls and executes them in
// order before the simulation.
public delegate void TaintCallback();
private struct TaintCallbackEntry
{
@@ -178,6 +175,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private Object _taintLock = new Object();
// A pointer to an instance if this structure is passed to the C++ code
// Used to pass basic configuration values to the unmanaged code.
ConfigurationParameters[] m_params;
GCHandle m_paramsHandle;
@@ -192,10 +190,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes;
// 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; }
private bool m_vehicleLoggingEnabled;
public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
#region Construction and Initialization
public BSScene(string identifier)
{
m_initialized = false;
@@ -218,6 +216,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
mesher = meshmerizer;
_taintedObjects = new List<TaintCallbackEntry>();
// Enable very detailed logging.
// By creating an empty logger when not logging, the log message invocation code
// can be left in and every call doesn't have to check for null.
@@ -230,38 +231,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
PhysicsLogging = new Logging.LogWriter();
}
// If Debug logging level, enable logging from the unmanaged code
m_DebugLogCallbackHandle = null;
if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
if (PhysicsLogging.Enabled)
// The handle is saved in a variable to make sure it doesn't get freed after this call
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
else
m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
}
// Get the version of the DLL
// TODO: this doesn't work yet. Something wrong with marshaling the returned string.
// BulletSimVersion = BulletSimAPI.GetVersion();
// m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
// if Debug, enable logging from the unmanaged code
if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
{
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
if (PhysicsLogging.Enabled)
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
BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
}
_taintedObjects = new List<TaintCallbackEntry>();
mesher = meshmerizer;
// The bounding box for the simulated world
// The bounding box for the simulated world. The origin is 0,0,0 unless we're
// a child in a mega-region.
// Turns out that Bullet really doesn't care about the extents of the simulated
// area. It tracks active objects no matter where they are.
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
// m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
m_DebugLogCallbackHandle);
// Initialization to support the transition to a new API which puts most of the logic
// into the C# code so it is easier to modify and add to.
m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID));
m_constraintCollection = new BSConstraintCollection(World);
World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
Constraints = new BSConstraintCollection(World);
TerrainManager = new BSTerrainManager(this);
TerrainManager.CreateInitialGroundPlaneAndTerrain();
m_initialized = true;
}
@@ -289,7 +295,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
// Very detailed logging for vehicle debugging
m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
// Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
@@ -324,6 +330,38 @@ public class BSScene : PhysicsScene, IPhysicsParameters
PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
}
public override void Dispose()
{
// m_log.DebugFormat("{0}: Dispose()", LogHeader);
// make sure no stepping happens while we're deleting stuff
m_initialized = false;
TerrainManager.ReleaseGroundPlaneAndTerrain();
foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
{
kvp.Value.Destroy();
}
PhysObjects.Clear();
// Now that the prims are all cleaned up, there should be no constraints left
if (Constraints != null)
{
Constraints.Dispose();
Constraints = null;
}
// Anything left in the unmanaged code should be cleaned out
BulletSimAPI.Shutdown(WorldID);
// Not logging any more
PhysicsLogging.Close();
}
#endregion // Construction and Initialization
#region Prim and Avatar addition and removal
public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
{
m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -337,7 +375,13 @@ 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);
// TODO: Remove kludge someday.
// We must generate a collision for avatars whether they collide or not.
// This is required by OpenSim to update avatar animations, etc.
lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor);
return actor;
}
@@ -352,7 +396,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 +420,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 +445,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;
}
@@ -408,6 +454,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// information call is not needed.
public override void AddPhysicsActorTaint(PhysicsActor prim) { }
#endregion // Prim and Avatar addition and removal
#region Simulation
// Simulate one timestep
public override float Simulate(float timeStep)
{
@@ -424,6 +473,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int simulateStartTime = Util.EnvironmentTickCount();
// update the prim states while we know the physics engine is not busy
int numTaints = _taintedObjects.Count;
ProcessTaints();
// Some of the prims operate with special vehicle properties
@@ -435,14 +485,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
int numSubSteps = 0;
try
{
numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount);
DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}",
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
}
catch (Exception e)
{
m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e);
// DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount);
m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
updatedEntityCount = 0;
collidersCount = 0;
}
@@ -451,7 +504,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
// Get a value for 'now' so all the collision and update routines don't have to get their own
m_simulationNowTime = Util.EnvironmentTickCount();
SimulationNowTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim.
// Collisions must be processed before updates.
@@ -470,19 +523,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 +540,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,58 +573,47 @@ 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)
if (localID <= TerrainManager.HighestTerrainID)
{
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)
if (collidingWith <= TerrainManager.HighestTerrainID)
{
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;
}
#endregion // Simulation
public override void GetResults() { }
#region Terrain
public override void SetTerrain(float[] heightMap) {
m_heightMap = heightMap;
this.TaintedObject("BSScene.SetTerrain", delegate()
{
BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
});
}
// Someday we will have complex terrain with caves and tunnels
// For the moment, it's flat and convex
public float GetTerrainHeightAtXYZ(Vector3 loc)
{
return GetTerrainHeightAtXY(loc.X, loc.Y);
}
public float GetTerrainHeightAtXY(float tX, float tY)
{
if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize)
return 30;
return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
TerrainManager.SetTerrain(heightMap);
}
public override void SetWaterLevel(float baseheight)
@@ -598,38 +631,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
}
public override void Dispose()
// Although no one seems to check this, I do support combining.
public override bool SupportsCombining()
{
// m_log.DebugFormat("{0}: Dispose()", LogHeader);
// make sure no stepping happens while we're deleting stuff
m_initialized = false;
foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
{
kvp.Value.Destroy();
}
m_avatars.Clear();
foreach (KeyValuePair<uint, BSPrim> kvp in m_prims)
{
kvp.Value.Destroy();
}
m_prims.Clear();
// Now that the prims are all cleaned up, there should be no constraints left
if (m_constraintCollection != null)
{
m_constraintCollection.Dispose();
m_constraintCollection = null;
}
// Anything left in the unmanaged code should be cleaned out
BulletSimAPI.Shutdown(WorldID);
// Not logging any more
PhysicsLogging.Close();
return TerrainManager.SupportsCombining();
}
// This call says I am a child to region zero in a mega-region. 'pScene' is that
// of region zero, 'offset' is my offset from regions zero's origin, and
// 'extents' is the largest XY that is handled in my region.
public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
{
TerrainManager.Combine(pScene, offset, extents);
}
// Unhook all the combining that I know about.
public override void UnCombine(PhysicsScene pScene)
{
TerrainManager.UnCombine(pScene);
}
#endregion // Terrain
public override Dictionary<uint, float> GetTopColliders()
{
@@ -840,14 +861,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// no locking because only called when physics engine is not busy
private void ProcessVehicles(float timeStep)
{
foreach (BSPrim prim in m_vehicles)
foreach (BSPhysObject pobj in m_vehicles)
{
prim.StepVehicle(timeStep);
pobj.StepVehicle(timeStep);
}
}
#endregion Vehicles
#region Parameters
#region INI and command line parameter processing
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
delegate float ParamGet(BSScene scene);
@@ -950,9 +971,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)s.m_maximumObjectMass; },
(s,p,l,v) => { s.m_maximumObjectMass = v; } ),
(s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)s.MaximumObjectMass; },
(s,p,l,v) => { s.MaximumObjectMass = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f,
@@ -996,42 +1017,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,
@@ -1049,35 +1070,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].terrainRestitution; },
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.5f,
0.2f,
(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)",
@@ -1214,6 +1235,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
// This creates an array in the correct format for returning the list of
// parameters. This is used by the 'list' option of the 'physics' command.
private void BuildParameterTable()
{
if (SettableParameters.Length < ParameterDefinitions.Length)
@@ -1264,18 +1287,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);
}
@@ -1298,7 +1313,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
TaintedObject("BSScene.UpdateParameterSet", delegate() {
foreach (uint lID in objectIDs)
{
BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
}
});
break;
@@ -1316,7 +1331,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
string xparm = parm.ToLower();
float xval = val;
TaintedObject("BSScene.TaintedUpdateParameter", delegate() {
BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval);
BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval);
});
}

View File

@@ -0,0 +1,464 @@
/*
* 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 OpenSim.Framework;
using OpenSim.Region.Framework;
using OpenSim.Region.CoreModules;
using OpenSim.Region.Physics.Manager;
using Nini.Config;
using log4net;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSTerrainManager
{
static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
// These height values are fractional so the odd values will be
// noticable when debugging.
public const float HEIGHT_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f;
// If the min and max height are equal, we reduce the min by this
// amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
// Until the whole simulator is changed to pass us the region size, we rely on constants.
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, 0f);
// The scene that I am part of
private BSScene m_physicsScene;
// The ground plane created to keep thing from falling to infinity.
private BulletBody m_groundPlane;
// If doing mega-regions, if we're region zero we will be managing multiple
// region terrains since region zero does the physics for the whole mega-region.
private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
// True of the terrain has been modified.
// Used to force recalculation of terrain height after terrain has been modified
private bool m_terrainModified;
// If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
// This is incremented before assigning to new region so it is the last ID allocated.
private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
public uint HighestTerrainID { get {return m_terrainCount; } }
// If doing mega-regions, this holds our offset from region zero of
// the mega-regions. "parentScene" points to the PhysicsScene of region zero.
private Vector3 m_worldOffset;
// If the parent region (region 0), this is the extent of the combined regions
// relative to the origin of region zero
private Vector3 m_worldMax;
private PhysicsScene m_parentScene;
public BSTerrainManager(BSScene physicsScene)
{
m_physicsScene = physicsScene;
m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
m_terrainModified = false;
// Assume one region of default size
m_worldOffset = Vector3.Zero;
m_worldMax = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, 4096f);
m_parentScene = null;
}
// Create the initial instance of terrain and the underlying ground plane.
// The objects are allocated in the unmanaged space and the pointers are tracked
// by the managed code.
// The terrains and the groundPlane are not added to the list of PhysObjects.
// This is called from the initialization routine so we presume it is
// safe to call Bullet in real time. We hope no one is moving prims around yet.
public void CreateInitialGroundPlaneAndTerrain()
{
// The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape(BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN));
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.Ptr, Vector3.Zero, Quaternion.Identity));
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
float[] initialMap = new float[totalHeights];
for (int ii = 0; ii < totalHeights; ii++)
{
initialMap[ii] = HEIGHT_INITIALIZATION;
}
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
}
// Release all the terrain structures we might have allocated
public void ReleaseGroundPlaneAndTerrain()
{
if (m_groundPlane.Ptr != IntPtr.Zero)
{
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr))
{
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr);
}
m_groundPlane.Ptr = IntPtr.Zero;
}
ReleaseTerrain();
}
// Release all the terrain we have allocated
public void ReleaseTerrain()
{
foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
{
if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr))
{
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr);
BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
}
}
m_heightMaps.Clear();
}
// The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) {
if (m_worldOffset != Vector3.Zero && m_parentScene != null)
{
// If a child of a mega-region, we shouldn't have any terrain allocated for us
ReleaseGroundPlaneAndTerrain();
// If doing the mega-prim stuff and we are the child of the zero region,
// the terrain is added to our parent
if (m_parentScene is BSScene)
{
DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
BSScene.DetailLogZero, m_worldOffset, m_worldMax);
((BSScene)m_parentScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
heightMap, m_worldOffset, m_worldOffset+DefaultRegionSize, false);
}
}
else
{
// If not doing the mega-prim thing, just change the terrain
DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
UpdateOrCreateTerrain(BSScene.TERRAIN_ID, heightMap, m_worldOffset, m_worldOffset+DefaultRegionSize, false);
}
}
// If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
// based on the passed information. The 'id' should be either the terrain id or
// BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
// The latter feature is for creating child terrains for mega-regions.
// If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
// then a new body and shape is created and the mapInfo is filled.
// This call is used for doing the initial terrain creation.
// If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
// terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain.
// The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
// calling this routine from initialization or taint-time routines) or whether to delay
// all the unmanaged activities to taint-time.
private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool doNow)
{
DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},doNow={3}",
BSScene.DetailLogZero, minCoords, maxCoords, doNow);
float minZ = float.MaxValue;
float maxZ = float.MinValue;
Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y);
int heightMapSize = heightMap.Length;
for (int ii = 0; ii < heightMapSize; ii++)
{
float height = heightMap[ii];
if (height < minZ) minZ = height;
if (height > maxZ) maxZ = height;
}
// The shape of the terrain is from its base to its extents.
minCoords.Z = minZ;
maxCoords.Z = maxZ;
BulletHeightMapInfo mapInfo;
if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo))
{
// If this is terrain we know about, it's easy to update
mapInfo.heightMap = heightMap;
mapInfo.minCoords = minCoords;
mapInfo.maxCoords = maxCoords;
mapInfo.minZ = minZ;
mapInfo.maxZ = maxZ;
mapInfo.sizeX = maxCoords.X - minCoords.X;
mapInfo.sizeY = maxCoords.Y - minCoords.Y;
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
BSScene.TaintCallback rebuildOperation = delegate()
{
if (m_parentScene != null)
{
// It's possible that Combine() was called after this code was queued.
// If we are a child of combined regions, we don't create any terrain for us.
DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
// Get rid of any terrain that may have been allocated for us.
ReleaseGroundPlaneAndTerrain();
// I hate doing this, but just bail
return;
}
if (mapInfo.terrainBody.Ptr != IntPtr.Zero)
{
// Updating an existing terrain.
DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
// Remove from the dynamics world because we're going to mangle this object
BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
// Get rid of the old terrain
BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
mapInfo.Ptr = IntPtr.Zero;
/*
// NOTE: This routine is half here because I can't get the terrain shape replacement
// to work. In the short term, the above three lines completely delete the old
// terrain and the code below recreates one from scratch.
// Hopefully the Bullet community will help me out on this one.
// First, release the old collision shape (there is only one terrain)
BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
// Fill the existing height map info with the new location and size information
BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
// Create a terrain shape based on the new info
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
// Stuff the shape into the existing terrain body
BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
*/
}
// else
{
// Creating a new terrain.
DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
mapInfo.ID = id;
mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.ID,
mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
// The terrain object initial position is at the center of the object
Vector3 centerPos;
centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
centerPos.Z = minZ + ((maxZ - minZ) / 2f);
// Create the terrain shape from the mapInfo
mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
mapInfo.terrainBody = new BulletBody(mapInfo.ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.Ptr,
centerPos, Quaternion.Identity));
}
// Make sure the entry is in the heightmap table
m_heightMaps[terrainRegionBase] = mapInfo;
// Set current terrain attributes
BulletSimAPI.SetFriction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainFriction);
BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction);
BulletSimAPI.SetRestitution2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainRestitution);
BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT);
BulletSimAPI.SetMassProps2(mapInfo.terrainBody.Ptr, 0f, Vector3.Zero);
BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.Ptr);
// Return the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
// redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr);
// Make sure the new shape is processed.
BulletSimAPI.Activate2(mapInfo.terrainBody.Ptr, true);
};
// There is the option to do the changes now (we're already in 'taint time'), or
// to do the Bullet operations later.
if (doNow)
rebuildOperation();
else
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
}
else
{
// We don't know about this terrain so either we are creating a new terrain or
// our mega-prim child is giving us a new terrain to add to the phys world
// if this is a child terrain, calculate a unique terrain id
uint newTerrainID = id;
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount;
float[] heightMapX = heightMap;
Vector3 minCoordsX = minCoords;
Vector3 maxCoordsX = maxCoords;
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
// Code that must happen at taint-time
BSScene.TaintCallback createOperation = delegate()
{
DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
// Create a new mapInfo that will be filled with the new info
mapInfo = new BulletHeightMapInfo(id, heightMapX,
BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, newTerrainID,
minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
// Put the unfilled heightmap info into the collection of same
m_heightMaps.Add(terrainRegionBase, mapInfo);
// Build the terrain
UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
};
// If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
if (doNow)
createOperation();
else
m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
}
}
// Someday we will have complex terrain with caves and tunnels
public float GetTerrainHeightAtXYZ(Vector3 loc)
{
// For the moment, it's flat and convex
return GetTerrainHeightAtXY(loc.X, loc.Y);
}
// Given an X and Y, find the height of the terrain.
// Since we could be handling multiple terrains for a mega-region,
// the base of the region is calcuated assuming all regions are
// the same size and that is the default.
// Once the heightMapInfo is found, we have all the information to
// compute the offset into the array.
private float lastHeightTX = 999999f;
private float lastHeightTY = 999999f;
private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
public float GetTerrainHeightAtXY(float tX, float tY)
{
// You'd be surprized at the number of times this routine is called
// with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight;
lastHeightTX = tX;
lastHeightTY = tY;
float ret = HEIGHT_GETHEIGHT_RET;
int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector2 terrainBaseXY = new Vector2(offsetX, offsetY);
BulletHeightMapInfo mapInfo;
if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo))
{
float regionX = tX - offsetX;
float regionY = tY - offsetY;
if (regionX > mapInfo.sizeX) regionX = 0;
if (regionY > mapInfo.sizeY) regionY = 0;
int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX;
ret = mapInfo.heightMap[mapIndex];
m_terrainModified = false;
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
}
else
{
m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, m_physicsScene.RegionName, tX, tY);
}
lastHeight = ret;
return ret;
}
// Although no one seems to check this, I do support combining.
public bool SupportsCombining()
{
return true;
}
// This routine is called two ways:
// One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
// extent of the combined regions. This is to inform the parent of the size
// of the combined regions.
// and one with 'offset' as the offset of the child region to the base region,
// 'pScene' pointing to the parent and 'extents' of zero. This informs the
// child of its relative base and new parent.
public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
{
m_worldOffset = offset;
m_worldMax = extents;
m_parentScene = pScene;
if (pScene != null)
{
// We are a child.
// We want m_worldMax to be the highest coordinate of our piece of terrain.
m_worldMax = offset + DefaultRegionSize;
}
DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
}
// Unhook all the combining that I know about.
public void UnCombine(PhysicsScene pScene)
{
// Just like ODE, for the moment a NOP
DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
}
private void DetailLog(string msg, params Object[] args)
{
m_physicsScene.PhysicsLogging.Write(msg, args);
}
}
}

View File

@@ -33,15 +33,25 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API
// These hold pointers to allocated objects in the unmanaged space.
// The physics engine controller class created at initialization
public struct BulletSim
{
public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; }
public uint ID;
public BulletSim(uint worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; }
public uint worldID;
// The scene is only in here so very low level routines have a handle to print debug/error messages
public BSScene scene;
public IntPtr Ptr;
}
public struct BulletShape
{
public BulletShape(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr;
}
// An allocated Bullet btRigidBody
public struct BulletBody
{
public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
@@ -49,12 +59,41 @@ public struct BulletBody
public uint ID;
}
// An allocated Bullet btConstraint
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr;
}
// An allocated HeightMapThing which hold various heightmap info
// Made a class rather than a struct so there would be only one
// instance of this and C# will pass around pointers rather
// than making copies.
public class BulletHeightMapInfo
{
public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
ID = id;
Ptr = xx;
heightMap = hm;
terrainRegionBase = new Vector2(0f, 0f);
minCoords = new Vector3(100f, 100f, 25f);
maxCoords = new Vector3(101f, 101f, 26f);
minZ = maxZ = 0f;
sizeX = sizeY = 256f;
}
public uint ID;
public IntPtr Ptr;
public float[] heightMap;
public Vector2 terrainRegionBase;
public Vector3 minCoords;
public Vector3 maxCoords;
public float sizeX, sizeY;
public float minZ, maxZ;
public BulletShape terrainShape;
public BulletBody terrainBody;
}
// ===============================================================================
[StructLayout(LayoutKind.Sequential)]
public struct ConvexHull
@@ -221,6 +260,10 @@ public enum ConstraintParamAxis : int
// ===============================================================================
static class BulletSimAPI {
// Link back to the managed code for outputting log messages
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetVersion();
@@ -228,7 +271,11 @@ public static extern string GetVersion();
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
int maxCollisions, IntPtr collisionArray,
int maxUpdates, IntPtr updateArray);
int maxUpdates, IntPtr updateArray,
DebugLogCallback logRoutine);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
@@ -342,8 +389,6 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
public static extern void DumpBulletStatistics();
// Log a debug message
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetDebugLogCallback(DebugLogCallback callback);
@@ -377,7 +422,7 @@ public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap2(IntPtr world, float[] heightmap);
public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void Shutdown2(IntPtr sim);
@@ -412,14 +457,31 @@ public static extern IntPtr BuildNativeShape2(IntPtr world,
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateGroundPlaneBody2(uint id, Vector3 center, float collisionMargin);
public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateTerrainBody2(uint id,
Vector3 minCoords, Vector3 maxCoords, float collisionMargin,
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, Vector3 pos, Quaternion rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetBodyShape2(IntPtr sim, IntPtr obj, IntPtr shape);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
[MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -473,11 +535,16 @@ public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj);
public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
// =====================================================================================
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void Activate2(IntPtr obj, bool forceActivation);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetPosition2(IntPtr obj);
@@ -521,6 +588,9 @@ public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetFriction2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetHitFraction2(IntPtr obj, float val);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetRestitution2(IntPtr obj, float val);
@@ -564,7 +634,7 @@ public static extern bool SetMargin2(IntPtr obj, float val);
public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyObject2(IntPtr world, uint id);
public static extern bool DestroyObject2(IntPtr world, IntPtr obj);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void DumpPhysicsStatistics2(IntPtr sim);

View File

@@ -310,7 +310,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// ---------- Integer ----------
else if (lslparm is LSL_Integer)
{
if (type == typeof(int))
if (type == typeof(int) || type == typeof(float))
return (int)(LSL_Integer)lslparm;
}

View File

@@ -1673,6 +1673,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return;
}
MessageObject(objUUID, message);
}
private void MessageObject(UUID objUUID, string message)
{
object[] resobj = new object[] { new LSL_Types.LSLString(m_host.UUID.ToString()), new LSL_Types.LSLString(message) };
SceneObjectPart sceneOP = World.GetSceneObjectPart(objUUID);
@@ -3224,6 +3229,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
}
#region Attachment commands
public void osForceAttachToAvatar(int attachmentPoint)
{
CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar");
@@ -3313,6 +3320,175 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
((LSL_Api)m_LSL_Api).DetachFromAvatar();
}
public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints)
{
CheckThreatLevel(ThreatLevel.Moderate, "osGetNumberOfAttachments");
m_host.AddScriptLPS(1);
UUID targetUUID;
ScenePresence target;
LSL_List resp = new LSL_List();
if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target))
{
foreach (object point in attachmentPoints.Data)
{
LSL_Integer ipoint = new LSL_Integer(
(point is LSL_Integer || point is int || point is uint) ?
(int)point :
0
);
resp.Add(ipoint);
if (ipoint == 0)
{
// indicates zero attachments
resp.Add(new LSL_Integer(0));
}
else
{
// gets the number of attachments on the attachment point
resp.Add(new LSL_Integer(target.GetAttachments((uint)ipoint).Count));
}
}
}
return resp;
}
public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int options)
{
CheckThreatLevel(ThreatLevel.Moderate, "osMessageAttachments");
m_host.AddScriptLPS(1);
UUID targetUUID;
ScenePresence target;
if (attachmentPoints.Length >= 1 && UUID.TryParse(avatar.ToString(), out targetUUID) && World.TryGetScenePresence(targetUUID, out target))
{
List<int> aps = new List<int>();
foreach (object point in attachmentPoints.Data)
{
int ipoint;
if (int.TryParse(point.ToString(), out ipoint))
{
aps.Add(ipoint);
}
}
List<SceneObjectGroup> attachments = new List<SceneObjectGroup>();
bool msgAll = aps.Contains(ScriptBaseClass.OS_ATTACH_MSG_ALL);
bool invertPoints = (options & ScriptBaseClass.OS_ATTACH_MSG_INVERT_POINTS) != 0;
if (msgAll && invertPoints)
{
return;
}
else if (msgAll || invertPoints)
{
attachments = target.GetAttachments();
}
else
{
foreach (int point in aps)
{
if (point > 0)
{
attachments.AddRange(target.GetAttachments((uint)point));
}
}
}
// if we have no attachments at this point, exit now
if (attachments.Count == 0)
{
return;
}
List<SceneObjectGroup> ignoreThese = new List<SceneObjectGroup>();
if (invertPoints)
{
foreach (SceneObjectGroup attachment in attachments)
{
if (aps.Contains((int)attachment.AttachmentPoint))
{
ignoreThese.Add(attachment);
}
}
}
foreach (SceneObjectGroup attachment in ignoreThese)
{
attachments.Remove(attachment);
}
ignoreThese.Clear();
// if inverting removed all attachments to check, exit now
if (attachments.Count < 1)
{
return;
}
if ((options & ScriptBaseClass.OS_ATTACH_MSG_OBJECT_CREATOR) != 0)
{
foreach (SceneObjectGroup attachment in attachments)
{
if (attachment.RootPart.CreatorID != m_host.CreatorID)
{
ignoreThese.Add(attachment);
}
}
foreach (SceneObjectGroup attachment in ignoreThese)
{
attachments.Remove(attachment);
}
ignoreThese.Clear();
// if filtering by same object creator removed all
// attachments to check, exit now
if (attachments.Count == 0)
{
return;
}
}
if ((options & ScriptBaseClass.OS_ATTACH_MSG_SCRIPT_CREATOR) != 0)
{
foreach (SceneObjectGroup attachment in attachments)
{
if (attachment.RootPart.CreatorID != m_item.CreatorID)
{
ignoreThese.Add(attachment);
}
}
foreach (SceneObjectGroup attachment in ignoreThese)
{
attachments.Remove(attachment);
}
ignoreThese.Clear();
// if filtering by object creator must match originating
// script creator removed all attachments to check,
// exit now
if (attachments.Count == 0)
{
return;
}
}
foreach (SceneObjectGroup attachment in attachments)
{
MessageObject(attachment.RootPart.UUID, message);
}
}
}
#endregion
/// <summary>
/// Checks if thing is a UUID.
/// </summary>

View File

@@ -157,7 +157,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
void osAvatarPlayAnimation(string avatar, string animation);
void osAvatarStopAnimation(string avatar, string animation);
// Attachment commands
#region Attachment commands
/// <summary>
/// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH
@@ -192,6 +192,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces
/// <remarks>Nothing happens if the object is not attached.</remarks>
void osForceDetachFromAvatar();
/// <summary>
/// Returns a strided list of the specified attachment points and the number of attachments on those points.
/// </summary>
/// <param name="avatar">avatar UUID</param>
/// <param name="attachmentPoints">list of ATTACH_* constants</param>
/// <returns></returns>
LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints);
/// <summary>
/// Sends a specified message to the specified avatar's attachments on
/// the specified attachment points.
/// </summary>
/// <remarks>
/// Behaves as osMessageObject(), without the sending script needing to know the attachment keys in advance.
/// </remarks>
/// <param name="avatar">avatar UUID</param>
/// <param name="message">message string</param>
/// <param name="attachmentPoints">list of ATTACH_* constants, or -1 for all attachments. If -1 is specified and OS_ATTACH_MSG_INVERT_POINTS is present in flags, no action is taken.</param>
/// <param name="flags">flags further constraining the attachments to deliver the message to.</param>
void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int flags);
#endregion
//texture draw functions
string osMovePen(string drawList, int x, int y);
string osDrawLine(string drawList, int startX, int startY, int endX, int endY);

View File

@@ -237,6 +237,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
public const int ATTACH_HUD_BOTTOM = 37;
public const int ATTACH_HUD_BOTTOM_RIGHT = 38;
#region osMessageAttachments constants
/// <summary>
/// Instructs osMessageAttachements to send the message to attachments
/// on every point.
/// </summary>
/// <remarks>
/// One might expect this to be named OS_ATTACH_ALL, but then one might
/// also expect functions designed to attach or detach or get
/// attachments to work with it too. Attaching a no-copy item to
/// many attachments could be dangerous.
/// when combined with OS_ATTACH_MSG_INVERT_POINTS, will prevent the
/// message from being sent.
/// if combined with OS_ATTACH_MSG_OBJECT_CREATOR or
/// OS_ATTACH_MSG_SCRIPT_CREATOR, could result in no message being
/// sent- this is expected behaviour.
/// </remarks>
public const int OS_ATTACH_MSG_ALL = -65535;
/// <summary>
/// Instructs osMessageAttachements to invert how the attachment points
/// list should be treated (e.g. go from inclusive operation to
/// exclusive operation).
/// </summary>
/// <remarks>
/// This might be used if you want to deliver a message to one set of
/// attachments and a different message to everything else. With
/// this flag, you only need to build one explicit list for both calls.
/// </remarks>
public const int OS_ATTACH_MSG_INVERT_POINTS = 1;
/// <summary>
/// Instructs osMessageAttachments to only send the message to
/// attachments with a CreatorID that matches the host object CreatorID
/// </summary>
/// <remarks>
/// This would be used if distributed in an object vendor/updater server.
/// </remarks>
public const int OS_ATTACH_MSG_OBJECT_CREATOR = 2;
/// <summary>
/// Instructs osMessageAttachments to only send the message to
/// attachments with a CreatorID that matches the sending script CreatorID
/// </summary>
/// <remarks>
/// This might be used if the script is distributed independently of a
/// containing object.
/// </remarks>
public const int OS_ATTACH_MSG_SCRIPT_CREATOR = 4;
#endregion
public const int LAND_LEVEL = 0;
public const int LAND_RAISE = 1;
public const int LAND_LOWER = 2;

View File

@@ -289,7 +289,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
m_OSSL_Functions.osAvatarStopAnimation(avatar, animation);
}
// Avatar functions
#region Attachment commands
public void osForceAttachToAvatar(int attachmentPoint)
{
@@ -311,6 +311,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
m_OSSL_Functions.osForceDetachFromAvatar();
}
public LSL_List osGetNumberOfAttachments(LSL_Key avatar, LSL_List attachmentPoints)
{
return m_OSSL_Functions.osGetNumberOfAttachments(avatar, attachmentPoints);
}
public void osMessageAttachments(LSL_Key avatar, string message, LSL_List attachmentPoints, int flags)
{
m_OSSL_Functions.osMessageAttachments(avatar, message, attachmentPoints, flags);
}
#endregion
// Texture Draw functions
public string osMovePen(string drawList, int x, int y)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.