aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
authorDan Lake2012-03-27 12:51:58 -0700
committerDan Lake2012-03-27 12:51:58 -0700
commit971d32fda3cf8384987a6709cd2242afecce13ab (patch)
tree2607c27fad429ff0036fe7b7d275ddf717397282 /OpenSim/Region/Physics/BulletSPlugin
parentWhen loading objects from DB, first add to scene, then call TriggerOnSceneObj... (diff)
parentHG: beginning of a more restrictive inventory access procedure (optional). Ex... (diff)
downloadopensim-SC-971d32fda3cf8384987a6709cd2242afecce13ab.zip
opensim-SC-971d32fda3cf8384987a6709cd2242afecce13ab.tar.gz
opensim-SC-971d32fda3cf8384987a6709cd2242afecce13ab.tar.bz2
opensim-SC-971d32fda3cf8384987a6709cd2242afecce13ab.tar.xz
Merge branch 'master' of ssh://opensimulator.org/var/git/opensim
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs41
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs35
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs133
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs19
5 files changed, 183 insertions, 49 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 0cab5d1..b08d5db 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -94,7 +94,7 @@ public class BSCharacter : PhysicsActor
94 _flying = isFlying; 94 _flying = isFlying;
95 _orientation = Quaternion.Identity; 95 _orientation = Quaternion.Identity;
96 _velocity = Vector3.Zero; 96 _velocity = Vector3.Zero;
97 _buoyancy = isFlying ? 1f : 0f; 97 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
98 _scale = new Vector3(1f, 1f, 1f); 98 _scale = new Vector3(1f, 1f, 1f);
99 _density = _scene.Params.avatarDensity; 99 _density = _scene.Params.avatarDensity;
100 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 100 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
@@ -110,7 +110,7 @@ public class BSCharacter : PhysicsActor
110 shapeData.Buoyancy = _buoyancy; 110 shapeData.Buoyancy = _buoyancy;
111 shapeData.Static = ShapeData.numericFalse; 111 shapeData.Static = ShapeData.numericFalse;
112 shapeData.Friction = _scene.Params.avatarFriction; 112 shapeData.Friction = _scene.Params.avatarFriction;
113 shapeData.Restitution = _scene.Params.defaultRestitution; 113 shapeData.Restitution = _scene.Params.avatarRestitution;
114 114
115 // do actual create at taint time 115 // do actual create at taint time
116 _scene.TaintedObject(delegate() 116 _scene.TaintedObject(delegate()
@@ -260,13 +260,13 @@ public class BSCharacter : PhysicsActor
260 get { return _flying; } 260 get { return _flying; }
261 set { 261 set {
262 _flying = value; 262 _flying = value;
263 _scene.TaintedObject(delegate() 263 // simulate flying by changing the effect of gravity
264 { 264 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
265 // simulate flying by changing the effect of gravity
266 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _flying ? 1f : 0f);
267 });
268 } 265 }
269 } 266 }
267 private float ComputeBuoyancyFromFlying(bool ifFlying) {
268 return ifFlying ? 1f : 0f;
269 }
270 public override bool 270 public override bool
271 SetAlwaysRun { 271 SetAlwaysRun {
272 get { return _setAlwaysRun; } 272 get { return _setAlwaysRun; }
@@ -299,6 +299,7 @@ public class BSCharacter : PhysicsActor
299 get { return _kinematic; } 299 get { return _kinematic; }
300 set { _kinematic = value; } 300 set { _kinematic = value; }
301 } 301 }
302 // neg=fall quickly, 0=1g, 1=0g, pos=float up
302 public override float Buoyancy { 303 public override float Buoyancy {
303 get { return _buoyancy; } 304 get { return _buoyancy; }
304 set { _buoyancy = value; 305 set { _buoyancy = value;
@@ -355,7 +356,7 @@ public class BSCharacter : PhysicsActor
355 } 356 }
356 else 357 else
357 { 358 {
358 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 359 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader);
359 } 360 }
360 //m_lastUpdateSent = false; 361 //m_lastUpdateSent = false;
361 } 362 }
@@ -425,6 +426,8 @@ public class BSCharacter : PhysicsActor
425 } 426 }
426 } 427 }
427 428
429 // Called by the scene when a collision with this object is reported
430 CollisionEventUpdate collisionCollection = null;
428 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth) 431 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
429 { 432 {
430 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); 433 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
@@ -442,10 +445,24 @@ public class BSCharacter : PhysicsActor
442 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; 445 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
443 _lastCollisionTime = nowTime; 446 _lastCollisionTime = nowTime;
444 447
445 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>(); 448 if (collisionCollection == null)
446 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 449 collisionCollection = new CollisionEventUpdate();
447 CollisionEventUpdate args = new CollisionEventUpdate(contactPoints); 450 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
448 base.SendCollisionUpdate(args); 451 }
452
453 public void SendCollisions()
454 {
455 // if (collisionCollection != null)
456 // {
457 // base.SendCollisionUpdate(collisionCollection);
458 // collisionCollection = null;
459 // }
460 // Kludge to make a collision call even if there are no collisions.
461 // This causes the avatar animation to get updated.
462 if (collisionCollection == null)
463 collisionCollection = new CollisionEventUpdate();
464 base.SendCollisionUpdate(collisionCollection);
465 collisionCollection = null;
449 } 466 }
450 467
451} 468}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 046726d..eb20eb3 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -821,7 +821,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
821 */ 821 */
822 822
823 // Get what the body is doing, this includes 'external' influences 823 // Get what the body is doing, this includes 'external' influences
824 Vector3 angularVelocity = m_prim.AngularVelocity; 824 Vector3 angularVelocity = m_prim.RotationalVelocity;
825 // Vector3 angularVelocity = Vector3.Zero; 825 // Vector3 angularVelocity = Vector3.Zero;
826 826
827 if (m_angularMotorApply > 0) 827 if (m_angularMotorApply > 0)
@@ -910,7 +910,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
910 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 910 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
911 911
912 // Apply to the body 912 // Apply to the body
913 m_prim.AngularVelocity = m_lastAngularVelocity; 913 m_prim.RotationalVelocity = m_lastAngularVelocity;
914 914
915 } //end MoveAngular 915 } //end MoveAngular
916 internal void LimitRotation(float timestep) 916 internal void LimitRotation(float timestep)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 898436b..248d1f2 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -85,7 +85,6 @@ public sealed class BSPrim : PhysicsActor
85 private OMV.Vector3 _rotationalVelocity; 85 private OMV.Vector3 _rotationalVelocity;
86 private bool _kinematic; 86 private bool _kinematic;
87 private float _buoyancy; 87 private float _buoyancy;
88 private OMV.Vector3 _angularVelocity;
89 88
90 private List<BSPrim> _childrenPrims; 89 private List<BSPrim> _childrenPrims;
91 private BSPrim _parentPrim; 90 private BSPrim _parentPrim;
@@ -119,7 +118,6 @@ public sealed class BSPrim : PhysicsActor
119 _buoyancy = 1f; 118 _buoyancy = 1f;
120 _velocity = OMV.Vector3.Zero; 119 _velocity = OMV.Vector3.Zero;
121 _rotationalVelocity = OMV.Vector3.Zero; 120 _rotationalVelocity = OMV.Vector3.Zero;
122 _angularVelocity = OMV.Vector3.Zero;
123 _hullKey = 0; 121 _hullKey = 0;
124 _meshKey = 0; 122 _meshKey = 0;
125 _pbs = pbs; 123 _pbs = pbs;
@@ -146,7 +144,7 @@ public sealed class BSPrim : PhysicsActor
146 // called when this prim is being destroyed and we should free all the resources 144 // called when this prim is being destroyed and we should free all the resources
147 public void Destroy() 145 public void Destroy()
148 { 146 {
149 // m_log.DebugFormat("{0}: Destroy", LogHeader); 147 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
150 // Undo any vehicle properties 148 // Undo any vehicle properties
151 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); 149 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
152 _scene.RemoveVehiclePrim(this); // just to make sure 150 _scene.RemoveVehiclePrim(this); // just to make sure
@@ -203,7 +201,7 @@ public sealed class BSPrim : PhysicsActor
203 201
204 // link me to the specified parent 202 // link me to the specified parent
205 public override void link(PhysicsActor obj) { 203 public override void link(PhysicsActor obj) {
206 BSPrim parent = (BSPrim)obj; 204 BSPrim parent = obj as BSPrim;
207 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); 205 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
208 // TODO: decide if this parent checking needs to happen at taint time 206 // TODO: decide if this parent checking needs to happen at taint time
209 if (_parentPrim == null) 207 if (_parentPrim == null)
@@ -527,10 +525,6 @@ public sealed class BSPrim : PhysicsActor
527 }); 525 });
528 } 526 }
529 } 527 }
530 public OMV.Vector3 AngularVelocity {
531 get { return _angularVelocity; }
532 set { _angularVelocity = value; }
533 }
534 public override bool Kinematic { 528 public override bool Kinematic {
535 get { return _kinematic; } 529 get { return _kinematic; }
536 set { _kinematic = value; 530 set { _kinematic = value;
@@ -993,7 +987,7 @@ public sealed class BSPrim : PhysicsActor
993 } 987 }
994 988
995 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 989 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
996 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count); 990 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
997 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices, 991 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
998 vertices.Count, verticesAsFloats); 992 vertices.Count, verticesAsFloats);
999 993
@@ -1127,7 +1121,7 @@ public sealed class BSPrim : PhysicsActor
1127 return; 1121 return;
1128 } 1122 }
1129 1123
1130 // Create an object in Bullet 1124 // Create an object in Bullet if it has not already been created
1131 // No locking here because this is done when the physics engine is not simulating 1125 // No locking here because this is done when the physics engine is not simulating
1132 private void CreateObject() 1126 private void CreateObject()
1133 { 1127 {
@@ -1324,13 +1318,15 @@ public sealed class BSPrim : PhysicsActor
1324 _velocity = entprop.Velocity; 1318 _velocity = entprop.Velocity;
1325 _acceleration = entprop.Acceleration; 1319 _acceleration = entprop.Acceleration;
1326 _rotationalVelocity = entprop.RotationalVelocity; 1320 _rotationalVelocity = entprop.RotationalVelocity;
1327 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); 1321 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}",
1322 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1328 base.RequestPhysicsterseUpdate(); 1323 base.RequestPhysicsterseUpdate();
1329 } 1324 }
1330 } 1325 }
1331 } 1326 }
1332 1327
1333 // I've collided with something 1328 // I've collided with something
1329 CollisionEventUpdate collisionCollection = null;
1334 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 1330 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1335 { 1331 {
1336 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); 1332 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
@@ -1348,11 +1344,18 @@ public sealed class BSPrim : PhysicsActor
1348 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; 1344 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1349 _lastCollisionTime = nowTime; 1345 _lastCollisionTime = nowTime;
1350 1346
1351 // create the event for the collision 1347 if (collisionCollection == null)
1352 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>(); 1348 collisionCollection = new CollisionEventUpdate();
1353 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 1349 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1354 CollisionEventUpdate args = new CollisionEventUpdate(contactPoints); 1350 }
1355 base.SendCollisionUpdate(args); 1351
1352 public void SendCollisions()
1353 {
1354 if (collisionCollection != null)
1355 {
1356 base.SendCollisionUpdate(collisionCollection);
1357 collisionCollection = null;
1358 }
1356 } 1359 }
1357} 1360}
1358} 1361}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index e9a849c..94a0ccf 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -37,14 +37,18 @@ using OpenMetaverse;
37using OpenSim.Region.Framework; 37using OpenSim.Region.Framework;
38 38
39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 39// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
40// Debug linkset
41// Test with multiple regions in one simulator
40// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) 42// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
41// Test sculpties 43// Test sculpties
42// Compute physics FPS reasonably 44// Compute physics FPS reasonably
43// Based on material, set density and friction 45// Based on material, set density and friction
44// More efficient memory usage in passing hull information from BSPrim to BulletSim 46// More efficient memory usage when passing hull information from BSPrim to BulletSim
45// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 47// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
46// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 48// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
47// At the moment, physical and phantom causes object to drop through the terrain 49// At the moment, physical and phantom causes object to drop through the terrain
50// Physical phantom objects and related typing (collision options )
51// Check out llVolumeDetect. Must do something for that.
48// Should prim.link() and prim.delink() membership checking happen at taint time? 52// Should prim.link() and prim.delink() membership checking happen at taint time?
49// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 53// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
50// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 54// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
@@ -52,6 +56,16 @@ using OpenSim.Region.Framework;
52// Implement LockAngularMotion 56// Implement LockAngularMotion
53// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
54// Does NeedsMeshing() really need to exclude all the different shapes? 58// Does NeedsMeshing() really need to exclude all the different shapes?
59// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
60// Add PID movement operations. What does ScenePresence.MoveToTarget do?
61// Check terrain size. 128 or 127?
62// Multiple contact points on collision?
63// See code in ode::near... calls to collision_accounting_events()
64// (This might not be a problem. ODE collects all the collisions with one object in one tick.)
65// Use collision masks for collision with terrain and phantom objects
66// Figure out how to not allocate a new Dictionary and List for every collision
67// in BSPrim.Collide() and BSCharacter.Collide(). Can the same ones be reused?
68// Raycast
55// 69//
56namespace OpenSim.Region.Physics.BulletSPlugin 70namespace OpenSim.Region.Physics.BulletSPlugin
57{ 71{
@@ -64,6 +78,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
64 78
65 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 79 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
66 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 80 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
81 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
82 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
67 private List<BSPrim> m_vehicles = new List<BSPrim>(); 83 private List<BSPrim> m_vehicles = new List<BSPrim>();
68 private float[] m_heightMap; 84 private float[] m_heightMap;
69 private float m_waterLevel; 85 private float m_waterLevel;
@@ -164,6 +180,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
164 if (m_log.IsDebugEnabled) 180 if (m_log.IsDebugEnabled)
165 { 181 {
166 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 182 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
183 // the handle is saved to it doesn't get freed after this call
167 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 184 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
168 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); 185 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
169 } 186 }
@@ -172,7 +189,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 189
173 mesher = meshmerizer; 190 mesher = meshmerizer;
174 // The bounding box for the simulated world 191 // The bounding box for the simulated world
175 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f); 192 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f);
176 193
177 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 194 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
178 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 195 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
@@ -220,10 +237,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
220 parms.terrainFriction = 0.5f; 237 parms.terrainFriction = 0.5f;
221 parms.terrainHitFraction = 0.8f; 238 parms.terrainHitFraction = 0.8f;
222 parms.terrainRestitution = 0f; 239 parms.terrainRestitution = 0f;
223 parms.avatarFriction = 0.0f; 240 parms.avatarFriction = 0.5f;
241 parms.avatarRestitution = 0.0f;
224 parms.avatarDensity = 60f; 242 parms.avatarDensity = 60f;
225 parms.avatarCapsuleRadius = 0.37f; 243 parms.avatarCapsuleRadius = 0.37f;
226 parms.avatarCapsuleHeight = 1.5f; // 2.140599f 244 parms.avatarCapsuleHeight = 1.5f; // 2.140599f
245 parms.avatarContactProcessingThreshold = 0.1f;
246
247 parms.maxPersistantManifoldPoolSize = 0f;
248 parms.shouldDisableContactPoolDynamicAllocation = ConfigurationParameters.numericTrue;
249 parms.shouldForceUpdateAllAabbs = ConfigurationParameters.numericFalse;
250 parms.shouldRandomizeSolverOrder = ConfigurationParameters.numericFalse;
251 parms.shouldSplitSimulationIslands = ConfigurationParameters.numericFalse;
252 parms.shouldEnableFrictionCaching = ConfigurationParameters.numericFalse;
253 parms.numberOfSolverIterations = 0f; // means use default
227 254
228 if (config != null) 255 if (config != null)
229 { 256 {
@@ -265,14 +292,40 @@ public class BSScene : PhysicsScene, IPhysicsParameters
265 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction); 292 parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
266 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution); 293 parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
267 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction); 294 parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
295 parms.avatarRestitution = pConfig.GetFloat("AvatarRestitution", parms.avatarRestitution);
268 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity); 296 parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
269 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius); 297 parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
270 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight); 298 parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
299 parms.avatarContactProcessingThreshold = pConfig.GetFloat("AvatarContactProcessingThreshold", parms.avatarContactProcessingThreshold);
300
301 parms.maxPersistantManifoldPoolSize = pConfig.GetFloat("MaxPersistantManifoldPoolSize", parms.maxPersistantManifoldPoolSize);
302 parms.shouldDisableContactPoolDynamicAllocation = ParamBoolean(pConfig, "ShouldDisableContactPoolDynamicAllocation", parms.shouldDisableContactPoolDynamicAllocation);
303 parms.shouldForceUpdateAllAabbs = ParamBoolean(pConfig, "ShouldForceUpdateAllAabbs", parms.shouldForceUpdateAllAabbs);
304 parms.shouldRandomizeSolverOrder = ParamBoolean(pConfig, "ShouldRandomizeSolverOrder", parms.shouldRandomizeSolverOrder);
305 parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
306 parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
307 parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
271 } 308 }
272 } 309 }
273 m_params[0] = parms; 310 m_params[0] = parms;
274 } 311 }
275 312
313 // A helper function that handles a true/false parameter and returns the proper float number encoding
314 float ParamBoolean(IConfig config, string parmName, float deflt)
315 {
316 float ret = deflt;
317 if (config.Contains(parmName))
318 {
319 ret = ConfigurationParameters.numericFalse;
320 if (config.GetBoolean(parmName, false))
321 {
322 ret = ConfigurationParameters.numericTrue;
323 }
324 }
325 return ret;
326 }
327
328
276 // Called directly from unmanaged code so don't do much 329 // Called directly from unmanaged code so don't do much
277 private void BulletLogger(string msg) 330 private void BulletLogger(string msg)
278 { 331 {
@@ -384,6 +437,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
384 } 437 }
385 } 438 }
386 439
440 // The SendCollision's batch up the collisions on the objects. Now push the collisions into the simulator.
441 foreach (BSPrim bsp in m_primsWithCollisions)
442 bsp.SendCollisions();
443 m_primsWithCollisions.Clear();
444 // foreach (BSCharacter bsc in m_avatarsWithCollisions)
445 // bsc.SendCollisions();
446 // This is a kludge to get avatar movement updated. ODE sends collisions even if there isn't any
447 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
448 kvp.Value.SendCollisions();
449 m_avatarsWithCollisions.Clear();
450
387 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 451 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
388 if (updatedEntityCount > 0) 452 if (updatedEntityCount > 0)
389 { 453 {
@@ -391,16 +455,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
391 { 455 {
392 EntityProperties entprop = m_updateArray[ii]; 456 EntityProperties entprop = m_updateArray[ii];
393 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position); 457 // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position);
394 BSCharacter actor;
395 if (m_avatars.TryGetValue(entprop.ID, out actor))
396 {
397 actor.UpdateProperties(entprop);
398 continue;
399 }
400 BSPrim prim; 458 BSPrim prim;
401 if (m_prims.TryGetValue(entprop.ID, out prim)) 459 if (m_prims.TryGetValue(entprop.ID, out prim))
402 { 460 {
403 prim.UpdateProperties(entprop); 461 prim.UpdateProperties(entprop);
462 continue;
463 }
464 BSCharacter actor;
465 if (m_avatars.TryGetValue(entprop.ID, out actor))
466 {
467 actor.UpdateProperties(entprop);
404 } 468 }
405 } 469 }
406 } 470 }
@@ -434,11 +498,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
434 BSPrim prim; 498 BSPrim prim;
435 if (m_prims.TryGetValue(localID, out prim)) { 499 if (m_prims.TryGetValue(localID, out prim)) {
436 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 500 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
501 m_primsWithCollisions.Add(prim);
437 return; 502 return;
438 } 503 }
439 BSCharacter actor; 504 BSCharacter actor;
440 if (m_avatars.TryGetValue(localID, out actor)) { 505 if (m_avatars.TryGetValue(localID, out actor)) {
441 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 506 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
507 m_avatarsWithCollisions.Add(actor);
442 return; 508 return;
443 } 509 }
444 return; 510 return;
@@ -470,12 +536,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
470 536
471 public override void DeleteTerrain() 537 public override void DeleteTerrain()
472 { 538 {
473 m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 539 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
474 } 540 }
475 541
476 public override void Dispose() 542 public override void Dispose()
477 { 543 {
478 m_log.DebugFormat("{0}: Dispose()", LogHeader); 544 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
479 } 545 }
480 546
481 public override Dictionary<uint, float> GetTopColliders() 547 public override Dictionary<uint, float> GetTopColliders()
@@ -699,9 +765,23 @@ public class BSScene : PhysicsScene, IPhysicsParameters
699 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), 765 new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ),
700 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), 766 new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ),
701 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), 767 new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ),
702 // new PhysParameterEntry("CcdMotionThreshold", "" ), 768 new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ),
703 // new PhysParameterEntry("CcdSweptSphereRadius", "" ), 769 new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ),
704 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), 770 new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ),
771 // Can only change the following at initialization time. Change the INI file and reboot.
772 new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"),
773 new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"),
774 new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"),
775 new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"),
776 new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"),
777 new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"),
778 new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"),
779
780 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ),
781 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
782
783 new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ),
784 new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
705 785
706 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), 786 new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ),
707 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 787 new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ),
@@ -710,7 +790,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
710 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), 790 new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ),
711 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), 791 new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ),
712 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 792 new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ),
713 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ) 793 new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ),
794 new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions")
795
714 }; 796 };
715 797
716 #region IPhysicsParameters 798 #region IPhysicsParameters
@@ -733,6 +815,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
733 switch (lparm) 815 switch (lparm)
734 { 816 {
735 case "detailedstats": m_detailedStatsStep = (int)val; break; 817 case "detailedstats": m_detailedStatsStep = (int)val; break;
818
736 case "meshlod": m_meshLOD = (int)val; break; 819 case "meshlod": m_meshLOD = (int)val; break;
737 case "sculptlod": m_sculptLOD = (int)val; break; 820 case "sculptlod": m_sculptLOD = (int)val; break;
738 case "maxsubstep": m_maxSubSteps = (int)val; break; 821 case "maxsubstep": m_maxSubSteps = (int)val; break;
@@ -743,7 +826,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
743 case "defaultdensity": m_params[0].defaultDensity = val; break; 826 case "defaultdensity": m_params[0].defaultDensity = val; break;
744 case "defaultrestitution": m_params[0].defaultRestitution = val; break; 827 case "defaultrestitution": m_params[0].defaultRestitution = val; break;
745 case "collisionmargin": m_params[0].collisionMargin = val; break; 828 case "collisionmargin": m_params[0].collisionMargin = val; break;
746 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, PhysParameterEntry.APPLY_TO_NONE, val); break; 829 case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, localID, val); break;
747 830
748 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break; 831 case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
749 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break; 832 case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
@@ -753,6 +836,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
753 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break; 836 case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
754 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break; 837 case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
755 case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break; 838 case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break;
839 // the following are used only at initialization time so setting them makes no sense
840 // case "maxPersistantmanifoldpoolSize": m_params[0].maxPersistantManifoldPoolSize = val; break;
841 // case "shoulddisablecontactpooldynamicallocation": m_params[0].shouldDisableContactPoolDynamicAllocation = val; break;
842 // case "shouldforceupdateallaabbs": m_params[0].shouldForceUpdateAllAabbs = val; break;
843 // case "shouldrandomizesolverorder": m_params[0].shouldRandomizeSolverOrder = val; break;
844 // case "shouldsplitsimulationislands": m_params[0].shouldSplitSimulationIslands = val; break;
845 // case "shouldenablefrictioncaching": m_params[0].shouldEnableFrictionCaching = val; break;
846 // case "numberofsolveriterations": m_params[0].numberOfSolverIterations = val; break;
847
848 case "friction": TaintedUpdateParameter(lparm, localID, val); break;
849 case "restitution": TaintedUpdateParameter(lparm, localID, val); break;
756 850
757 // set a terrain physical feature and cause terrain to be recalculated 851 // set a terrain physical feature and cause terrain to be recalculated
758 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break; 852 case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
@@ -764,6 +858,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
764 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break; 858 case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
765 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break; 859 case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
766 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break; 860 case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
861 case "avatarcontactprocessingthreshold": UpdateParameterAvatars(ref m_params[0].avatarContactProcessingThreshold, "avatar", localID, val); break;
767 862
768 default: ret = false; break; 863 default: ret = false; break;
769 } 864 }
@@ -856,6 +951,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
856 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break; 951 case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
857 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break; 952 case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
858 case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break; 953 case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break;
954 case "maxPersistantmanifoldpoolSize": val = m_params[0].maxPersistantManifoldPoolSize; break;
955 case "shoulddisablecontactpooldynamicallocation": val = m_params[0].shouldDisableContactPoolDynamicAllocation; break;
956 case "shouldforceupdateallaabbs": val = m_params[0].shouldForceUpdateAllAabbs; break;
957 case "shouldrandomizesolverorder": val = m_params[0].shouldRandomizeSolverOrder; break;
958 case "shouldsplitsimulationislands": val = m_params[0].shouldSplitSimulationIslands; break;
959 case "shouldenablefrictioncaching": val = m_params[0].shouldEnableFrictionCaching; break;
960 case "numberofsolveriterations": val = m_params[0].numberOfSolverIterations; break;
859 961
860 case "terrainfriction": val = m_params[0].terrainFriction; break; 962 case "terrainfriction": val = m_params[0].terrainFriction; break;
861 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break; 963 case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
@@ -866,6 +968,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
866 case "avatarrestitution": val = m_params[0].avatarRestitution; break; 968 case "avatarrestitution": val = m_params[0].avatarRestitution; break;
867 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break; 969 case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
868 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break; 970 case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
971 case "avatarcontactprocessingthreshold": val = m_params[0].avatarContactProcessingThreshold; break;
869 default: ret = false; break; 972 default: ret = false; break;
870 973
871 } 974 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index d12bd7d..086f0dc 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -132,6 +132,15 @@ public struct ConfigurationParameters
132 public float avatarRestitution; 132 public float avatarRestitution;
133 public float avatarCapsuleRadius; 133 public float avatarCapsuleRadius;
134 public float avatarCapsuleHeight; 134 public float avatarCapsuleHeight;
135 public float avatarContactProcessingThreshold;
136
137 public float maxPersistantManifoldPoolSize;
138 public float shouldDisableContactPoolDynamicAllocation;
139 public float shouldForceUpdateAllAabbs;
140 public float shouldRandomizeSolverOrder;
141 public float shouldSplitSimulationIslands;
142 public float shouldEnableFrictionCaching;
143 public float numberOfSolverIterations;
135 144
136 public const float numericTrue = 1f; 145 public const float numericTrue = 1f;
137 public const float numericFalse = 0f; 146 public const float numericFalse = 0f;
@@ -149,16 +158,16 @@ public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
149 int maxUpdates, IntPtr updateArray); 158 int maxUpdates, IntPtr updateArray);
150 159
151[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 160[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
152public static extern bool UpdateParameter(uint worldID, uint localID,
153 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
154
155[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
156public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 161public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
157 162
158[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 163[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
159public static extern void Shutdown(uint worldID); 164public static extern void Shutdown(uint worldID);
160 165
166[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
167public static extern bool UpdateParameter(uint worldID, uint localID,
168 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
161 169
170// ===============================================================================
162[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 171[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
163public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 172public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
164 out int updatedEntityCount, 173 out int updatedEntityCount,
@@ -240,6 +249,7 @@ public static extern bool HasObject(uint worldID, uint id);
240[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 249[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
241public static extern bool DestroyObject(uint worldID, uint id); 250public static extern bool DestroyObject(uint worldID, uint id);
242 251
252// ===============================================================================
243[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 253[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
244public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin); 254public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
245 255
@@ -249,6 +259,7 @@ public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vec
249[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 259[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
250public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); 260public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
251 261
262// ===============================================================================
252[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 263[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
253public static extern void DumpBulletStatistics(); 264public static extern void DumpBulletStatistics();
254 265