aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs135
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs12
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs)13
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs)4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs568
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs136
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs273
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs260
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs20
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs325
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs198
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs429
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs23
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs26
-rw-r--r--OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs9
16 files changed, 1592 insertions, 843 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index a041ba8..2a5397e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -34,7 +34,7 @@ using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : BSPhysObject 37public sealed class BSCharacter : BSPhysObject
38{ 38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
@@ -97,28 +97,14 @@ public class BSCharacter : BSPhysObject
97 // set _avatarVolume and _mass based on capsule size, _density and Scale 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
98 ComputeAvatarVolumeAndMass(); 98 ComputeAvatarVolumeAndMass();
99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw); 100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
101
102 ShapeData shapeData = new ShapeData();
103 shapeData.ID = LocalID;
104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity;
108 shapeData.Size = Scale; // capsule is a native shape but scale is not just <1,1,1>
109 shapeData.Scale = Scale;
110 shapeData.Mass = _mass;
111 shapeData.Buoyancy = _buoyancy;
112 shapeData.Static = ShapeData.numericFalse;
113 shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
114 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
115 101
116 // do actual create at taint time 102 // do actual create at taint time
117 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 103 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
118 { 104 {
119 DetailLog("{0},BSCharacter.create,taint", LocalID); 105 DetailLog("{0},BSCharacter.create,taint", LocalID);
120 // New body and shape into BSBody and BSShape 106 // New body and shape into BSBody and BSShape
121 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null); 107 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
122 108
123 SetPhysicalProperties(); 109 SetPhysicalProperties();
124 }); 110 });
@@ -131,46 +117,45 @@ public class BSCharacter : BSPhysObject
131 DetailLog("{0},BSCharacter.Destroy", LocalID); 117 DetailLog("{0},BSCharacter.Destroy", LocalID);
132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 118 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
133 { 119 {
134 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); 120 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
135 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); 121 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
136 }); 122 });
137 } 123 }
138 124
139 private void SetPhysicalProperties() 125 private void SetPhysicalProperties()
140 { 126 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); 127 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
142 128
143 ZeroMotion(); 129 ZeroMotion();
144 ForcePosition = _position; 130 ForcePosition = _position;
145 // Set the velocity and compute the proper friction 131 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity; 132 ForceVelocity = _velocity;
147 133
148 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); 134 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
149 BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin); 135 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
150 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); 136 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
151 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 137 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
152 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 138 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
153 { 139 {
154 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 140 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
155 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 141 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
156 } 142 }
157 143
158 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); 144 UpdatePhysicalMassProperties(RawMass);
159 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
160 145
161 // Make so capsule does not fall over 146 // Make so capsule does not fall over
162 BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero); 147 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
163 148
164 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 149 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
165 150
166 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); 151 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
167 152
168 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 153 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
169 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION); 154 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
170 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); 155 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
171 156
172 // Do this after the object has been added to the world 157 // Do this after the object has been added to the world
173 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, 158 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
174 (uint)CollisionFilterGroups.AvatarFilter, 159 (uint)CollisionFilterGroups.AvatarFilter,
175 (uint)CollisionFilterGroups.AvatarMask); 160 (uint)CollisionFilterGroups.AvatarMask);
176 } 161 }
@@ -196,13 +181,12 @@ public class BSCharacter : BSPhysObject
196 ComputeAvatarScale(_size); 181 ComputeAvatarScale(_size);
197 ComputeAvatarVolumeAndMass(); 182 ComputeAvatarVolumeAndMass();
198 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", 183 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
199 LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw); 184 LocalID, Scale, _avatarDensity, _avatarVolume, RawMass);
200 185
201 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 186 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
202 { 187 {
203 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); 188 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
204 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); 189 UpdatePhysicalMassProperties(RawMass);
205 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
206 }); 190 });
207 191
208 } 192 }
@@ -214,6 +198,11 @@ public class BSCharacter : BSPhysObject
214 { 198 {
215 set { BaseShape = value; } 199 set { BaseShape = value; }
216 } 200 }
201 // I want the physics engine to make an avatar capsule
202 public override ShapeData.PhysicsShapeType PreferredPhysicalShape
203 {
204 get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; }
205 }
217 206
218 public override bool Grabbed { 207 public override bool Grabbed {
219 set { _grabbed = value; } 208 set { _grabbed = value; }
@@ -236,16 +225,22 @@ public class BSCharacter : BSPhysObject
236 _rotationalVelocity = OMV.Vector3.Zero; 225 _rotationalVelocity = OMV.Vector3.Zero;
237 226
238 // Zero some other properties directly into the physics engine 227 // Zero some other properties directly into the physics engine
239 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero); 228 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
240 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero); 229 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
241 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); 230 BulletSimAPI.SetInterpolationVelocity2(PhysBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
242 BulletSimAPI.ClearForces2(BSBody.ptr); 231 BulletSimAPI.ClearForces2(PhysBody.ptr);
243 } 232 }
244 233
245 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 234 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
246 235
236 public override OMV.Vector3 RawPosition
237 {
238 get { return _position; }
239 set { _position = value; }
240 }
247 public override OMV.Vector3 Position { 241 public override OMV.Vector3 Position {
248 get { 242 get {
243 // Don't refetch the position because this function is called a zillion times
249 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 244 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
250 return _position; 245 return _position;
251 } 246 }
@@ -256,19 +251,19 @@ public class BSCharacter : BSPhysObject
256 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 251 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
257 { 252 {
258 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 253 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
259 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 254 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
260 }); 255 });
261 } 256 }
262 } 257 }
263 public override OMV.Vector3 ForcePosition { 258 public override OMV.Vector3 ForcePosition {
264 get { 259 get {
265 _position = BulletSimAPI.GetPosition2(BSBody.ptr); 260 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
266 return _position; 261 return _position;
267 } 262 }
268 set { 263 set {
269 _position = value; 264 _position = value;
270 PositionSanityCheck(); 265 PositionSanityCheck();
271 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 266 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
272 } 267 }
273 } 268 }
274 269
@@ -312,15 +307,11 @@ public class BSCharacter : BSPhysObject
312 { 307 {
313 // The new position value must be pushed into the physics engine but we can't 308 // The new position value must be pushed into the physics engine but we can't
314 // just assign to "Position" because of potential call loops. 309 // just assign to "Position" because of potential call loops.
315 BSScene.TaintCallback sanityOperation = delegate() 310 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
316 { 311 {
317 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 312 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
318 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 313 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
319 }; 314 });
320 if (inTaintTime)
321 sanityOperation();
322 else
323 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
324 ret = true; 315 ret = true;
325 } 316 }
326 return ret; 317 return ret;
@@ -329,7 +320,14 @@ public class BSCharacter : BSPhysObject
329 public override float Mass { get { return _mass; } } 320 public override float Mass { get { return _mass; } }
330 321
331 // used when we only want this prim's mass and not the linkset thing 322 // used when we only want this prim's mass and not the linkset thing
332 public override float MassRaw { get {return _mass; } } 323 public override float RawMass {
324 get {return _mass; }
325 }
326 public override void UpdatePhysicalMassProperties(float physMass)
327 {
328 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
329 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
330 }
333 331
334 public override OMV.Vector3 Force { 332 public override OMV.Vector3 Force {
335 get { return _force; } 333 get { return _force; }
@@ -339,7 +337,7 @@ public class BSCharacter : BSPhysObject
339 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 337 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
340 { 338 {
341 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 339 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
342 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 340 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
343 }); 341 });
344 } 342 }
345 } 343 }
@@ -378,7 +376,7 @@ public class BSCharacter : BSPhysObject
378 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 376 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
379 { 377 {
380 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 378 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
381 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); 379 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
382 } 380 }
383 } 381 }
384 else 382 else
@@ -386,15 +384,15 @@ public class BSCharacter : BSPhysObject
386 if (_currentFriction != PhysicsScene.Params.avatarFriction) 384 if (_currentFriction != PhysicsScene.Params.avatarFriction)
387 { 385 {
388 _currentFriction = PhysicsScene.Params.avatarFriction; 386 _currentFriction = PhysicsScene.Params.avatarFriction;
389 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); 387 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
390 } 388 }
391 } 389 }
392 _velocity = value; 390 _velocity = value;
393 // Remember the set velocity so we can suppress the reduction by friction, ... 391 // Remember the set velocity so we can suppress the reduction by friction, ...
394 _appliedVelocity = value; 392 _appliedVelocity = value;
395 393
396 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 394 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
397 BulletSimAPI.Activate2(BSBody.ptr, true); 395 BulletSimAPI.Activate2(PhysBody.ptr, true);
398 } 396 }
399 } 397 }
400 public override OMV.Vector3 Torque { 398 public override OMV.Vector3 Torque {
@@ -411,6 +409,11 @@ public class BSCharacter : BSPhysObject
411 get { return _acceleration; } 409 get { return _acceleration; }
412 set { _acceleration = value; } 410 set { _acceleration = value; }
413 } 411 }
412 public override OMV.Quaternion RawOrientation
413 {
414 get { return _orientation; }
415 set { _orientation = value; }
416 }
414 public override OMV.Quaternion Orientation { 417 public override OMV.Quaternion Orientation {
415 get { return _orientation; } 418 get { return _orientation; }
416 set { 419 set {
@@ -419,7 +422,7 @@ public class BSCharacter : BSPhysObject
419 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 422 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
420 { 423 {
421 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 424 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
422 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 425 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
423 }); 426 });
424 } 427 }
425 } 428 }
@@ -428,13 +431,13 @@ public class BSCharacter : BSPhysObject
428 { 431 {
429 get 432 get
430 { 433 {
431 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); 434 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
432 return _orientation; 435 return _orientation;
433 } 436 }
434 set 437 set
435 { 438 {
436 _orientation = value; 439 _orientation = value;
437 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 440 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
438 } 441 }
439 } 442 }
440 public override int PhysicsActorType { 443 public override int PhysicsActorType {
@@ -493,9 +496,9 @@ public class BSCharacter : BSPhysObject
493 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 496 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
494 { 497 {
495 if (_floatOnWater) 498 if (_floatOnWater)
496 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 499 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
497 else 500 else
498 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 501 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
499 }); 502 });
500 } 503 }
501 } 504 }
@@ -528,7 +531,7 @@ public class BSCharacter : BSPhysObject
528 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 531 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
529 // Buoyancy is faked by changing the gravity applied to the object 532 // Buoyancy is faked by changing the gravity applied to the object
530 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 533 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
531 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); 534 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
532 } 535 }
533 } 536 }
534 537
@@ -574,7 +577,7 @@ public class BSCharacter : BSPhysObject
574 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() 577 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
575 { 578 {
576 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 579 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
577 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 580 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
578 }); 581 });
579 } 582 }
580 else 583 else
@@ -642,7 +645,7 @@ public class BSCharacter : BSPhysObject
642 // That's just the way they are defined. 645 // That's just the way they are defined.
643 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); 646 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
644 _velocity = avVel; 647 _velocity = avVel;
645 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); 648 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
646 } 649 }
647 650
648 // Tell the linkset about value changes 651 // Tell the linkset about value changes
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index f017cdd..65fac00 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -42,6 +42,12 @@ public abstract class BSConstraint : IDisposable
42 protected BulletConstraint m_constraint; 42 protected BulletConstraint m_constraint;
43 protected bool m_enabled = false; 43 protected bool m_enabled = false;
44 44
45 public BulletBody Body1 { get { return m_body1; } }
46 public BulletBody Body2 { get { return m_body2; } }
47 public BulletConstraint Constraint { get { return m_constraint; } }
48 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } }
50
45 public BSConstraint() 51 public BSConstraint()
46 { 52 {
47 } 53 }
@@ -64,12 +70,6 @@ public abstract class BSConstraint : IDisposable
64 } 70 }
65 } 71 }
66 72
67 public BulletBody Body1 { get { return m_body1; } }
68 public BulletBody Body2 { get { return m_body2; } }
69 public BulletConstraint Constraint { get { return m_constraint; } }
70 public abstract ConstraintType Type { get; }
71
72
73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
74 { 74 {
75 bool ret = false; 75 bool ret = false;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 3306a97..23ef052 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -32,14 +32,14 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public class BS6DofConstraint : BSConstraint 35public sealed class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38 38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
42 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@@ -58,7 +58,7 @@ public class BS6DofConstraint : BSConstraint
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
59 } 59 }
60 60
61 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 { 64 {
@@ -71,8 +71,7 @@ public class BS6DofConstraint : BSConstraint
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 "[BULLETSIM 6DOF CONSTRAINT]", world.worldID, 74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
75 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
76 m_enabled = false; 75 m_enabled = false;
77 } 76 }
78 else 77 else
@@ -135,7 +134,11 @@ public class BS6DofConstraint : BSConstraint
135 bool ret = false; 134 bool ret = false;
136 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
137 if (m_enabled) 136 if (m_enabled)
137 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 }
139 return ret; 142 return ret;
140 } 143 }
141 144
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index 22ea367..a9fd826 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36public class BSConstraintCollection : IDisposable 36public sealed class BSConstraintCollection : IDisposable
37{ 37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; 39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
@@ -143,8 +143,6 @@ public class BSConstraintCollection : IDisposable
143 // Return 'true' if any constraints were destroyed. 143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1) 144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 { 145 {
146 // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
147
148 List<BSConstraint> toRemove = new List<BSConstraint>(); 146 List<BSConstraint> toRemove = new List<BSConstraint>();
149 uint lookingID = body1.ID; 147 uint lookingID = body1.ID;
150 lock (m_constraints) 148 lock (m_constraints)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index 7c8a215..ed3ffa7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -32,11 +32,11 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 38
39 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 117c878..819635a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -52,7 +52,7 @@ using OpenSim.Region.Physics.Manager;
52 52
53namespace OpenSim.Region.Physics.BulletSPlugin 53namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public sealed class BSDynamics
56 { 56 {
57 private BSScene PhysicsScene { get; set; } 57 private BSScene PhysicsScene { get; set; }
58 // the prim this dynamic controller belongs to 58 // the prim this dynamic controller belongs to
@@ -72,8 +72,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
72 // LIMIT_ROLL_ONLY 72 // LIMIT_ROLL_ONLY
73 private Vector3 m_BlockingEndPoint = Vector3.Zero; 73 private Vector3 m_BlockingEndPoint = Vector3.Zero;
74 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 74 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
75 private Quaternion m_referenceFrame = Quaternion.Identity;
76
75 // Linear properties 77 // Linear properties
76 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 78 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
79 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 80 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
78 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body 81 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
79 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 82 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
@@ -86,7 +89,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
86 89
87 //Angular properties 90 //Angular properties
88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 91 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
89 private int m_angularMotorApply = 0; // application frame counter 92 // private int m_angularMotorApply = 0; // application frame counter
90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 93 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
91 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 94 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
92 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 95 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
@@ -95,19 +98,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 98 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
96 99
97 //Deflection properties 100 //Deflection properties
98 // private float m_angularDeflectionEfficiency = 0; 101 private float m_angularDeflectionEfficiency = 0;
99 // private float m_angularDeflectionTimescale = 0; 102 private float m_angularDeflectionTimescale = 0;
100 // private float m_linearDeflectionEfficiency = 0; 103 private float m_linearDeflectionEfficiency = 0;
101 // private float m_linearDeflectionTimescale = 0; 104 private float m_linearDeflectionTimescale = 0;
102 105
103 //Banking properties 106 //Banking properties
104 // private float m_bankingEfficiency = 0; 107 private float m_bankingEfficiency = 0;
105 // private float m_bankingMix = 0; 108 private float m_bankingMix = 0;
106 // private float m_bankingTimescale = 0; 109 private float m_bankingTimescale = 0;
107 110
108 //Hover and Buoyancy properties 111 //Hover and Buoyancy properties
109 private float m_VhoverHeight = 0f; 112 private float m_VhoverHeight = 0f;
110// private float m_VhoverEfficiency = 0f; 113 private float m_VhoverEfficiency = 0f;
111 private float m_VhoverTimescale = 0f; 114 private float m_VhoverTimescale = 0f;
112 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 115 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
113 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 116 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
@@ -138,10 +141,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
138 switch (pParam) 141 switch (pParam)
139 { 142 {
140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 143 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
141 // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 144 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
142 break; 145 break;
143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 146 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
144 // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 147 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
145 break; 148 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 149 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 150 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -150,20 +153,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
150 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 153 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
151 break; 154 break;
152 case Vehicle.BANKING_EFFICIENCY: 155 case Vehicle.BANKING_EFFICIENCY:
153 // m_bankingEfficiency = Math.Max(pValue, 0.01f); 156 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
154 break; 157 break;
155 case Vehicle.BANKING_MIX: 158 case Vehicle.BANKING_MIX:
156 // m_bankingMix = Math.Max(pValue, 0.01f); 159 m_bankingMix = Math.Max(pValue, 0.01f);
157 break; 160 break;
158 case Vehicle.BANKING_TIMESCALE: 161 case Vehicle.BANKING_TIMESCALE:
159 // m_bankingTimescale = Math.Max(pValue, 0.01f); 162 m_bankingTimescale = Math.Max(pValue, 0.01f);
160 break; 163 break;
161 case Vehicle.BUOYANCY: 164 case Vehicle.BUOYANCY:
162 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 165 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
163 break; 166 break;
164// case Vehicle.HOVER_EFFICIENCY: 167 case Vehicle.HOVER_EFFICIENCY:
165// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 168 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
166// break; 169 break;
167 case Vehicle.HOVER_HEIGHT: 170 case Vehicle.HOVER_HEIGHT:
168 m_VhoverHeight = pValue; 171 m_VhoverHeight = pValue;
169 break; 172 break;
@@ -171,10 +174,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
171 m_VhoverTimescale = Math.Max(pValue, 0.01f); 174 m_VhoverTimescale = Math.Max(pValue, 0.01f);
172 break; 175 break;
173 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 176 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
174 // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 177 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
175 break; 178 break;
176 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 179 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
177 // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 180 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
178 break; 181 break;
179 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 182 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
180 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 183 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -196,7 +199,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
196 break; 199 break;
197 case Vehicle.ANGULAR_MOTOR_DIRECTION: 200 case Vehicle.ANGULAR_MOTOR_DIRECTION:
198 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 201 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
199 m_angularMotorApply = 10; 202 // m_angularMotorApply = 100;
200 break; 203 break;
201 case Vehicle.LINEAR_FRICTION_TIMESCALE: 204 case Vehicle.LINEAR_FRICTION_TIMESCALE:
202 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 205 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
@@ -206,7 +209,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
206 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 209 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
207 break; 210 break;
208 case Vehicle.LINEAR_MOTOR_OFFSET: 211 case Vehicle.LINEAR_MOTOR_OFFSET:
209 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 212 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
210 break; 213 break;
211 214
212 } 215 }
@@ -221,15 +224,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
221 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 224 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
222 break; 225 break;
223 case Vehicle.ANGULAR_MOTOR_DIRECTION: 226 case Vehicle.ANGULAR_MOTOR_DIRECTION:
224 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
225 // Limit requested angular speed to 2 rps= 4 pi rads/sec 227 // Limit requested angular speed to 2 rps= 4 pi rads/sec
226 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; 228 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f));
227 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; 229 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
228 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; 230 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
229 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; 231 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
230 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; 232 // m_angularMotorApply = 100;
231 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
232 m_angularMotorApply = 10;
233 break; 233 break;
234 case Vehicle.LINEAR_FRICTION_TIMESCALE: 234 case Vehicle.LINEAR_FRICTION_TIMESCALE:
235 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 235 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -239,7 +239,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
239 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 239 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
240 break; 240 break;
241 case Vehicle.LINEAR_MOTOR_OFFSET: 241 case Vehicle.LINEAR_MOTOR_OFFSET:
242 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 242 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
243 break; 243 break;
244 case Vehicle.BLOCK_EXIT: 244 case Vehicle.BLOCK_EXIT:
245 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 245 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -253,7 +253,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
253 switch (pParam) 253 switch (pParam)
254 { 254 {
255 case Vehicle.REFERENCE_FRAME: 255 case Vehicle.REFERENCE_FRAME:
256 // m_referenceFrame = pValue; 256 m_referenceFrame = pValue;
257 break; 257 break;
258 case Vehicle.ROLL_FRAME: 258 case Vehicle.ROLL_FRAME:
259 m_RollreferenceFrame = pValue; 259 m_RollreferenceFrame = pValue;
@@ -265,21 +265,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 { 265 {
266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
267 VehicleFlag parm = (VehicleFlag)pParam; 267 VehicleFlag parm = (VehicleFlag)pParam;
268 if (remove) 268 if (pParam == -1)
269 m_flags = (VehicleFlag)0;
270 else
269 { 271 {
270 if (pParam == -1) 272 if (remove)
271 {
272 m_flags = (VehicleFlag)0;
273 }
274 else
275 {
276 m_flags &= ~parm; 273 m_flags &= ~parm;
277 } 274 else
278 } 275 m_flags |= parm;
279 else {
280 m_flags |= parm;
281 } 276 }
282 }//end ProcessVehicleFlags 277 }
283 278
284 internal void ProcessTypeChange(Vehicle pType) 279 internal void ProcessTypeChange(Vehicle pType)
285 { 280 {
@@ -288,99 +283,142 @@ namespace OpenSim.Region.Physics.BulletSPlugin
288 Type = pType; 283 Type = pType;
289 switch (pType) 284 switch (pType)
290 { 285 {
291 case Vehicle.TYPE_NONE: 286 case Vehicle.TYPE_NONE:
292 m_linearFrictionTimescale = new Vector3(0, 0, 0);
293 m_angularFrictionTimescale = new Vector3(0, 0, 0);
294 m_linearMotorDirection = Vector3.Zero; 287 m_linearMotorDirection = Vector3.Zero;
295 m_linearMotorTimescale = 0; 288 m_linearMotorTimescale = 0;
296 m_linearMotorDecayTimescale = 0; 289 m_linearMotorDecayTimescale = 0;
290 m_linearFrictionTimescale = new Vector3(0, 0, 0);
291
297 m_angularMotorDirection = Vector3.Zero; 292 m_angularMotorDirection = Vector3.Zero;
298 m_angularMotorTimescale = 0;
299 m_angularMotorDecayTimescale = 0; 293 m_angularMotorDecayTimescale = 0;
294 m_angularMotorTimescale = 0;
295 m_angularFrictionTimescale = new Vector3(0, 0, 0);
296
300 m_VhoverHeight = 0; 297 m_VhoverHeight = 0;
298 m_VhoverEfficiency = 0;
301 m_VhoverTimescale = 0; 299 m_VhoverTimescale = 0;
302 m_VehicleBuoyancy = 0; 300 m_VehicleBuoyancy = 0;
301
302 m_linearDeflectionEfficiency = 1;
303 m_linearDeflectionTimescale = 1;
304
305 m_angularDeflectionEfficiency = 0;
306 m_angularDeflectionTimescale = 1000;
307
308 m_verticalAttractionEfficiency = 0;
309 m_verticalAttractionTimescale = 0;
310
311 m_bankingEfficiency = 0;
312 m_bankingTimescale = 1000;
313 m_bankingMix = 1;
314
315 m_referenceFrame = Quaternion.Identity;
303 m_flags = (VehicleFlag)0; 316 m_flags = (VehicleFlag)0;
304 break; 317 break;
305 318
306 case Vehicle.TYPE_SLED: 319 case Vehicle.TYPE_SLED:
307 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
308 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
309 m_linearMotorDirection = Vector3.Zero; 320 m_linearMotorDirection = Vector3.Zero;
310 m_linearMotorTimescale = 1000; 321 m_linearMotorTimescale = 1000;
311 m_linearMotorDecayTimescale = 120; 322 m_linearMotorDecayTimescale = 120;
323 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
324
312 m_angularMotorDirection = Vector3.Zero; 325 m_angularMotorDirection = Vector3.Zero;
313 m_angularMotorTimescale = 1000; 326 m_angularMotorTimescale = 1000;
314 m_angularMotorDecayTimescale = 120; 327 m_angularMotorDecayTimescale = 120;
328 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
329
315 m_VhoverHeight = 0; 330 m_VhoverHeight = 0;
316// m_VhoverEfficiency = 1; 331 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
317 m_VhoverTimescale = 10; 332 m_VhoverTimescale = 10;
318 m_VehicleBuoyancy = 0; 333 m_VehicleBuoyancy = 0;
319 // m_linearDeflectionEfficiency = 1; 334
320 // m_linearDeflectionTimescale = 1; 335 m_linearDeflectionEfficiency = 1;
321 // m_angularDeflectionEfficiency = 1; 336 m_linearDeflectionTimescale = 1;
322 // m_angularDeflectionTimescale = 1000; 337
323 // m_bankingEfficiency = 0; 338 m_angularDeflectionEfficiency = 1;
324 // m_bankingMix = 1; 339 m_angularDeflectionTimescale = 1000;
325 // m_bankingTimescale = 10; 340
326 // m_referenceFrame = Quaternion.Identity; 341 m_verticalAttractionEfficiency = 0;
342 m_verticalAttractionTimescale = 0;
343
344 m_bankingEfficiency = 0;
345 m_bankingTimescale = 10;
346 m_bankingMix = 1;
347
348 m_referenceFrame = Quaternion.Identity;
327 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 349 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
328 m_flags &= 350 m_flags &=
329 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 351 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
330 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 352 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
331 break; 353 break;
332 case Vehicle.TYPE_CAR: 354 case Vehicle.TYPE_CAR:
333 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
334 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
335 m_linearMotorDirection = Vector3.Zero; 355 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1; 356 m_linearMotorTimescale = 1;
337 m_linearMotorDecayTimescale = 60; 357 m_linearMotorDecayTimescale = 60;
358 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
359
338 m_angularMotorDirection = Vector3.Zero; 360 m_angularMotorDirection = Vector3.Zero;
339 m_angularMotorTimescale = 1; 361 m_angularMotorTimescale = 1;
340 m_angularMotorDecayTimescale = 0.8f; 362 m_angularMotorDecayTimescale = 0.8f;
363 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
364
341 m_VhoverHeight = 0; 365 m_VhoverHeight = 0;
342// m_VhoverEfficiency = 0; 366 m_VhoverEfficiency = 0;
343 m_VhoverTimescale = 1000; 367 m_VhoverTimescale = 1000;
344 m_VehicleBuoyancy = 0; 368 m_VehicleBuoyancy = 0;
345 // // m_linearDeflectionEfficiency = 1; 369
346 // // m_linearDeflectionTimescale = 2; 370 m_linearDeflectionEfficiency = 1;
347 // // m_angularDeflectionEfficiency = 0; 371 m_linearDeflectionTimescale = 2;
348 // m_angularDeflectionTimescale = 10; 372
373 m_angularDeflectionEfficiency = 0;
374 m_angularDeflectionTimescale = 10;
375
349 m_verticalAttractionEfficiency = 1f; 376 m_verticalAttractionEfficiency = 1f;
350 m_verticalAttractionTimescale = 10f; 377 m_verticalAttractionTimescale = 10f;
351 // m_bankingEfficiency = -0.2f; 378
352 // m_bankingMix = 1; 379 m_bankingEfficiency = -0.2f;
353 // m_bankingTimescale = 1; 380 m_bankingMix = 1;
354 // m_referenceFrame = Quaternion.Identity; 381 m_bankingTimescale = 1;
382
383 m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
385 | VehicleFlag.HOVER_TERRAIN_ONLY
386 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 387 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
356 | VehicleFlag.LIMIT_ROLL_ONLY 388 | VehicleFlag.LIMIT_ROLL_ONLY
357 | VehicleFlag.LIMIT_MOTOR_UP); 389 | VehicleFlag.LIMIT_MOTOR_UP
358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 390 | VehicleFlag.HOVER_UP_ONLY);
359 m_flags |= (VehicleFlag.HOVER_UP_ONLY);
360 break; 391 break;
361 case Vehicle.TYPE_BOAT: 392 case Vehicle.TYPE_BOAT:
362 m_linearFrictionTimescale = new Vector3(10, 3, 2);
363 m_angularFrictionTimescale = new Vector3(10,10,10);
364 m_linearMotorDirection = Vector3.Zero; 393 m_linearMotorDirection = Vector3.Zero;
365 m_linearMotorTimescale = 5; 394 m_linearMotorTimescale = 5;
366 m_linearMotorDecayTimescale = 60; 395 m_linearMotorDecayTimescale = 60;
396 m_linearFrictionTimescale = new Vector3(10, 3, 2);
397
367 m_angularMotorDirection = Vector3.Zero; 398 m_angularMotorDirection = Vector3.Zero;
368 m_angularMotorTimescale = 4; 399 m_angularMotorTimescale = 4;
369 m_angularMotorDecayTimescale = 4; 400 m_angularMotorDecayTimescale = 4;
401 m_angularFrictionTimescale = new Vector3(10,10,10);
402
370 m_VhoverHeight = 0; 403 m_VhoverHeight = 0;
371// m_VhoverEfficiency = 0.5f; 404 m_VhoverEfficiency = 0.5f;
372 m_VhoverTimescale = 2; 405 m_VhoverTimescale = 2;
373 m_VehicleBuoyancy = 1; 406 m_VehicleBuoyancy = 1;
374 // m_linearDeflectionEfficiency = 0.5f; 407
375 // m_linearDeflectionTimescale = 3; 408 m_linearDeflectionEfficiency = 0.5f;
376 // m_angularDeflectionEfficiency = 0.5f; 409 m_linearDeflectionTimescale = 3;
377 // m_angularDeflectionTimescale = 5; 410
411 m_angularDeflectionEfficiency = 0.5f;
412 m_angularDeflectionTimescale = 5;
413
378 m_verticalAttractionEfficiency = 0.5f; 414 m_verticalAttractionEfficiency = 0.5f;
379 m_verticalAttractionTimescale = 5f; 415 m_verticalAttractionTimescale = 5f;
380 // m_bankingEfficiency = -0.3f; 416
381 // m_bankingMix = 0.8f; 417 m_bankingEfficiency = -0.3f;
382 // m_bankingTimescale = 1; 418 m_bankingMix = 0.8f;
383 // m_referenceFrame = Quaternion.Identity; 419 m_bankingTimescale = 1;
420
421 m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 422 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
385 | VehicleFlag.HOVER_GLOBAL_HEIGHT 423 | VehicleFlag.HOVER_GLOBAL_HEIGHT
386 | VehicleFlag.LIMIT_ROLL_ONLY 424 | VehicleFlag.LIMIT_ROLL_ONLY
@@ -390,28 +428,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
390 | VehicleFlag.HOVER_WATER_ONLY); 428 | VehicleFlag.HOVER_WATER_ONLY);
391 break; 429 break;
392 case Vehicle.TYPE_AIRPLANE: 430 case Vehicle.TYPE_AIRPLANE:
393 m_linearFrictionTimescale = new Vector3(200, 10, 5);
394 m_angularFrictionTimescale = new Vector3(20, 20, 20);
395 m_linearMotorDirection = Vector3.Zero; 431 m_linearMotorDirection = Vector3.Zero;
396 m_linearMotorTimescale = 2; 432 m_linearMotorTimescale = 2;
397 m_linearMotorDecayTimescale = 60; 433 m_linearMotorDecayTimescale = 60;
434 m_linearFrictionTimescale = new Vector3(200, 10, 5);
435
398 m_angularMotorDirection = Vector3.Zero; 436 m_angularMotorDirection = Vector3.Zero;
399 m_angularMotorTimescale = 4; 437 m_angularMotorTimescale = 4;
400 m_angularMotorDecayTimescale = 4; 438 m_angularMotorDecayTimescale = 4;
439 m_angularFrictionTimescale = new Vector3(20, 20, 20);
440
401 m_VhoverHeight = 0; 441 m_VhoverHeight = 0;
402// m_VhoverEfficiency = 0.5f; 442 m_VhoverEfficiency = 0.5f;
403 m_VhoverTimescale = 1000; 443 m_VhoverTimescale = 1000;
404 m_VehicleBuoyancy = 0; 444 m_VehicleBuoyancy = 0;
405 // m_linearDeflectionEfficiency = 0.5f; 445
406 // m_linearDeflectionTimescale = 3; 446 m_linearDeflectionEfficiency = 0.5f;
407 // m_angularDeflectionEfficiency = 1; 447 m_linearDeflectionTimescale = 3;
408 // m_angularDeflectionTimescale = 2; 448
449 m_angularDeflectionEfficiency = 1;
450 m_angularDeflectionTimescale = 2;
451
409 m_verticalAttractionEfficiency = 0.9f; 452 m_verticalAttractionEfficiency = 0.9f;
410 m_verticalAttractionTimescale = 2f; 453 m_verticalAttractionTimescale = 2f;
411 // m_bankingEfficiency = 1; 454
412 // m_bankingMix = 0.7f; 455 m_bankingEfficiency = 1;
413 // m_bankingTimescale = 2; 456 m_bankingMix = 0.7f;
414 // m_referenceFrame = Quaternion.Identity; 457 m_bankingTimescale = 2;
458
459 m_referenceFrame = Quaternion.Identity;
415 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 460 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
416 | VehicleFlag.HOVER_TERRAIN_ONLY 461 | VehicleFlag.HOVER_TERRAIN_ONLY
417 | VehicleFlag.HOVER_GLOBAL_HEIGHT 462 | VehicleFlag.HOVER_GLOBAL_HEIGHT
@@ -421,28 +466,36 @@ namespace OpenSim.Region.Physics.BulletSPlugin
421 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 466 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
422 break; 467 break;
423 case Vehicle.TYPE_BALLOON: 468 case Vehicle.TYPE_BALLOON:
424 m_linearFrictionTimescale = new Vector3(5, 5, 5);
425 m_angularFrictionTimescale = new Vector3(10, 10, 10);
426 m_linearMotorDirection = Vector3.Zero; 469 m_linearMotorDirection = Vector3.Zero;
427 m_linearMotorTimescale = 5; 470 m_linearMotorTimescale = 5;
471 m_linearFrictionTimescale = new Vector3(5, 5, 5);
428 m_linearMotorDecayTimescale = 60; 472 m_linearMotorDecayTimescale = 60;
473
429 m_angularMotorDirection = Vector3.Zero; 474 m_angularMotorDirection = Vector3.Zero;
430 m_angularMotorTimescale = 6; 475 m_angularMotorTimescale = 6;
476 m_angularFrictionTimescale = new Vector3(10, 10, 10);
431 m_angularMotorDecayTimescale = 10; 477 m_angularMotorDecayTimescale = 10;
478
432 m_VhoverHeight = 5; 479 m_VhoverHeight = 5;
433// m_VhoverEfficiency = 0.8f; 480 m_VhoverEfficiency = 0.8f;
434 m_VhoverTimescale = 10; 481 m_VhoverTimescale = 10;
435 m_VehicleBuoyancy = 1; 482 m_VehicleBuoyancy = 1;
436 // m_linearDeflectionEfficiency = 0; 483
437 // m_linearDeflectionTimescale = 5; 484 m_linearDeflectionEfficiency = 0;
438 // m_angularDeflectionEfficiency = 0; 485 m_linearDeflectionTimescale = 5;
439 // m_angularDeflectionTimescale = 5; 486
487 m_angularDeflectionEfficiency = 0;
488 m_angularDeflectionTimescale = 5;
489
440 m_verticalAttractionEfficiency = 1f; 490 m_verticalAttractionEfficiency = 1f;
441 m_verticalAttractionTimescale = 100f; 491 m_verticalAttractionTimescale = 100f;
442 // m_bankingEfficiency = 0; 492
443 // m_bankingMix = 0.7f; 493 m_bankingEfficiency = 0;
444 // m_bankingTimescale = 5; 494 m_bankingMix = 0.7f;
445 // m_referenceFrame = Quaternion.Identity; 495 m_bankingTimescale = 5;
496 m_referenceFrame = Quaternion.Identity;
497
498 m_referenceFrame = Quaternion.Identity;
446 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 499 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
447 | VehicleFlag.HOVER_TERRAIN_ONLY 500 | VehicleFlag.HOVER_TERRAIN_ONLY
448 | VehicleFlag.HOVER_UP_ONLY 501 | VehicleFlag.HOVER_UP_ONLY
@@ -452,21 +505,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
452 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 505 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
453 break; 506 break;
454 } 507 }
455 }//end SetDefaultsForType 508 }
456 509
457 // Some of the properties of this prim may have changed. 510 // Some of the properties of this prim may have changed.
458 // Do any updating needed for a vehicle 511 // Do any updating needed for a vehicle
459 public void Refresh() 512 public void Refresh()
460 { 513 {
461 if (!IsActive) 514 if (IsActive)
462 return; 515 {
463 516 // Friction effects are handled by this vehicle code
464 // Set the prim's inertia to zero. The vehicle code handles that and this 517 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
465 // removes the motion and torque actions introduced by Bullet. 518 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
466 Vector3 inertia = Vector3.Zero; 519 }
467 // comment out for DEBUG test
468 // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
469 // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
470 } 520 }
471 521
472 // One step of the vehicle properties for the next 'pTimestep' seconds. 522 // One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -474,10 +524,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
474 { 524 {
475 if (!IsActive) return; 525 if (!IsActive) return;
476 526
527 // DEBUG
528 // Because Bullet does apply forces to the vehicle, our last computed
529 // linear and angular velocities are not what is happening now.
530 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
531 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
532 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
533 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
534 // END DEBUG
535
477 MoveLinear(pTimestep); 536 MoveLinear(pTimestep);
478 MoveAngular(pTimestep); 537 MoveAngular(pTimestep);
479 LimitRotation(pTimestep); 538 LimitRotation(pTimestep);
480 539
540 // DEBUG: Trying to figure out why Bullet goes crazy when the root prim is moved.
541 // BulletSimAPI.SetInterpolationVelocity2(Prim.BSBody.ptr, m_newVelocity, m_lastAngularVelocity); // DEBUG DEBUG DEBUG
542
481 // remember the position so next step we can limit absolute movement effects 543 // remember the position so next step we can limit absolute movement effects
482 m_lastPositionVector = Prim.ForcePosition; 544 m_lastPositionVector = Prim.ForcePosition;
483 545
@@ -489,62 +551,51 @@ namespace OpenSim.Region.Physics.BulletSPlugin
489 // Also does hover and float. 551 // Also does hover and float.
490 private void MoveLinear(float pTimestep) 552 private void MoveLinear(float pTimestep)
491 { 553 {
492 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates 554 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
493 // m_lastLinearVelocityVector is the speed we are moving in that direction 555 // m_lastLinearVelocityVector is the current speed we are moving in that direction
494 if (m_linearMotorDirection.LengthSquared() > 0.001f) 556 if (m_linearMotorDirection.LengthSquared() > 0.001f)
495 { 557 {
496 Vector3 origDir = m_linearMotorDirection; 558 Vector3 origDir = m_linearMotorDirection;
497 Vector3 origVel = m_lastLinearVelocityVector; 559 Vector3 origVel = m_lastLinearVelocityVector;
560 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
498 561
499 // add drive to body 562 // add drive to body
500 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep); 563 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
501 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep);
502 // lastLinearVelocityVector is the current body velocity vector 564 // lastLinearVelocityVector is the current body velocity vector
503 // RA: Not sure what the *10 is for. A correction for pTimestep?
504 // m_lastLinearVelocityVector += (addAmount*10);
505 m_lastLinearVelocityVector += addAmount; 565 m_lastLinearVelocityVector += addAmount;
506 566
507 // Limit the velocity vector to less than the last set linear motor direction 567 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
508 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 568 m_linearMotorDirection *= (1f - decayFactor);
509 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 569
510 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) 570 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
511 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; 571 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
512 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 572
513 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 573 // Rotate new object velocity from vehicle relative to world coordinates
514 574 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
515 /* 575
516 // decay applied velocity 576 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lmVel={8},newVel={9}",
517 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep); 577 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
518 // (RA: do not know where the 0.5f comes from) 578 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
519 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
520 */
521 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
522 m_linearMotorDirection *= keepfraction;
523
524 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
525 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
526 } 579 }
527 else 580 else
528 { 581 {
529 // if what remains of direction is very small, zero it. 582 // if what remains of direction is very small, zero it.
530 m_linearMotorDirection = Vector3.Zero; 583 m_linearMotorDirection = Vector3.Zero;
531 m_lastLinearVelocityVector = Vector3.Zero; 584 m_lastLinearVelocityVector = Vector3.Zero;
585 m_newVelocity = Vector3.Zero;
586
532 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 587 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
533 } 588 }
534 589
535 // convert requested object velocity to object relative vector 590 // m_newVelocity is velocity computed from linear motor in world coordinates
536 Quaternion rotq = Prim.ForceOrientation;
537 m_newVelocity = m_lastLinearVelocityVector * rotq;
538
539 // Add the various forces into m_dir which will be our new direction vector (velocity)
540 591
541 // add Gravity and Buoyancy 592 // Gravity and Buoyancy
542 // There is some gravity, make a gravity force vector that is applied after object velocity. 593 // There is some gravity, make a gravity force vector that is applied after object velocity.
543 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 594 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
544 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy)); 595 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
545 596
546 /* 597 /*
547 * RA: Not sure why one would do this 598 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
548 // Preserve the current Z velocity 599 // Preserve the current Z velocity
549 Vector3 vel_now = m_prim.Velocity; 600 Vector3 vel_now = m_prim.Velocity;
550 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 601 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
@@ -567,6 +618,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
567 } 618 }
568 619
569 // Check if hovering 620 // Check if hovering
621 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
622 // m_VhoverTimescale: time to achieve height
570 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 623 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
571 { 624 {
572 // We should hover, get the target height 625 // We should hover, get the target height
@@ -597,13 +650,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
597 } 650 }
598 else 651 else
599 { 652 {
600 float herr0 = pos.Z - m_VhoverTargetHeight; 653 float verticalError = pos.Z - m_VhoverTargetHeight;
654 // RA: where does the 50 come from?
655 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
601 // Replace Vertical speed with correction figure if significant 656 // Replace Vertical speed with correction figure if significant
602 if (Math.Abs(herr0) > 0.01f) 657 if (Math.Abs(verticalError) > 0.01f)
603 { 658 {
604 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 659 m_newVelocity.Z += verticalCorrectionVelocity;
605 //KF: m_VhoverEfficiency is not yet implemented 660 //KF: m_VhoverEfficiency is not yet implemented
606 } 661 }
662 else if (verticalError < -0.01)
663 {
664 m_newVelocity.Z -= verticalCorrectionVelocity;
665 }
607 else 666 else
608 { 667 {
609 m_newVelocity.Z = 0f; 668 m_newVelocity.Z = 0f;
@@ -680,19 +739,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
680 739
681 // Apply velocity 740 // Apply velocity
682 Prim.ForceVelocity = m_newVelocity; 741 Prim.ForceVelocity = m_newVelocity;
683 // apply gravity force 742 // Prim.AddForce(m_newVelocity * Prim.Linkset.LinksetMass, false);
684 // Why is this set here? The physics engine already does gravity. 743 Prim.AddForce(grav * Prim.Linkset.LinksetMass, false);
685 Prim.AddForce(grav, false, true);
686 744
687 // Apply friction 745 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4}",
688 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 746 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav);
689 m_lastLinearVelocityVector *= keepFraction;
690
691 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
692 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
693 747
694 } // end MoveLinear() 748 } // end MoveLinear()
695 749
750 // =======================================================================
696 // Apply the effect of the angular motor. 751 // Apply the effect of the angular motor.
697 private void MoveAngular(float pTimestep) 752 private void MoveAngular(float pTimestep)
698 { 753 {
@@ -704,94 +759,150 @@ namespace OpenSim.Region.Physics.BulletSPlugin
704 // m_angularFrictionTimescale // body angular velocity decay rate 759 // m_angularFrictionTimescale // body angular velocity decay rate
705 // m_lastAngularVelocity // what was last applied to body 760 // m_lastAngularVelocity // what was last applied to body
706 761
707 // Get what the body is doing, this includes 'external' influences 762 if (m_angularMotorDirection.LengthSquared() > 0.0001)
708 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
709
710 if (m_angularMotorApply > 0)
711 { 763 {
712 // Rather than snapping the angular motor velocity from the old value to
713 // a newly set velocity, this routine steps the value from the previous
714 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
715 // There are m_angularMotorApply steps.
716 Vector3 origVel = m_angularMotorVelocity; 764 Vector3 origVel = m_angularMotorVelocity;
717 Vector3 origDir = m_angularMotorDirection; 765 Vector3 origDir = m_angularMotorDirection;
718 766
719 // ramp up to new value 767 // new velocity += error / ( time to get there / step interval)
720 // new velocity += error / ( time to get there / step interval) 768 // requested speed - last motor speed
721 // requested speed - last motor speed 769 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
722 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 770 // decay requested direction
723 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 771 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
724 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
725 772
726 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}", 773 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
727 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); 774 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
728
729 m_angularMotorApply--;
730 } 775 }
731 else 776 else
732 { 777 {
733 // No motor recently applied, keep the body velocity 778 m_angularMotorVelocity = Vector3.Zero;
734 // and decay the velocity 779 }
735 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 780
736 if (m_angularMotorVelocity.LengthSquared() < 0.00001) 781 #region Vertical attactor
737 m_angularMotorVelocity = Vector3.Zero; 782
738 } // end motor section
739
740 // Vertical attractor section
741 Vector3 vertattr = Vector3.Zero; 783 Vector3 vertattr = Vector3.Zero;
742 Vector3 deflection = Vector3.Zero; 784 Vector3 deflection = Vector3.Zero;
743 Vector3 banking = Vector3.Zero; 785 Vector3 banking = Vector3.Zero;
744 786
745 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 787 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
746 { 788 {
747 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); 789 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
748 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 790 if (Prim.Linkset.LinksetIsColliding)
791 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
749 792
750 // get present body rotation 793 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
751 Quaternion rotq = Prim.ForceOrientation;
752 // vector pointing up
753 Vector3 verterr = Vector3.Zero;
754 verterr.Z = 1.0f;
755 794
756 // rotate it to Body Angle 795 // Create a vector of the vehicle "up" in world coordinates
757 verterr = verterr * rotq; 796 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
758 // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. 797 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
759 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go 798 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
760 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 799 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
800 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
801 // modulated to prevent a stable inverted body.
761 802
762 // Error is 0 (no error) to +/- 2 (max error) 803 // Error is 0 (no error) to +/- 2 (max error)
763 if (verterr.Z < 0.0f) 804 if (verticalError.Z < 0.0f)
764 { 805 {
765 verterr.X = 2.0f - verterr.X; 806 verticalError.X = 2.0f - verticalError.X;
766 verterr.Y = 2.0f - verterr.Y; 807 verticalError.Y = 2.0f - verticalError.Y;
767 } 808 }
768 // scale it by VAservo 809 // scale it by VAservo
769 verterr = verterr * VAservo; 810 verticalError = verticalError * VAservo;
770 811
771 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 812 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
772 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 813 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
773 vertattr.X = verterr.Y; 814 // Z is not changed.
774 vertattr.Y = - verterr.X; 815 vertattr.X = verticalError.Y;
816 vertattr.Y = - verticalError.X;
775 vertattr.Z = 0f; 817 vertattr.Z = 0f;
776 818
777 // scaling appears better usingsquare-law 819 // scaling appears better usingsquare-law
820 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
778 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 821 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
779 vertattr.X += bounce * angularVelocity.X; 822 vertattr.X += bounce * angularVelocity.X;
780 vertattr.Y += bounce * angularVelocity.Y; 823 vertattr.Y += bounce * angularVelocity.Y;
781 824
782 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 825 VDetailLog("{0},MoveAngular,verticalAttraction,verticalError={1},bounce={2},vertattr={3}",
783 Prim.LocalID, verterr, bounce, vertattr); 826 Prim.LocalID, verticalError, bounce, vertattr);
784 827
785 } // else vertical attractor is off 828 }
829 #endregion // Vertical attactor
786 830
787 m_lastVertAttractor = vertattr; 831 #region Deflection
832
833 //Forward is the prefered direction, but if the reference frame has changed, we need to take this into account as well
834 if (m_angularDeflectionEfficiency != 0)
835 {
836 Vector3 preferredAxisOfMotion =
837 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
838 preferredAxisOfMotion *= Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
839
840 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
841
842 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
843 Prim.LocalID, preferredAxisOfMotion, deflection);
844 }
845
846 #endregion
847
848 #region Banking
849
850 if (m_bankingEfficiency != 0)
851 {
852 Vector3 dir = Vector3.One * Prim.ForceOrientation;
853 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
854 //Changes which way it banks in and out of turns
855
856 //Use the square of the efficiency, as it looks much more how SL banking works
857 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
858 if (m_bankingEfficiency < 0)
859 effSquared *= -1; //Keep the negative!
788 860
789 // Bank section tba 861 float mix = Math.Abs(m_bankingMix);
862 if (m_angularMotorVelocity.X == 0)
863 {
864 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
865 {
866 Vector3 axisAngle;
867 float angle;
868 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
869 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
870 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
871 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
872 else
873 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
874 }*/
875 }
876 else
877 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
878 if (!Prim.Linkset.LinksetIsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
879 //If they are colliding, we probably shouldn't shove the prim around... probably
880 {
881 float angVelZ = m_angularMotorVelocity.X*-1;
882 /*if(angVelZ > mix)
883 angVelZ = mix;
884 else if(angVelZ < -mix)
885 angVelZ = -mix;*/
886 //This controls how fast and how far the banking occurs
887 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
888 if (bankingRot.X > 3)
889 bankingRot.X = 3;
890 else if (bankingRot.X < -3)
891 bankingRot.X = -3;
892 bankingRot *= Prim.ForceOrientation;
893 banking += bankingRot;
894 }
895 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
896 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
897 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
898 }
899
900 #endregion
790 901
791 // Deflection section tba 902 m_lastVertAttractor = vertattr;
792 903
793 // Sum velocities 904 // Sum velocities
794 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 905 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
795 906
796 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 907 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
797 { 908 {
@@ -806,52 +917,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
806 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 917 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
807 } 918 }
808 919
809 // apply friction
810 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
811 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
812
813 // Apply to the body 920 // Apply to the body
814 Prim.ForceRotationalVelocity = m_lastAngularVelocity; 921 // The above calculates the absolute angular velocity needed
922 // Prim.ForceRotationalVelocity = m_lastAngularVelocity;
923
924 // Apply a force to overcome current angular velocity
925 Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity) * Prim.Linkset.LinksetMass;
926 // Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity);
927 // Prim.AddAngularForce(applyAngularForce, false);
928 Prim.ApplyTorqueImpulse(applyAngularForce, false);
929
930 // Apply friction for next time
931 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
932 m_lastAngularVelocity *= Vector3.One - decayamount;
815 933
816 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); 934 VDetailLog("{0},MoveAngular,done,applyAForce={1},decay={2},lastAngular={3}",
935 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
817 } //end MoveAngular 936 } //end MoveAngular
818 937
819 internal void LimitRotation(float timestep) 938 internal void LimitRotation(float timestep)
820 { 939 {
821 Quaternion rotq = Prim.ForceOrientation; 940 Quaternion rotq = Prim.ForceOrientation;
822 Quaternion m_rot = rotq; 941 Quaternion m_rot = rotq;
823 bool changed = false;
824 if (m_RollreferenceFrame != Quaternion.Identity) 942 if (m_RollreferenceFrame != Quaternion.Identity)
825 { 943 {
826 if (rotq.X >= m_RollreferenceFrame.X) 944 if (rotq.X >= m_RollreferenceFrame.X)
827 { 945 {
828 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 946 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
829 changed = true;
830 } 947 }
831 if (rotq.Y >= m_RollreferenceFrame.Y) 948 if (rotq.Y >= m_RollreferenceFrame.Y)
832 { 949 {
833 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 950 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
834 changed = true;
835 } 951 }
836 if (rotq.X <= -m_RollreferenceFrame.X) 952 if (rotq.X <= -m_RollreferenceFrame.X)
837 { 953 {
838 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 954 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
839 changed = true;
840 } 955 }
841 if (rotq.Y <= -m_RollreferenceFrame.Y) 956 if (rotq.Y <= -m_RollreferenceFrame.Y)
842 { 957 {
843 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 958 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
844 changed = true;
845 } 959 }
846 changed = true;
847 } 960 }
848 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 961 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
849 { 962 {
850 m_rot.X = 0; 963 m_rot.X = 0;
851 m_rot.Y = 0; 964 m_rot.Y = 0;
852 changed = true;
853 } 965 }
854 if (changed) 966 if (rotq != m_rot)
855 { 967 {
856 Prim.ForceOrientation = m_rot; 968 Prim.ForceOrientation = m_rot;
857 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 969 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index c984824..3a92f93 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -36,20 +36,29 @@ public abstract class BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 public enum LinksetImplementation
40 {
41 Constraint = 0, // linkset tied together with constraints
42 Compound = 1, // linkset tied together as a compound object
43 Manual = 2 // linkset tied together manually (code moves all the pieces)
44 }
39 // Create the correct type of linkset for this child 45 // Create the correct type of linkset for this child
40 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) 46 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
41 { 47 {
42 BSLinkset ret = null; 48 BSLinkset ret = null;
43 /*
44 if (parent.IsPhysical)
45 ret = new BSLinksetConstraints(physScene, parent);
46 else
47 ret = new BSLinksetManual(physScene, parent);
48 */
49
50 // at the moment, there is only one
51 ret = new BSLinksetConstraints(physScene, parent);
52 49
50 switch ((int)physScene.Params.linksetImplementation)
51 {
52 case (int)LinksetImplementation.Compound:
53 ret = new BSLinksetCompound(physScene, parent);
54 break;
55 case (int)LinksetImplementation.Manual:
56 // ret = new BSLinksetManual(physScene, parent);
57 break;
58 default:
59 ret = new BSLinksetConstraints(physScene, parent);
60 break;
61 }
53 return ret; 62 return ret;
54 } 63 }
55 64
@@ -61,22 +70,27 @@ public abstract class BSLinkset
61 public int LinksetID { get; private set; } 70 public int LinksetID { get; private set; }
62 71
63 // The children under the root in this linkset. 72 // The children under the root in this linkset.
64 // There are two lists of children: the current children at runtime
65 // and the children at taint-time. For instance, if you delink a
66 // child from the linkset, the child is removed from m_children
67 // but the constraint won't be removed until taint time.
68 // Two lists lets this track the 'current' children and
69 // the physical 'taint' children separately.
70 // After taint processing and before the simulation step, these
71 // two lists must be the same.
72 protected HashSet<BSPhysObject> m_children; 73 protected HashSet<BSPhysObject> m_children;
73 protected HashSet<BSPhysObject> m_taintChildren;
74 74
75 // We lock the diddling of linkset classes to prevent any badness. 75 // We lock the diddling of linkset classes to prevent any badness.
76 // This locks the modification of the instances of this class. Changes 76 // This locks the modification of the instances of this class. Changes
77 // to the physical representation is done via the tainting mechenism. 77 // to the physical representation is done via the tainting mechenism.
78 protected object m_linksetActivityLock = new Object(); 78 protected object m_linksetActivityLock = new Object();
79 79
80 // Some linksets have a preferred physical shape.
81 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
82 public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
83 {
84 return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
85 }
86
87 // Linksets move around the children so the linkset might need to compute the child position
88 public virtual OMV.Vector3 Position(BSPhysObject member)
89 { return member.RawPosition; }
90 public virtual OMV.Quaternion Orientation(BSPhysObject member)
91 { return member.RawOrientation; }
92 // TODO: does this need to be done for Velocity and RotationalVelocityy?
93
80 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 94 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
81 protected float m_mass; 95 protected float m_mass;
82 public float LinksetMass 96 public float LinksetMass
@@ -88,6 +102,8 @@ public abstract class BSLinkset
88 } 102 }
89 } 103 }
90 104
105 public virtual bool LinksetIsColliding { get { return false; } }
106
91 public OMV.Vector3 CenterOfMass 107 public OMV.Vector3 CenterOfMass
92 { 108 {
93 get { return ComputeLinksetCenterOfMass(); } 109 get { return ComputeLinksetCenterOfMass(); }
@@ -108,8 +124,7 @@ public abstract class BSLinkset
108 PhysicsScene = scene; 124 PhysicsScene = scene;
109 LinksetRoot = parent; 125 LinksetRoot = parent;
110 m_children = new HashSet<BSPhysObject>(); 126 m_children = new HashSet<BSPhysObject>();
111 m_taintChildren = new HashSet<BSPhysObject>(); 127 m_mass = parent.RawMass;
112 m_mass = parent.MassRaw;
113 } 128 }
114 129
115 // Link to a linkset where the child knows the parent. 130 // Link to a linkset where the child knows the parent.
@@ -140,7 +155,6 @@ public abstract class BSLinkset
140 // Cannot remove the root from a linkset. 155 // Cannot remove the root from a linkset.
141 return this; 156 return this;
142 } 157 }
143
144 RemoveChildFromLinkset(child); 158 RemoveChildFromLinkset(child);
145 } 159 }
146 160
@@ -165,9 +179,8 @@ public abstract class BSLinkset
165 bool ret = false; 179 bool ret = false;
166 lock (m_linksetActivityLock) 180 lock (m_linksetActivityLock)
167 { 181 {
168 if (m_children.Contains(child)) 182 ret = m_children.Contains(child);
169 ret = true; 183 /* Safer version but the above should work
170 /*
171 foreach (BSPhysObject bp in m_children) 184 foreach (BSPhysObject bp in m_children)
172 { 185 {
173 if (child.LocalID == bp.LocalID) 186 if (child.LocalID == bp.LocalID)
@@ -181,10 +194,36 @@ public abstract class BSLinkset
181 return ret; 194 return ret;
182 } 195 }
183 196
197 // Perform an action on each member of the linkset including root prim.
198 // Depends on the action on whether this should be done at taint time.
199 public delegate bool ForEachMemberAction(BSPhysObject obj);
200 public virtual bool ForEachMember(ForEachMemberAction action)
201 {
202 bool ret = false;
203 lock (m_linksetActivityLock)
204 {
205 action(LinksetRoot);
206 foreach (BSPhysObject po in m_children)
207 {
208 if (action(po))
209 break;
210 }
211 }
212 return ret;
213 }
214
215 // I am the root of a linkset and a new child is being added
216 // Called while LinkActivity is locked.
217 protected abstract void AddChildToLinkset(BSPhysObject child);
218
219 // I am the root of a linkset and one of my children is being removed.
220 // Safe to call even if the child is not really in my linkset.
221 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
222
184 // When physical properties are changed the linkset needs to recalculate 223 // When physical properties are changed the linkset needs to recalculate
185 // its internal properties. 224 // its internal properties.
186 // May be called at runtime or taint-time (just pass the appropriate flag). 225 // May be called at runtime or taint-time.
187 public abstract void Refresh(BSPhysObject requestor, bool inTaintTime); 226 public abstract void Refresh(BSPhysObject requestor);
188 227
189 // The object is going dynamic (physical). Do any setup necessary 228 // The object is going dynamic (physical). Do any setup necessary
190 // for a dynamic linkset. 229 // for a dynamic linkset.
@@ -218,17 +257,17 @@ public abstract class BSLinkset
218 public abstract void RestoreBodyDependencies(BSPrim child); 257 public abstract void RestoreBodyDependencies(BSPrim child);
219 258
220 // ================================================================ 259 // ================================================================
221 // Below this point is internal magic
222
223 protected virtual float ComputeLinksetMass() 260 protected virtual float ComputeLinksetMass()
224 { 261 {
225 float mass; 262 float mass = LinksetRoot.RawMass;
226 lock (m_linksetActivityLock) 263 if (HasAnyChildren)
227 { 264 {
228 mass = LinksetRoot.MassRaw; 265 lock (m_linksetActivityLock)
229 foreach (BSPhysObject bp in m_taintChildren)
230 { 266 {
231 mass += bp.MassRaw; 267 foreach (BSPhysObject bp in m_children)
268 {
269 mass += bp.RawMass;
270 }
232 } 271 }
233 } 272 }
234 return mass; 273 return mass;
@@ -239,13 +278,13 @@ public abstract class BSLinkset
239 OMV.Vector3 com; 278 OMV.Vector3 com;
240 lock (m_linksetActivityLock) 279 lock (m_linksetActivityLock)
241 { 280 {
242 com = LinksetRoot.Position * LinksetRoot.MassRaw; 281 com = LinksetRoot.Position * LinksetRoot.RawMass;
243 float totalMass = LinksetRoot.MassRaw; 282 float totalMass = LinksetRoot.RawMass;
244 283
245 foreach (BSPhysObject bp in m_taintChildren) 284 foreach (BSPhysObject bp in m_children)
246 { 285 {
247 com += bp.Position * bp.MassRaw; 286 com += bp.Position * bp.RawMass;
248 totalMass += bp.MassRaw; 287 totalMass += bp.RawMass;
249 } 288 }
250 if (totalMass != 0f) 289 if (totalMass != 0f)
251 com /= totalMass; 290 com /= totalMass;
@@ -261,31 +300,16 @@ public abstract class BSLinkset
261 { 300 {
262 com = LinksetRoot.Position; 301 com = LinksetRoot.Position;
263 302
264 foreach (BSPhysObject bp in m_taintChildren) 303 foreach (BSPhysObject bp in m_children)
265 { 304 {
266 com += bp.Position * bp.MassRaw; 305 com += bp.Position * bp.RawMass;
267 } 306 }
268 com /= (m_taintChildren.Count + 1); 307 com /= (m_children.Count + 1);
269 } 308 }
270 309
271 return com; 310 return com;
272 } 311 }
273 312
274 // I am the root of a linkset and a new child is being added
275 // Called while LinkActivity is locked.
276 protected abstract void AddChildToLinkset(BSPhysObject child);
277
278 // Forcefully removing a child from a linkset.
279 // This is not being called by the child so we have to make sure the child doesn't think
280 // it's still connected to the linkset.
281 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
282 // also has to be updated (like pointer to prim's parent).
283 protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild);
284
285 // I am the root of a linkset and one of my children is being removed.
286 // Safe to call even if the child is not really in my linkset.
287 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
288
289 // Invoke the detailed logger and output something if it's enabled. 313 // Invoke the detailed logger and output something if it's enabled.
290 protected void DetailLog(string msg, params Object[] args) 314 protected void DetailLog(string msg, params Object[] args)
291 { 315 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
new file mode 100755
index 0000000..12c6d7a
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetCompound : BSLinkset
36{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 {
47 ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren)
49 {
50 ret = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
51 }
52 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
53 return ret;
54 }
55
56 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 {
62 // External request for Refresh (from BSPrim) is not necessary
63 // InternalRefresh(requestor);
64 }
65
66 private void InternalRefresh(BSPhysObject requestor)
67 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
69 // Queue to happen after all the other taint processing
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
71 {
72 if (IsRoot(requestor) && HasAnyChildren)
73 RecomputeLinksetCompound();
74 });
75 }
76
77 // The object is going dynamic (physical). Do any setup necessary
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child)
84 {
85 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child))
88 {
89 // Physical children are removed from the world as the shape ofthe root compound
90 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
93 ret = true;
94 }
95 return ret;
96 }
97
98 // The object is going static (non-physical). Do any setup necessary for a static linkset.
99 // Return 'true' if any properties updated on the passed object.
100 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset.
102 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child)
104 {
105 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child))
108 {
109 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true;
114 }
115 return ret;
116 }
117
118 // Called at taint-time!!
119 public override void UpdateProperties(BSPhysObject updated)
120 {
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
134 }
135
136 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child)
141 {
142 bool ret = false;
143
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
146
147 if (!IsRoot(child))
148 {
149 // Cause the current shape to be freed and the new one to be built.
150 InternalRefresh(LinksetRoot);
151 ret = true;
152 }
153
154 return ret;
155 }
156
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints.
159 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child)
161 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
163 }
164
165 // ================================================================
166
167 // Add a new child to the linkset.
168 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child)
170 {
171 if (!HasChild(child))
172 {
173 m_children.Add(child);
174
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176
177 // Cause constraints and assorted properties to be recomputed before the next simulation step.
178 InternalRefresh(LinksetRoot);
179 }
180 return;
181 }
182
183 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 {
187 if (m_children.Remove(child))
188 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"),
192 child.LocalID, child.PhysBody.ptr.ToString("X"));
193
194 // Cause the child's body to be rebuilt and thus restored to normal operation
195 child.ForceBodyShapeRebuild(false);
196
197 if (!HasAnyChildren)
198 {
199 // The linkset is now empty. The root needs rebuilding.
200 LinksetRoot.ForceBodyShapeRebuild(false);
201 }
202 else
203 {
204 // Schedule a rebuild of the linkset before the next simulation tick.
205 InternalRefresh(LinksetRoot);
206 }
207 }
208 return;
209 }
210
211 // Called before the simulation step to make sure the compound based linkset
212 // is all initialized.
213 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!!
216 private void RecomputeLinksetCompound()
217 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 {
227 if (!IsRoot(cPrim))
228 {
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
236
237 if (cPrim.PhysShape.isNativeShape)
238 {
239 // Native shapes are not shared so we need to create a new one.
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
253 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
256 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262
263 // With all of the linkset packed into the root prim, it has the mass of everyone.
264 float linksetMass = LinksetMass;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266
267 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
268 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
269 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
270
271 }
272}
273} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 8a750b5..d2387fb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -32,7 +32,7 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinksetConstraints : BSLinkset 35public sealed class BSLinksetConstraints : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 38
@@ -43,23 +43,16 @@ public class BSLinksetConstraints : BSLinkset
43 43
44 // When physical properties are changed the linkset needs to recalculate 44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties. 45 // its internal properties.
46 // May be called at runtime or taint-time (just pass the appropriate flag). 46 // This is queued in the 'post taint' queue so the
47 public override void Refresh(BSPhysObject requestor, bool inTaintTime) 47 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor)
48 { 49 {
49 // If there are no children or not root, I am not the one that recomputes the constraints 50 // Queue to happen after all the other taint processing
50 if (!HasAnyChildren || !IsRoot(requestor)) 51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
51 return;
52
53 BSScene.TaintCallback refreshOperation = delegate()
54 { 52 {
55 RecomputeLinksetConstraintVariables(); 53 if (HasAnyChildren && IsRoot(requestor))
56 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}", 54 RecomputeLinksetConstraints();
57 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); 55 });
58 };
59 if (inTaintTime)
60 refreshOperation();
61 else
62 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
63 } 56 }
64 57
65 // The object is going dynamic (physical). Do any setup necessary 58 // The object is going dynamic (physical). Do any setup necessary
@@ -74,9 +67,10 @@ public class BSLinksetConstraints : BSLinkset
74 return false; 67 return false;
75 } 68 }
76 69
77 // The object is going static (non-physical). Do any setup necessary 70 // The object is going static (non-physical). Do any setup necessary for a static linkset.
78 // for a static linkset.
79 // Return 'true' if any properties updated on the passed object. 71 // Return 'true' if any properties updated on the passed object.
72 // This doesn't normally happen -- OpenSim removes the objects from the physical
73 // world if it is a static linkset.
80 // Called at taint-time! 74 // Called at taint-time!
81 public override bool MakeStatic(BSPhysObject child) 75 public override bool MakeStatic(BSPhysObject child)
82 { 76 {
@@ -90,35 +84,36 @@ public class BSLinksetConstraints : BSLinkset
90 // Nothing to do for constraints on property updates 84 // Nothing to do for constraints on property updates
91 } 85 }
92 86
93 // Routine used when rebuilding the body of the root of the linkset 87 // The children of the linkset are moved around by the constraints.
94 // Destroy all the constraints have have been made to root. 88 // Just grab the current values of wherever it is right now.
95 // This is called when the root body is changing. 89 public override OMV.Vector3 Position(BSPhysObject member)
96 // Returns 'true' of something eas actually removed and would need restoring 90 {
91 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
92 }
93
94 public override OMV.Quaternion Orientation(BSPhysObject member)
95 {
96 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
97 }
98
99 // Routine called when rebuilding the body of some member of the linkset.
100 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step.
102 // Returns 'true' of something was actually removed and would need restoring
97 // Called at taint-time!! 103 // Called at taint-time!!
98 public override bool RemoveBodyDependencies(BSPrim child) 104 public override bool RemoveBodyDependencies(BSPrim child)
99 { 105 {
100 bool ret = false; 106 bool ret = false;
101 107
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"));
110
102 lock (m_linksetActivityLock) 111 lock (m_linksetActivityLock)
103 { 112 {
104 if (IsRoot(child)) 113 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
105 { 114 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
106 // If the one with the dependency is root, must undo all children 115 // Cause the constraints, et al to be rebuilt before the next simulation step.
107 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 116 Refresh(LinksetRoot);
108 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
109
110 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
111 }
112 else
113 {
114 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
115 child.LocalID,
116 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
117 child.LocalID, child.BSBody.ptr.ToString("X"));
118 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
119 // Despite the function name, this removes any link to the specified object.
120 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
121 }
122 } 117 }
123 return ret; 118 return ret;
124 } 119 }
@@ -128,32 +123,12 @@ public class BSLinksetConstraints : BSLinkset
128 // Called at taint-time!! 123 // Called at taint-time!!
129 public override void RestoreBodyDependencies(BSPrim child) 124 public override void RestoreBodyDependencies(BSPrim child)
130 { 125 {
131 lock (m_linksetActivityLock) 126 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
132 {
133 if (IsRoot(child))
134 {
135 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
136 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
137 foreach (BSPhysObject bpo in m_taintChildren)
138 {
139 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
140 }
141 }
142 else
143 {
144 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
145 LinksetRoot.LocalID,
146 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
147 child.LocalID, child.BSBody.ptr.ToString("X"));
148 PhysicallyLinkAChildToRoot(LinksetRoot, child);
149 }
150 }
151 } 127 }
152 128
153 // ================================================================ 129 // ================================================================
154 // Below this point is internal magic
155 130
156 // I am the root of a linkset and a new child is being added 131 // Add a new child to the linkset.
157 // Called while LinkActivity is locked. 132 // Called while LinkActivity is locked.
158 protected override void AddChildToLinkset(BSPhysObject child) 133 protected override void AddChildToLinkset(BSPhysObject child)
159 { 134 {
@@ -161,39 +136,15 @@ public class BSLinksetConstraints : BSLinkset
161 { 136 {
162 m_children.Add(child); 137 m_children.Add(child);
163 138
164 BSPhysObject rootx = LinksetRoot; // capture the root as of now 139 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
165 BSPhysObject childx = child;
166
167 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
168 140
169 PhysicsScene.TaintedObject("AddChildToLinkset", delegate() 141 // Cause constraints and assorted properties to be recomputed before the next simulation step.
170 { 142 Refresh(LinksetRoot);
171 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
172 rootx.LocalID,
173 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
174 childx.LocalID, childx.BSBody.ptr.ToString("X"));
175 // Since this is taint-time, the body and shape could have changed for the child
176 rootx.ForcePosition = rootx.Position; // DEBUG
177 childx.ForcePosition = childx.Position; // DEBUG
178 PhysicallyLinkAChildToRoot(rootx, childx);
179 m_taintChildren.Add(child);
180 });
181 } 143 }
182 return; 144 return;
183 } 145 }
184 146
185 // Forcefully removing a child from a linkset. 147 // Remove the specified child from the linkset.
186 // This is not being called by the child so we have to make sure the child doesn't think
187 // it's still connected to the linkset.
188 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
189 // also has to be updated (like pointer to prim's parent).
190 protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
191 {
192 pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
193 RemoveChildFromLinkset(pchild);
194 }
195
196 // I am the root of a linkset and one of my children is being removed.
197 // Safe to call even if the child is not really in my linkset. 148 // Safe to call even if the child is not really in my linkset.
198 protected override void RemoveChildFromLinkset(BSPhysObject child) 149 protected override void RemoveChildFromLinkset(BSPhysObject child)
199 { 150 {
@@ -202,22 +153,21 @@ public class BSLinksetConstraints : BSLinkset
202 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now 153 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
203 BSPhysObject childx = child; 154 BSPhysObject childx = child;
204 155
205 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
206 childx.LocalID, 157 childx.LocalID,
207 rootx.LocalID, rootx.BSBody.ptr.ToString("X"), 158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"),
208 childx.LocalID, childx.BSBody.ptr.ToString("X")); 159 childx.LocalID, childx.PhysBody.ptr.ToString("X"));
209 160
210 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
211 { 162 {
212 m_taintChildren.Remove(child);
213 PhysicallyUnlinkAChildFromRoot(rootx, childx); 163 PhysicallyUnlinkAChildFromRoot(rootx, childx);
214 RecomputeLinksetConstraintVariables();
215 }); 164 });
216 165 // See that the linkset parameters are recomputed at the end of the taint time.
166 Refresh(LinksetRoot);
217 } 167 }
218 else 168 else
219 { 169 {
220 // This will happen if we remove the root of the linkset first. Non-fatal occurance. 170 // Non-fatal occurance.
221 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); 171 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
222 } 172 }
223 return; 173 return;
@@ -227,6 +177,12 @@ public class BSLinksetConstraints : BSLinkset
227 // Called at taint time! 177 // Called at taint time!
228 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 178 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
229 { 179 {
180 // Don't build the constraint when asked. Put it off until just before the simulation step.
181 Refresh(rootPrim);
182 }
183
184 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
185 {
230 // Zero motion for children so they don't interpolate 186 // Zero motion for children so they don't interpolate
231 childPrim.ZeroMotion(); 187 childPrim.ZeroMotion();
232 188
@@ -237,22 +193,23 @@ public class BSLinksetConstraints : BSLinkset
237 // real world coordinate of midpoint between the two objects 193 // real world coordinate of midpoint between the two objects
238 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 194 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
239 195
240 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
241 rootPrim.LocalID, 197 rootPrim.LocalID,
242 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), 198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
243 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"), 199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"),
244 rootPrim.Position, childPrim.Position, midPoint); 200 rootPrim.Position, childPrim.Position, midPoint);
245 201
246 // create a constraint that allows no freedom of movement between the two objects 202 // create a constraint that allows no freedom of movement between the two objects
247 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 203 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
248 204
249 BS6DofConstraint constrain = new BS6DofConstraint( 205 BSConstraint6Dof constrain = new BSConstraint6Dof(
250 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true ); 206 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
207 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
251 208
252 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 209 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
253 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms 210 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
254 * of the objects. 211 * of the objects.
255 * Code left as a warning to future programmers. 212 * Code left for future programmers.
256 // ================================================================================== 213 // ==================================================================================
257 // relative position normalized to the root prim 214 // relative position normalized to the root prim
258 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); 215 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@@ -262,20 +219,13 @@ public class BSLinksetConstraints : BSLinkset
262 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; 219 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
263 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); 220 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
264 221
265 // create a constraint that allows no freedom of movement between the two objects 222 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
266 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
267 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
268 BS6DofConstraint constrain = new BS6DofConstraint( 223 BS6DofConstraint constrain = new BS6DofConstraint(
269 PhysicsScene.World, rootPrim.Body, childPrim.Body, 224 PhysicsScene.World, rootPrim.Body, childPrim.Body,
270 OMV.Vector3.Zero, 225 OMV.Vector3.Zero,
271 OMV.Quaternion.Inverse(rootPrim.Orientation), 226 OMV.Quaternion.Inverse(rootPrim.Orientation),
272 OMV.Vector3.Zero, 227 OMV.Vector3.Zero,
273 OMV.Quaternion.Inverse(childPrim.Orientation), 228 OMV.Quaternion.Inverse(childPrim.Orientation),
274 // A point half way between the parent and child
275 // childRelativePosition/2,
276 // childRelativeRotation,
277 // childRelativePosition/2,
278 // inverseChildRelativeRotation,
279 true, 229 true,
280 true 230 true
281 ); 231 );
@@ -298,25 +248,26 @@ public class BSLinksetConstraints : BSLinkset
298 { 248 {
299 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
300 } 250 }
251 return constrain;
301 } 252 }
302 253
303 // Remove linkage between myself and a particular child 254 // Remove linkage between the linkset root and a particular child
304 // The root and child bodies are passed in because we need to remove the constraint between 255 // The root and child bodies are passed in because we need to remove the constraint between
305 // the bodies that were at unlink time. 256 // the bodies that were present at unlink time.
306 // Called at taint time! 257 // Called at taint time!
307 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 258 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
308 { 259 {
309 bool ret = false; 260 bool ret = false;
310 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
311 rootPrim.LocalID, 262 rootPrim.LocalID,
312 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), 263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
313 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X")); 264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"));
314 265
315 // Find the constraint for this link and get rid of it from the overall collection and from my list 266 // Find the constraint for this link and get rid of it from the overall collection and from my list
316 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody)) 267 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
317 { 268 {
318 // Make the child refresh its location 269 // Make the child refresh its location
319 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); 270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
320 ret = true; 271 ret = true;
321 } 272 }
322 273
@@ -324,62 +275,53 @@ public class BSLinksetConstraints : BSLinkset
324 } 275 }
325 276
326 // Remove linkage between myself and any possible children I might have. 277 // Remove linkage between myself and any possible children I might have.
278 // Returns 'true' of any constraints were destroyed.
327 // Called at taint time! 279 // Called at taint time!
328 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 280 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
329 { 281 {
330 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 282 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
331 bool ret = false;
332 283
333 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody)) 284 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
334 {
335 ret = true;
336 }
337 return ret;
338 } 285 }
339 286
340 // Call each of the constraints that make up this linkset and recompute the 287 // Call each of the constraints that make up this linkset and recompute the
341 // various transforms and variables. Used when objects are added or removed 288 // various transforms and variables. Create constraints of not created yet.
342 // from a linkset to make sure the constraints know about the new mass and 289 // Called before the simulation step to make sure the constraint based linkset
343 // geometry. 290 // is all initialized.
344 // Must only be called at taint time!! 291 // Called at taint time!!
345 private void RecomputeLinksetConstraintVariables() 292 private void RecomputeLinksetConstraints()
346 { 293 {
347 float linksetMass = LinksetMass; 294 float linksetMass = LinksetMass;
348 foreach (BSPhysObject child in m_taintChildren) 295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
296
297 // DEBUG: see of inter-linkset collisions are causing problems
298 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
299 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
300 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
302
303 foreach (BSPhysObject child in m_children)
349 { 304 {
305 // A child in the linkset physically shows the mass of the whole linkset.
306 // This allows Bullet to apply enough force on the child to move the whole linkset.
307 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass);
309
350 BSConstraint constrain; 310 BSConstraint constrain;
351 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain)) 311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
352 {
353 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
354 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
355 constrain.RecomputeConstraintVariables(linksetMass);
356 }
357 else
358 { 312 {
359 // Non-fatal error that happens when children are being added to the linkset but 313 // If constraint doesn't exist yet, create it.
360 // their constraints have not been created yet. 314 constrain = BuildConstraint(LinksetRoot, child);
361 break;
362 } 315 }
363 } 316 constrain.RecomputeConstraintVariables(linksetMass);
364 317
365 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values 318 // DEBUG: see of inter-linkset collisions are causing problems
366 if (m_children.Count == m_taintChildren.Count) 319 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
367 { 320 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
368 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
369 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
370 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
371 centerOfMass, OMV.Quaternion.Identity);
372 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
373 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
374 foreach (BSPhysObject child in m_taintChildren)
375 {
376 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
377 centerOfMass, OMV.Quaternion.Identity);
378 }
379 321
380 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG 322 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
381 } 323 }
382 return; 324
383 } 325 }
384} 326}
385} 327}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 538f905..7127aaf 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -63,12 +63,14 @@ public abstract class BSPhysObject : PhysicsActor
63 public BSLinkset Linkset { get; set; } 63 public BSLinkset Linkset { get; set; }
64 64
65 // Return the object mass without calculating it or having side effects 65 // Return the object mass without calculating it or having side effects
66 public abstract float MassRaw { get; } 66 public abstract float RawMass { get; }
67 // Set the raw mass but also update physical mass properties (inertia, ...)
68 public abstract void UpdatePhysicalMassProperties(float mass);
67 69
68 // Reference to the physical body (btCollisionObject) of this object 70 // Reference to the physical body (btCollisionObject) of this object
69 public BulletBody BSBody; 71 public BulletBody PhysBody;
70 // Reference to the physical shape (btCollisionShape) of this object 72 // Reference to the physical shape (btCollisionShape) of this object
71 public BulletShape BSShape; 73 public BulletShape PhysShape;
72 74
73 // 'true' if the mesh's underlying asset failed to build. 75 // 'true' if the mesh's underlying asset failed to build.
74 // This will keep us from looping after the first time the build failed. 76 // This will keep us from looping after the first time the build failed.
@@ -76,6 +78,12 @@ public abstract class BSPhysObject : PhysicsActor
76 78
77 // The objects base shape information. Null if not a prim type shape. 79 // The objects base shape information. Null if not a prim type shape.
78 public PrimitiveBaseShape BaseShape { get; protected set; } 80 public PrimitiveBaseShape BaseShape { get; protected set; }
81 // Some types of objects have preferred physical representations.
82 // Returns SHAPE_UNKNOWN if there is no preference.
83 public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape
84 {
85 get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; }
86 }
79 87
80 // When the physical properties are updated, an EntityProperty holds the update values. 88 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences 89 // Keep the current and last EntityProperties to enable computation of differences
@@ -99,8 +107,10 @@ public abstract class BSPhysObject : PhysicsActor
99 // Tell the object to clean up. 107 // Tell the object to clean up.
100 public abstract void Destroy(); 108 public abstract void Destroy();
101 109
110 public abstract OMV.Vector3 RawPosition { get; set; }
102 public abstract OMV.Vector3 ForcePosition { get; set; } 111 public abstract OMV.Vector3 ForcePosition { get; set; }
103 112
113 public abstract OMV.Quaternion RawOrientation { get; set; }
104 public abstract OMV.Quaternion ForceOrientation { get; set; } 114 public abstract OMV.Quaternion ForceOrientation { get; set; }
105 115
106 public abstract OMV.Vector3 ForceVelocity { get; set; } 116 public abstract OMV.Vector3 ForceVelocity { get; set; }
@@ -204,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor
204 214
205 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 215 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
206 { 216 {
207 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 217 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
208 }); 218 });
209 } 219 }
210 else 220 else
@@ -218,7 +228,7 @@ public abstract class BSPhysObject : PhysicsActor
218 SubscribedEventsMs = 0; 228 SubscribedEventsMs = 0;
219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 229 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
220 { 230 {
221 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 231 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
222 }); 232 });
223 } 233 }
224 // Return 'true' if the simulator wants collision events 234 // Return 'true' if the simulator wants collision events
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 38ab3de..aaa0d93 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -111,8 +111,8 @@ public sealed class BSPrim : BSPhysObject
111 _mass = CalculateMass(); 111 _mass = CalculateMass();
112 112
113 // No body or shape yet 113 // No body or shape yet
114 BSBody = new BulletBody(LocalID, IntPtr.Zero); 114 PhysBody = new BulletBody(LocalID, IntPtr.Zero);
115 BSShape = new BulletShape(IntPtr.Zero); 115 PhysShape = new BulletShape(IntPtr.Zero);
116 116
117 DetailLog("{0},BSPrim.constructor,call", LocalID); 117 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time 118 // do the actual object creation at taint time
@@ -120,7 +120,7 @@ public sealed class BSPrim : BSPhysObject
120 { 120 {
121 CreateGeomAndObject(true); 121 CreateGeomAndObject(true);
122 122
123 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr); 123 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
124 }); 124 });
125 } 125 }
126 126
@@ -145,8 +145,8 @@ public sealed class BSPrim : BSPhysObject
145 { 145 {
146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
147 // If there are physical body and shape, release my use of same. 147 // If there are physical body and shape, release my use of same.
148 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); 148 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
149 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); 149 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
150 }); 150 });
151 } 151 }
152 152
@@ -171,18 +171,18 @@ public sealed class BSPrim : BSPhysObject
171 ForceBodyShapeRebuild(false); 171 ForceBodyShapeRebuild(false);
172 } 172 }
173 } 173 }
174 // Whatever the linkset wants is what I want.
175 public override ShapeData.PhysicsShapeType PreferredPhysicalShape
176 { get { return Linkset.PreferredPhysicalShape(this); } }
177
174 public override bool ForceBodyShapeRebuild(bool inTaintTime) 178 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 { 179 {
176 LastAssetBuildFailed = false; 180 LastAssetBuildFailed = false;
177 BSScene.TaintCallback rebuildOperation = delegate() 181 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
178 { 182 {
179 _mass = CalculateMass(); // changing the shape changes the mass 183 _mass = CalculateMass(); // changing the shape changes the mass
180 CreateGeomAndObject(true); 184 CreateGeomAndObject(true);
181 }; 185 });
182 if (inTaintTime)
183 rebuildOperation();
184 else
185 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
186 return true; 186 return true;
187 } 187 }
188 public override bool Grabbed { 188 public override bool Grabbed {
@@ -242,8 +242,8 @@ public sealed class BSPrim : BSPhysObject
242 _acceleration = OMV.Vector3.Zero; 242 _acceleration = OMV.Vector3.Zero;
243 _rotationalVelocity = OMV.Vector3.Zero; 243 _rotationalVelocity = OMV.Vector3.Zero;
244 244
245 // Zero some other properties directly into the physics engine 245 // Zero some other properties in the physics engine
246 BulletSimAPI.ClearForces2(BSBody.ptr); 246 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
247 } 247 }
248 248
249 public override void LockAngularMotion(OMV.Vector3 axis) 249 public override void LockAngularMotion(OMV.Vector3 axis)
@@ -252,11 +252,16 @@ public sealed class BSPrim : BSPhysObject
252 return; 252 return;
253 } 253 }
254 254
255 public override OMV.Vector3 RawPosition
256 {
257 get { return _position; }
258 set { _position = value; }
259 }
255 public override OMV.Vector3 Position { 260 public override OMV.Vector3 Position {
256 get { 261 get {
262 // child prims move around based on their parent. Need to get the latest location
257 if (!Linkset.IsRoot(this)) 263 if (!Linkset.IsRoot(this))
258 // child prims move around based on their parent. Need to get the latest location 264 _position = Linkset.Position(this);
259 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
260 265
261 // don't do the GetObjectPosition for root elements because this function is called a zillion times 266 // don't do the GetObjectPosition for root elements because this function is called a zillion times
262 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 267 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
@@ -274,19 +279,21 @@ public sealed class BSPrim : BSPhysObject
274 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 279 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
275 { 280 {
276 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 281 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
277 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 282 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
283 ActivateIfPhysical(false);
278 }); 284 });
279 } 285 }
280 } 286 }
281 public override OMV.Vector3 ForcePosition { 287 public override OMV.Vector3 ForcePosition {
282 get { 288 get {
283 _position = BulletSimAPI.GetPosition2(BSBody.ptr); 289 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
284 return _position; 290 return _position;
285 } 291 }
286 set { 292 set {
287 _position = value; 293 _position = value;
288 PositionSanityCheck(); 294 PositionSanityCheck();
289 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 295 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
296 ActivateIfPhysical(false);
290 } 297 }
291 } 298 }
292 299
@@ -311,6 +318,7 @@ public sealed class BSPrim : BSPhysObject
311 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 318 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
312 { 319 {
313 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 320 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
321 // TODO: a floating motor so object will bob in the water
314 if (Position.Z < waterHeight) 322 if (Position.Z < waterHeight)
315 { 323 {
316 _position.Z = waterHeight; 324 _position.Z = waterHeight;
@@ -332,16 +340,11 @@ public sealed class BSPrim : BSPhysObject
332 { 340 {
333 // The new position value must be pushed into the physics engine but we can't 341 // The new position value must be pushed into the physics engine but we can't
334 // just assign to "Position" because of potential call loops. 342 // just assign to "Position" because of potential call loops.
335 BSScene.TaintCallback sanityOperation = delegate() 343 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate()
336 { 344 {
337 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 345 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
338 ForcePosition = _position; 346 ForcePosition = _position;
339 }; 347 });
340 if (inTaintTime)
341 sanityOperation();
342 else
343 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
344
345 ret = true; 348 ret = true;
346 } 349 }
347 return ret; 350 return ret;
@@ -353,13 +356,34 @@ public sealed class BSPrim : BSPhysObject
353 { 356 {
354 get 357 get
355 { 358 {
356 // return Linkset.LinksetMass; 359 return Linkset.LinksetMass;
357 return _mass; 360 // return _mass;
358 } 361 }
359 } 362 }
360 363
361 // used when we only want this prim's mass and not the linkset thing 364 // used when we only want this prim's mass and not the linkset thing
362 public override float MassRaw { get { return _mass; } } 365 public override float RawMass {
366 get { return _mass; }
367 }
368 // Set the physical mass to the passed mass.
369 // Note that this does not change _mass!
370 public override void UpdatePhysicalMassProperties(float physMass)
371 {
372 if (IsStatic)
373 {
374 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, OMV.Vector3.Zero);
375 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
376 }
377 else
378 {
379 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
380 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
381 // center of mass is at the zero of the object
382 BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
383 // BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
384 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, localInertia);
385 }
386 }
363 387
364 // Is this used? 388 // Is this used?
365 public override OMV.Vector3 CenterOfMass 389 public override OMV.Vector3 CenterOfMass
@@ -380,7 +404,7 @@ public sealed class BSPrim : BSPhysObject
380 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 404 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
381 { 405 {
382 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 406 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
383 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 407 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
384 }); 408 });
385 } 409 }
386 } 410 }
@@ -400,6 +424,7 @@ public sealed class BSPrim : BSPhysObject
400 // Done at taint time so we're sure the physics engine is not using the variables 424 // Done at taint time so we're sure the physics engine is not using the variables
401 // Vehicle code changes the parameters for this vehicle type. 425 // Vehicle code changes the parameters for this vehicle type.
402 _vehicle.ProcessTypeChange(type); 426 _vehicle.ProcessTypeChange(type);
427 ActivateIfPhysical(false);
403 }); 428 });
404 } 429 }
405 } 430 }
@@ -408,6 +433,7 @@ public sealed class BSPrim : BSPhysObject
408 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 433 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
409 { 434 {
410 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 435 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
436 ActivateIfPhysical(false);
411 }); 437 });
412 } 438 }
413 public override void VehicleVectorParam(int param, OMV.Vector3 value) 439 public override void VehicleVectorParam(int param, OMV.Vector3 value)
@@ -415,6 +441,7 @@ public sealed class BSPrim : BSPhysObject
415 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 441 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
416 { 442 {
417 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 443 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
444 ActivateIfPhysical(false);
418 }); 445 });
419 } 446 }
420 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 447 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
@@ -422,6 +449,7 @@ public sealed class BSPrim : BSPhysObject
422 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 449 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
423 { 450 {
424 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 451 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
452 ActivateIfPhysical(false);
425 }); 453 });
426 } 454 }
427 public override void VehicleFlags(int param, bool remove) 455 public override void VehicleFlags(int param, bool remove)
@@ -436,9 +464,16 @@ public sealed class BSPrim : BSPhysObject
436 // Called from Scene when doing simulation step so we're in taint processing time. 464 // Called from Scene when doing simulation step so we're in taint processing time.
437 public override void StepVehicle(float timeStep) 465 public override void StepVehicle(float timeStep)
438 { 466 {
439 if (IsPhysical) 467 if (IsPhysical && _vehicle.IsActive)
440 { 468 {
441 _vehicle.Step(timeStep); 469 _vehicle.Step(timeStep);
470 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
471 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
472 {
473 // This resets the interpolation values and recomputes the tensor variables
474 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
475 });
476 */
442 } 477 }
443 } 478 }
444 479
@@ -463,7 +498,7 @@ public sealed class BSPrim : BSPhysObject
463 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 498 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
464 { 499 {
465 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 500 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
466 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 501 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
467 }); 502 });
468 } 503 }
469 } 504 }
@@ -471,12 +506,14 @@ public sealed class BSPrim : BSPhysObject
471 get { return _velocity; } 506 get { return _velocity; }
472 set { 507 set {
473 _velocity = value; 508 _velocity = value;
474 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 509 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
475 } 510 }
476 } 511 }
477 public override OMV.Vector3 Torque { 512 public override OMV.Vector3 Torque {
478 get { return _torque; } 513 get { return _torque; }
479 set { _torque = value; 514 set {
515 _torque = value;
516 AddAngularForce(_torque, false, false);
480 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 517 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
481 } 518 }
482 } 519 }
@@ -489,12 +526,17 @@ public sealed class BSPrim : BSPhysObject
489 get { return _acceleration; } 526 get { return _acceleration; }
490 set { _acceleration = value; } 527 set { _acceleration = value; }
491 } 528 }
529 public override OMV.Quaternion RawOrientation
530 {
531 get { return _orientation; }
532 set { _orientation = value; }
533 }
492 public override OMV.Quaternion Orientation { 534 public override OMV.Quaternion Orientation {
493 get { 535 get {
536 // Children move around because tied to parent. Get a fresh value.
494 if (!Linkset.IsRoot(this)) 537 if (!Linkset.IsRoot(this))
495 { 538 {
496 // Children move around because tied to parent. Get a fresh value. 539 _orientation = Linkset.Orientation(this);
497 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
498 } 540 }
499 return _orientation; 541 return _orientation;
500 } 542 }
@@ -507,7 +549,7 @@ public sealed class BSPrim : BSPhysObject
507 { 549 {
508 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 550 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
509 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 551 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
510 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 552 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
511 }); 553 });
512 } 554 }
513 } 555 }
@@ -516,13 +558,13 @@ public sealed class BSPrim : BSPhysObject
516 { 558 {
517 get 559 get
518 { 560 {
519 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); 561 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
520 return _orientation; 562 return _orientation;
521 } 563 }
522 set 564 set
523 { 565 {
524 _orientation = value; 566 _orientation = value;
525 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 567 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
526 } 568 }
527 } 569 }
528 public override int PhysicsActorType { 570 public override int PhysicsActorType {
@@ -539,6 +581,8 @@ public sealed class BSPrim : BSPhysObject
539 { 581 {
540 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 582 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
541 SetObjectDynamic(true); 583 SetObjectDynamic(true);
584 // whether phys-to-static or static-to-phys, the object is not moving.
585 ZeroMotion();
542 }); 586 });
543 } 587 }
544 } 588 }
@@ -576,7 +620,7 @@ public sealed class BSPrim : BSPhysObject
576 620
577 // Mangling all the physical properties requires the object not be in the physical world. 621 // Mangling all the physical properties requires the object not be in the physical world.
578 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 622 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
579 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); 623 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
580 624
581 // Set up the object physicalness (does gravity and collisions move this object) 625 // Set up the object physicalness (does gravity and collisions move this object)
582 MakeDynamic(IsStatic); 626 MakeDynamic(IsStatic);
@@ -590,24 +634,24 @@ public sealed class BSPrim : BSPhysObject
590 // Make solid or not (do things bounce off or pass through this object). 634 // Make solid or not (do things bounce off or pass through this object).
591 MakeSolid(IsSolid); 635 MakeSolid(IsSolid);
592 636
593 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); 637 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
594 638
595 // Rebuild its shape 639 // Rebuild its shape
596 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); 640 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
597 641
598 // Collision filter can be set only when the object is in the world 642 // Collision filter can be set only when the object is in the world
599 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0) 643 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
600 { 644 {
601 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask); 645 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
602 } 646 }
603 647
604 // Recompute any linkset parameters. 648 // Recompute any linkset parameters.
605 // When going from non-physical to physical, this re-enables the constraints that 649 // When going from non-physical to physical, this re-enables the constraints that
606 // had been automatically disabled when the mass was set to zero. 650 // had been automatically disabled when the mass was set to zero.
607 Linkset.Refresh(this, true); 651 Linkset.Refresh(this);
608 652
609 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 653 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
610 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); 654 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
611 } 655 }
612 656
613 // "Making dynamic" means changing to and from static. 657 // "Making dynamic" means changing to and from static.
@@ -620,75 +664,74 @@ public sealed class BSPrim : BSPhysObject
620 if (makeStatic) 664 if (makeStatic)
621 { 665 {
622 // Become a Bullet 'static' object type 666 // Become a Bullet 'static' object type
623 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 667 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
624 // Stop all movement 668 // Stop all movement
625 BulletSimAPI.ClearAllForces2(BSBody.ptr); 669 ZeroMotion();
626 // Center of mass is at the center of the object 670 // Center of mass is at the center of the object
627 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation); 671 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
628 // Mass is zero which disables a bunch of physics stuff in Bullet 672 // Mass is zero which disables a bunch of physics stuff in Bullet
629 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); 673 UpdatePhysicalMassProperties(0f);
630 // There is no inertia in a static object
631 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
632 // Set collision detection parameters 674 // Set collision detection parameters
633 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 675 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
634 { 676 {
635 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 677 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
636 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 678 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
637 } 679 }
638 // There can be special things needed for implementing linksets 680 // There can be special things needed for implementing linksets
639 Linkset.MakeStatic(this); 681 Linkset.MakeStatic(this);
640 // The activation state is 'disabled' so Bullet will not try to act on it. 682 // The activation state is 'disabled' so Bullet will not try to act on it.
641 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); 683 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
642 // Start it out sleeping and physical actions could wake it up. 684 // Start it out sleeping and physical actions could wake it up.
643 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 685 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
644 686
645 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 687 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
646 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 688 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
647 } 689 }
648 else 690 else
649 { 691 {
650 // Not a Bullet static object 692 // Not a Bullet static object
651 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 693 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
652 694
653 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 695 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
654 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction); 696 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
655 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution); 697 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
656 698
657 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 699 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
658 BulletSimAPI.ClearAllForces2(BSBody.ptr); 700 // Since this can be called multiple times, only zero forces when becoming physical
701 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
659 702
660 // For good measure, make sure the transform is set through to the motion state 703 // For good measure, make sure the transform is set through to the motion state
661 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 704 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
705
706 // Center of mass is at the center of the object
707 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
662 708
663 // A dynamic object has mass 709 // A dynamic object has mass
664 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); 710 UpdatePhysicalMassProperties(RawMass);
665 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
666 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
667 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
668 711
669 // Set collision detection parameters 712 // Set collision detection parameters
670 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 713 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
671 { 714 {
672 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 715 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
673 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 716 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
674 } 717 }
675 718
676 // Various values for simulation limits 719 // Various values for simulation limits
677 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 720 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
678 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); 721 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
679 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 722 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
680 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 723 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
681 724
682 // There might be special things needed for implementing linksets. 725 // There might be special things needed for implementing linksets.
683 Linkset.MakeDynamic(this); 726 Linkset.MakeDynamic(this);
684 727
685 // Force activation of the object so Bullet will act on it. 728 // Force activation of the object so Bullet will act on it.
686 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 729 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
687 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 730 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
688 // BulletSimAPI.Activate2(BSBody.ptr, true); 731 // BulletSimAPI.Activate2(BSBody.ptr, true);
689 732
690 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 733 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
691 BSBody.collisionMask = CollisionFilterGroups.ObjectMask; 734 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
692 } 735 }
693 } 736 }
694 737
@@ -698,7 +741,7 @@ public sealed class BSPrim : BSPhysObject
698 // the functions after this one set up the state of a possibly newly created collision body. 741 // the functions after this one set up the state of a possibly newly created collision body.
699 private void MakeSolid(bool makeSolid) 742 private void MakeSolid(bool makeSolid)
700 { 743 {
701 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr); 744 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
702 if (makeSolid) 745 if (makeSolid)
703 { 746 {
704 // Verify the previous code created the correct shape for this type of thing. 747 // Verify the previous code created the correct shape for this type of thing.
@@ -706,7 +749,7 @@ public sealed class BSPrim : BSPhysObject
706 { 749 {
707 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 750 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
708 } 751 }
709 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 752 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
710 } 753 }
711 else 754 else
712 { 755 {
@@ -714,22 +757,31 @@ public sealed class BSPrim : BSPhysObject
714 { 757 {
715 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 758 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
716 } 759 }
717 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 760 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
718 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 761 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
719 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 762 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
720 } 763 }
721 } 764 }
722 765
766 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
767 // they need waking up when parameters are changed.
768 // Called in taint-time!!
769 private void ActivateIfPhysical(bool forceIt)
770 {
771 if (IsPhysical)
772 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
773 }
774
723 // Turn on or off the flag controlling whether collision events are returned to the simulator. 775 // Turn on or off the flag controlling whether collision events are returned to the simulator.
724 private void EnableCollisions(bool wantsCollisionEvents) 776 private void EnableCollisions(bool wantsCollisionEvents)
725 { 777 {
726 if (wantsCollisionEvents) 778 if (wantsCollisionEvents)
727 { 779 {
728 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 780 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
729 } 781 }
730 else 782 else
731 { 783 {
732 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 784 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
733 } 785 }
734 } 786 }
735 787
@@ -774,9 +826,9 @@ public sealed class BSPrim : BSPhysObject
774 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 826 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
775 { 827 {
776 if (_floatOnWater) 828 if (_floatOnWater)
777 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 829 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
778 else 830 else
779 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 831 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
780 }); 832 });
781 } 833 }
782 } 834 }
@@ -798,8 +850,8 @@ public sealed class BSPrim : BSPhysObject
798 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 850 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
799 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 851 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
800 { 852 {
801 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 853 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
802 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); 854 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
803 }); 855 });
804 } 856 }
805 } 857 }
@@ -809,7 +861,7 @@ public sealed class BSPrim : BSPhysObject
809 } 861 }
810 set { 862 set {
811 _rotationalVelocity = value; 863 _rotationalVelocity = value;
812 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); 864 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
813 } 865 }
814 } 866 }
815 public override bool Kinematic { 867 public override bool Kinematic {
@@ -835,7 +887,7 @@ public sealed class BSPrim : BSPhysObject
835 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 887 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
836 // Buoyancy is faked by changing the gravity applied to the object 888 // Buoyancy is faked by changing the gravity applied to the object
837 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 889 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
838 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); 890 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
839 } 891 }
840 } 892 }
841 893
@@ -888,7 +940,7 @@ public sealed class BSPrim : BSPhysObject
888 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 940 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
889 return; 941 return;
890 } 942 }
891 BSScene.TaintCallback addForceOperation = delegate() 943 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
892 { 944 {
893 OMV.Vector3 fSum = OMV.Vector3.Zero; 945 OMV.Vector3 fSum = OMV.Vector3.Zero;
894 lock (m_accumulatedForces) 946 lock (m_accumulatedForces)
@@ -900,20 +952,60 @@ public sealed class BSPrim : BSPhysObject
900 } 952 }
901 m_accumulatedForces.Clear(); 953 m_accumulatedForces.Clear();
902 } 954 }
903 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); 955 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
904 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. 956 if (fSum != OMV.Vector3.Zero)
905 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); 957 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
906 }; 958 });
907 if (inTaintTime)
908 addForceOperation();
909 else
910 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
911 } 959 }
912 960
961 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
913 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 962 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
914 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 963 AddAngularForce(force, pushforce, false);
915 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
916 } 964 }
965 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
966 {
967 if (force.IsFinite())
968 {
969 // _force += force;
970 lock (m_accumulatedAngularForces)
971 m_accumulatedAngularForces.Add(new OMV.Vector3(force));
972 }
973 else
974 {
975 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
976 return;
977 }
978 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
979 {
980 OMV.Vector3 fSum = OMV.Vector3.Zero;
981 lock (m_accumulatedAngularForces)
982 {
983 // Sum the accumulated additional forces for one big force to apply once.
984 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
985 {
986 fSum += v;
987 }
988 m_accumulatedAngularForces.Clear();
989 }
990 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
991 if (fSum != OMV.Vector3.Zero)
992 {
993 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
994 _torque = fSum;
995 }
996 });
997 }
998 // A torque impulse.
999 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1000 {
1001 OMV.Vector3 applyImpulse = impulse;
1002 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1003 {
1004 DetailLog("{0},BSPrim.ApplyTorqueImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
1005 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1006 });
1007 }
1008
917 public override void SetMomentum(OMV.Vector3 momentum) { 1009 public override void SetMomentum(OMV.Vector3 momentum) {
918 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 1010 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
919 } 1011 }
@@ -1195,9 +1287,7 @@ public sealed class BSPrim : BSPhysObject
1195 1287
1196 returnMass = _density * volume; 1288 returnMass = _density * volume;
1197 1289
1198 /* 1290 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1199 * This change means each object keeps its own mass and the Mass property
1200 * will return the sum if we're part of a linkset.
1201 if (IsRootOfLinkset) 1291 if (IsRootOfLinkset)
1202 { 1292 {
1203 foreach (BSPrim prim in _childrenPrims) 1293 foreach (BSPrim prim in _childrenPrims)
@@ -1217,34 +1307,11 @@ public sealed class BSPrim : BSPhysObject
1217 }// end CalculateMass 1307 }// end CalculateMass
1218 #endregion Mass Calculation 1308 #endregion Mass Calculation
1219 1309
1220 // Copy prim's info into the BulletSim shape description structure
1221 public void FillShapeInfo(out ShapeData shape)
1222 {
1223 shape.ID = LocalID;
1224 shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
1225 shape.Position = _position;
1226 shape.Rotation = _orientation;
1227 shape.Velocity = _velocity;
1228 shape.Size = _size;
1229 shape.Scale = Scale;
1230 shape.Mass = _isPhysical ? _mass : 0f;
1231 shape.Buoyancy = _buoyancy;
1232 shape.HullKey = 0;
1233 shape.MeshKey = 0;
1234 shape.Friction = _friction;
1235 shape.Restitution = _restitution;
1236 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1237 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1238 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1239 }
1240 // Rebuild the geometry and object. 1310 // Rebuild the geometry and object.
1241 // This is called when the shape changes so we need to recreate the mesh/hull. 1311 // This is called when the shape changes so we need to recreate the mesh/hull.
1242 // Called at taint-time!!! 1312 // Called at taint-time!!!
1243 private void CreateGeomAndObject(bool forceRebuild) 1313 private void CreateGeomAndObject(bool forceRebuild)
1244 { 1314 {
1245 ShapeData shapeData;
1246 FillShapeInfo(out shapeData);
1247
1248 // If this prim is part of a linkset, we must remove and restore the physical 1315 // If this prim is part of a linkset, we must remove and restore the physical
1249 // links if the body is rebuilt. 1316 // links if the body is rebuilt.
1250 bool needToRestoreLinkset = false; 1317 bool needToRestoreLinkset = false;
@@ -1253,8 +1320,7 @@ public sealed class BSPrim : BSPhysObject
1253 // Updates BSBody and BSShape with the new information. 1320 // Updates BSBody and BSShape with the new information.
1254 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1321 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1255 // Returns 'true' if either the body or the shape was changed. 1322 // Returns 'true' if either the body or the shape was changed.
1256 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, 1323 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1257 null, delegate(BulletBody dBody)
1258 { 1324 {
1259 // Called if the current prim body is about to be destroyed. 1325 // Called if the current prim body is about to be destroyed.
1260 // Remove all the physical dependencies on the old body. 1326 // Remove all the physical dependencies on the old body.
@@ -1353,8 +1419,9 @@ public sealed class BSPrim : BSPhysObject
1353 1419
1354 PositionSanityCheck(true); 1420 PositionSanityCheck(true);
1355 1421
1356 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1422 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1357 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1423 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1424 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1358 1425
1359 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1426 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1360 1427
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index db0c99e..740f339 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -62,7 +62,7 @@ using OpenMetaverse;
62// 62//
63namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
64{ 64{
65public class BSScene : PhysicsScene, IPhysicsParameters 65public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 66{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
@@ -116,6 +116,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
116 // True if initialized and ready to do simulation steps 116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false; 117 private bool m_initialized = false;
118 118
119 // Flag which is true when processing taints.
120 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
121 public bool InTaintTime { get; private set; }
122
119 // Pinned memory used to pass step information between managed and unmanaged 123 // Pinned memory used to pass step information between managed and unmanaged
120 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
121 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
@@ -171,7 +175,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
171 } 175 }
172 } 176 }
173 private Object _taintLock = new Object(); // lock for using the next object 177 private Object _taintLock = new Object(); // lock for using the next object
174 private List<TaintCallbackEntry> _taintedObjects; 178 private List<TaintCallbackEntry> _taintOperations;
179 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
180 private List<TaintCallbackEntry> _postStepOperations;
175 181
176 // A pointer to an instance if this structure is passed to the C++ code 182 // A pointer to an instance if this structure is passed to the C++ code
177 // Used to pass basic configuration values to the unmanaged code. 183 // Used to pass basic configuration values to the unmanaged code.
@@ -203,7 +209,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
203 public override void Initialise(IMesher meshmerizer, IConfigSource config) 209 public override void Initialise(IMesher meshmerizer, IConfigSource config)
204 { 210 {
205 mesher = meshmerizer; 211 mesher = meshmerizer;
206 _taintedObjects = new List<TaintCallbackEntry>(); 212 _taintOperations = new List<TaintCallbackEntry>();
213 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
214 _postStepOperations = new List<TaintCallbackEntry>();
207 PhysObjects = new Dictionary<uint, BSPhysObject>(); 215 PhysObjects = new Dictionary<uint, BSPhysObject>();
208 Shapes = new BSShapeCollection(this); 216 Shapes = new BSShapeCollection(this);
209 217
@@ -266,6 +274,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
266 TerrainManager = new BSTerrainManager(this); 274 TerrainManager = new BSTerrainManager(this);
267 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 275 TerrainManager.CreateInitialGroundPlaneAndTerrain();
268 276
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
278
279 InTaintTime = false;
269 m_initialized = true; 280 m_initialized = true;
270 } 281 }
271 282
@@ -475,23 +486,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
475 if (!m_initialized) return 5.0f; 486 if (!m_initialized) return 5.0f;
476 487
477 // update the prim states while we know the physics engine is not busy 488 // update the prim states while we know the physics engine is not busy
478 int numTaints = _taintedObjects.Count; 489 int numTaints = _taintOperations.Count;
479 ProcessTaints(); 490 ProcessTaints();
480 491
481 // Some of the prims operate with special vehicle properties 492 // Some of the prims operate with special vehicle properties
482 ProcessVehicles(timeStep); 493 ProcessVehicles(timeStep);
483 numTaints += _taintedObjects.Count; 494 numTaints += _taintOperations.Count;
484 ProcessTaints(); // the vehicles might have added taints 495 ProcessTaints(); // the vehicles might have added taints
485 496
486 // step the physical world one interval 497 // step the physical world one interval
487 m_simulationStep++; 498 m_simulationStep++;
488 int numSubSteps = 0; 499 int numSubSteps = 0;
489 500
490 // DEBUG
491 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
492
493 try 501 try
494 { 502 {
503 // DumpVehicles(); // DEBUG
495 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 504 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
496 505
497 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 506 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@@ -500,6 +509,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
500 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 509 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
501 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 510 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
502 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 511 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
512 // DumpVehicles(); // DEBUG
503 } 513 }
504 catch (Exception e) 514 catch (Exception e)
505 { 515 {
@@ -575,6 +585,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
575 } 585 }
576 } 586 }
577 587
588 ProcessPostStepTaints();
589
578 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 590 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
579 // Only enable this in a limited test world with few objects. 591 // Only enable this in a limited test world with few objects.
580 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 592 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
@@ -670,6 +682,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
670 682
671 public override bool IsThreaded { get { return false; } } 683 public override bool IsThreaded { get { return false; } }
672 684
685 #region Taints
686
673 // Calls to the PhysicsActors can't directly call into the physics engine 687 // Calls to the PhysicsActors can't directly call into the physics engine
674 // because it might be busy. We delay changes to a known time. 688 // because it might be busy. We delay changes to a known time.
675 // We rely on C#'s closure to save and restore the context for the delegate. 689 // We rely on C#'s closure to save and restore the context for the delegate.
@@ -679,30 +693,48 @@ public class BSScene : PhysicsScene, IPhysicsParameters
679 693
680 lock (_taintLock) 694 lock (_taintLock)
681 { 695 {
682 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 696 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
683 } 697 }
684 698
685 return; 699 return;
686 } 700 }
687 701
702 // Sometimes a potentially tainted operation can be used in and out of taint time.
703 // This routine executes the command immediately if in taint-time otherwise it is queued.
704 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
705 {
706 if (inTaintTime)
707 callback();
708 else
709 TaintedObject(ident, callback);
710 }
711
688 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 712 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
689 // a callback into itself to do the actual property change. That callback is called 713 // a callback into itself to do the actual property change. That callback is called
690 // here just before the physics engine is called to step the simulation. 714 // here just before the physics engine is called to step the simulation.
691 public void ProcessTaints() 715 public void ProcessTaints()
692 { 716 {
693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 717 InTaintTime = true;
718 ProcessRegularTaints();
719 ProcessPostTaintTaints();
720 InTaintTime = false;
721 }
722
723 private void ProcessRegularTaints()
724 {
725 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
694 { 726 {
695 int taintCount = m_taintsToProcessPerStep; 727 int taintCount = m_taintsToProcessPerStep;
696 TaintCallbackEntry oneCallback = new TaintCallbackEntry(); 728 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
697 while (_taintedObjects.Count > 0 && taintCount-- > 0) 729 while (_taintOperations.Count > 0 && taintCount-- > 0)
698 { 730 {
699 bool gotOne = false; 731 bool gotOne = false;
700 lock (_taintLock) 732 lock (_taintLock)
701 { 733 {
702 if (_taintedObjects.Count > 0) 734 if (_taintOperations.Count > 0)
703 { 735 {
704 oneCallback = _taintedObjects[0]; 736 oneCallback = _taintOperations[0];
705 _taintedObjects.RemoveAt(0); 737 _taintOperations.RemoveAt(0);
706 gotOne = true; 738 gotOne = true;
707 } 739 }
708 } 740 }
@@ -746,6 +778,101 @@ public class BSScene : PhysicsScene, IPhysicsParameters
746 } 778 }
747 } 779 }
748 780
781 // Schedule an update to happen after all the regular taints are processed.
782 // Note that new requests for the same operation ("ident") for the same object ("ID")
783 // will replace any previous operation by the same object.
784 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
785 {
786 if (!m_initialized) return;
787
788 string uniqueIdent = ident + "-" + ID.ToString();
789 lock (_taintLock)
790 {
791 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
792 }
793
794 return;
795 }
796
797 private void ProcessPostTaintTaints()
798 {
799 if (_postTaintOperations.Count > 0)
800 {
801 Dictionary<string, TaintCallbackEntry> oldList;
802 lock (_taintLock)
803 {
804 oldList = _postTaintOperations;
805 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
806 }
807
808 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
809 {
810 try
811 {
812 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
813 kvp.Value.callback();
814 }
815 catch (Exception e)
816 {
817 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
818 }
819 }
820 oldList.Clear();
821 }
822 }
823
824 public void PostStepTaintObject(String ident, TaintCallback callback)
825 {
826 if (!m_initialized) return;
827
828 lock (_taintLock)
829 {
830 _postStepOperations.Add(new TaintCallbackEntry(ident, callback));
831 }
832
833 return;
834 }
835
836 private void ProcessPostStepTaints()
837 {
838 if (_postStepOperations.Count > 0)
839 {
840 List<TaintCallbackEntry> oldList;
841 lock (_taintLock)
842 {
843 oldList = _postStepOperations;
844 _postStepOperations = new List<TaintCallbackEntry>();
845 }
846
847 foreach (TaintCallbackEntry tcbe in oldList)
848 {
849 try
850 {
851 DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
852 tcbe.callback();
853 }
854 catch (Exception e)
855 {
856 m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
857 }
858 }
859 oldList.Clear();
860 }
861 }
862
863 public bool AssertInTaintTime(string whereFrom)
864 {
865 if (!InTaintTime)
866 {
867 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
868 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
869 Util.PrintCallStack();
870 }
871 return InTaintTime;
872 }
873
874 #endregion // Taints
875
749 #region Vehicles 876 #region Vehicles
750 877
751 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 878 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
@@ -970,49 +1097,49 @@ public class BSScene : PhysicsScene, IPhysicsParameters
970 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 1097 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].linearDamping; }, 1098 (s) => { return s.m_params[0].linearDamping; },
972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, 1099 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
973 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), 1100 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ),
974 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 1101 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
975 0f, 1102 0f,
976 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 1103 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
977 (s) => { return s.m_params[0].angularDamping; }, 1104 (s) => { return s.m_params[0].angularDamping; },
978 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, 1105 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
979 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), 1106 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ),
980 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 1107 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
981 0.2f, 1108 0.2f,
982 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 1109 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].deactivationTime; }, 1110 (s) => { return s.m_params[0].deactivationTime; },
984 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, 1111 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
985 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ), 1112 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
986 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 1113 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
987 0.8f, 1114 0.8f,
988 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 1115 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
989 (s) => { return s.m_params[0].linearSleepingThreshold; }, 1116 (s) => { return s.m_params[0].linearSleepingThreshold; },
990 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, 1117 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
991 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), 1118 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
992 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 1119 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
993 1.0f, 1120 1.0f,
994 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 1121 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
995 (s) => { return s.m_params[0].angularSleepingThreshold; }, 1122 (s) => { return s.m_params[0].angularSleepingThreshold; },
996 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, 1123 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
997 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), 1124 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
998 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 1125 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
999 0f, // set to zero to disable 1126 0f, // set to zero to disable
1000 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1127 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1001 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1128 (s) => { return s.m_params[0].ccdMotionThreshold; },
1002 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, 1129 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1003 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ), 1130 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
1004 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1131 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1005 0f, 1132 0f,
1006 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1133 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1007 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1134 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1008 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, 1135 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1009 (s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ), 1136 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1137 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 1138 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1139 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1140 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, 1141 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1015 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ), 1142 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1016 1143
1017 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1144 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1018 0.5f, 1145 0.5f,
@@ -1107,6 +1234,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1107 (s) => { return s.m_params[0].numberOfSolverIterations; }, 1234 (s) => { return s.m_params[0].numberOfSolverIterations; },
1108 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), 1235 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1109 1236
1237 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1238 (float)BSLinkset.LinksetImplementation.Compound,
1239 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1240 (s) => { return s.m_params[0].linksetImplementation; },
1241 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
1110 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 1242 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1111 ConfigurationParameters.numericFalse, 1243 ConfigurationParameters.numericFalse,
1112 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1244 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
@@ -1128,12 +1260,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1128 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1260 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1129 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1261 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1130 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 1262 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1131 0.001f, 1263 0.1f,
1132 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1264 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1133 (s) => { return s.m_params[0].linkConstraintCFM; }, 1265 (s) => { return s.m_params[0].linkConstraintCFM; },
1134 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1266 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1135 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1267 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1136 0.8f, 1268 0.1f,
1137 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1269 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1138 (s) => { return s.m_params[0].linkConstraintERP; }, 1270 (s) => { return s.m_params[0].linkConstraintERP; },
1139 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1271 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@@ -1259,7 +1391,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1259 // If the local ID is APPLY_TO_NONE, just change the default value 1391 // If the local ID is APPLY_TO_NONE, just change the default value
1260 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1392 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1261 // If the localID is a specific object, apply the parameter change to only that object 1393 // If the localID is a specific object, apply the parameter change to only that object
1262 protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) 1394 private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1263 { 1395 {
1264 List<uint> objectIDs = new List<uint>(); 1396 List<uint> objectIDs = new List<uint>();
1265 switch (localID) 1397 switch (localID)
@@ -1284,7 +1416,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 } 1416 }
1285 1417
1286 // schedule the actual updating of the paramter to when the phys engine is not busy 1418 // schedule the actual updating of the paramter to when the phys engine is not busy
1287 protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) 1419 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1288 { 1420 {
1289 float xval = val; 1421 float xval = val;
1290 List<uint> xlIDs = lIDs; 1422 List<uint> xlIDs = lIDs;
@@ -1326,12 +1458,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1326 1458
1327 #endregion Runtime settable parameters 1459 #endregion Runtime settable parameters
1328 1460
1461 // Debugging routine for dumping detailed physical information for vehicle prims
1462 private void DumpVehicles()
1463 {
1464 foreach (BSPrim prim in m_vehicles)
1465 {
1466 BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
1467 BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
1468 }
1469 }
1470
1329 // Invoke the detailed logger and output something if it's enabled. 1471 // Invoke the detailed logger and output something if it's enabled.
1330 public void DetailLog(string msg, params Object[] args) 1472 public void DetailLog(string msg, params Object[] args)
1331 { 1473 {
1332 PhysicsLogging.Write(msg, args); 1474 PhysicsLogging.Write(msg, args);
1333 // Add the Flush() if debugging crashes to get all the messages written out. 1475 // Add the Flush() if debugging crashes. Gets all the messages written out.
1334 // PhysicsLogging.Flush(); 1476 PhysicsLogging.Flush();
1335 } 1477 }
1336 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1478 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1337 public const string DetailLogZero = "0000000000"; 1479 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 30fa50a..29a23c0 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -34,11 +34,11 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public sealed class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 protected BSScene PhysicsScene { get; set; } 41 private BSScene PhysicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
@@ -48,6 +48,7 @@ public class BSShapeCollection : IDisposable
48 public IntPtr ptr; 48 public IntPtr ptr;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
51 } 52 }
52 53
53 // Description of a hull. 54 // Description of a hull.
@@ -57,6 +58,7 @@ public class BSShapeCollection : IDisposable
57 public IntPtr ptr; 58 public IntPtr ptr;
58 public int referenceCount; 59 public int referenceCount;
59 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
60 } 62 }
61 63
62 // The sharable set of meshes and hulls. Indexed by their shape hash. 64 // The sharable set of meshes and hulls. Indexed by their shape hash.
@@ -90,9 +92,10 @@ public class BSShapeCollection : IDisposable
90 // remove the physical constraints before the body is destroyed. 92 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!! 93 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 { 96 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
98
96 bool ret = false; 99 bool ret = false;
97 100
98 // This lock could probably be pushed down lower but building shouldn't take long 101 // This lock could probably be pushed down lower but building shouldn't take long
@@ -100,41 +103,38 @@ public class BSShapeCollection : IDisposable
100 { 103 {
101 // Do we have the correct geometry for this type of object? 104 // Do we have the correct geometry for this type of object?
102 // Updates prim.BSShape with information/pointers to shape. 105 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape. 106 // Returns 'true' of BSShape is changed to a new shape.
104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 107 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
105 // If we had to select a new shape geometry for the object, 108 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it. 109 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body 110 // Updates prim.BSBody with information/pointers to requested body
111 // Returns 'true' if BSBody was changed.
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
109 prim.BSShape, shapeData, bodyCallback); 113 prim.PhysShape, bodyCallback);
110 ret = newGeom || newBody; 114 ret = newGeom || newBody;
111 } 115 }
112 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}", 116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
113 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape); 117 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
114 118
115 return ret; 119 return ret;
116 } 120 }
117 121
118 // Track another user of a body 122 // Track another user of a body.
119 // We presume the caller has allocated the body. 123 // We presume the caller has allocated the body.
120 // Bodies only have one user so the body is just put into the world if not already there. 124 // Bodies only have one user so the body is just put into the world if not already there.
121 public void ReferenceBody(BulletBody body, bool inTaintTime) 125 public void ReferenceBody(BulletBody body, bool inTaintTime)
122 { 126 {
123 lock (m_collectionActivityLock) 127 lock (m_collectionActivityLock)
124 { 128 {
125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); 129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
126 BSScene.TaintCallback createOperation = delegate() 130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
127 { 131 {
128 if (!BulletSimAPI.IsInWorld2(body.ptr)) 132 if (!BulletSimAPI.IsInWorld2(body.ptr))
129 { 133 {
130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
132 } 136 }
133 }; 137 });
134 if (inTaintTime)
135 createOperation();
136 else
137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
138 } 138 }
139 } 139 }
140 140
@@ -147,25 +147,23 @@ public class BSShapeCollection : IDisposable
147 147
148 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
149 { 149 {
150 BSScene.TaintCallback removeOperation = delegate() 150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 151 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body.ptr.ToString("X"), inTaintTime); 153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 155 if (bodyCallback != null) bodyCallback(body);
156 156
157 // It may have already been removed from the world in which case the next is a NOOP. 157 if (BulletSimAPI.IsInWorld2(body.ptr))
158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 158 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 }
159 162
160 // Zero any reference to the shape so it is not freed when the body is deleted. 163 // Zero any reference to the shape so it is not freed when the body is deleted.
161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
163 }; 166 });
164 // If already in taint-time, do the operations now. Otherwise queue for later.
165 if (inTaintTime)
166 removeOperation();
167 else
168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
169 } 167 }
170 } 168 }
171 169
@@ -175,7 +173,7 @@ public class BSShapeCollection : IDisposable
175 // Meshes and hulls for the same shape have the same hash key. 173 // Meshes and hulls for the same shape have the same hash key.
176 // NOTE that native shapes are not added to the mesh list or removed. 174 // NOTE that native shapes are not added to the mesh list or removed.
177 // Returns 'true' if this is the initial reference to the shape. Otherwise reused. 175 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
178 private bool ReferenceShape(BulletShape shape) 176 public bool ReferenceShape(BulletShape shape)
179 { 177 {
180 bool ret = false; 178 bool ret = false;
181 switch (shape.type) 179 switch (shape.type)
@@ -193,6 +191,7 @@ public class BSShapeCollection : IDisposable
193 { 191 {
194 // This is a new reference to a mesh 192 // This is a new reference to a mesh
195 meshDesc.ptr = shape.ptr; 193 meshDesc.ptr = shape.ptr;
194 meshDesc.shapeKey = shape.shapeKey;
196 // We keep a reference to the underlying IMesh data so a hull can be built 195 // We keep a reference to the underlying IMesh data so a hull can be built
197 meshDesc.referenceCount = 1; 196 meshDesc.referenceCount = 1;
198 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
@@ -215,6 +214,7 @@ public class BSShapeCollection : IDisposable
215 { 214 {
216 // This is a new reference to a hull 215 // This is a new reference to a hull
217 hullDesc.ptr = shape.ptr; 216 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 218 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
@@ -239,7 +239,7 @@ public class BSShapeCollection : IDisposable
239 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
240 return; 240 return;
241 241
242 BSScene.TaintCallback dereferenceOperation = delegate() 242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 243 {
244 if (shape.ptr != IntPtr.Zero) 244 if (shape.ptr != IntPtr.Zero)
245 { 245 {
@@ -261,6 +261,9 @@ public class BSShapeCollection : IDisposable
261 case ShapeData.PhysicsShapeType.SHAPE_MESH: 261 case ShapeData.PhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback); 262 DereferenceMesh(shape, shapeCallback);
263 break; 263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_COMPOUND:
265 DereferenceCompound(shape, shapeCallback);
266 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 267 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break; 268 break;
266 default: 269 default:
@@ -268,18 +271,7 @@ public class BSShapeCollection : IDisposable
268 } 271 }
269 } 272 }
270 } 273 }
271 }; 274 });
272 if (inTaintTime)
273 {
274 lock (m_collectionActivityLock)
275 {
276 dereferenceOperation();
277 }
278 }
279 else
280 {
281 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
282 }
283 } 275 }
284 276
285 // Count down the reference count for a mesh shape 277 // Count down the reference count for a mesh shape
@@ -294,8 +286,8 @@ public class BSShapeCollection : IDisposable
294 if (shapeCallback != null) shapeCallback(shape); 286 if (shapeCallback != null) shapeCallback(shape);
295 meshDesc.lastReferenced = System.DateTime.Now; 287 meshDesc.lastReferenced = System.DateTime.Now;
296 Meshes[shape.shapeKey] = meshDesc; 288 Meshes[shape.shapeKey] = meshDesc;
297 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}", 289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
298 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 290 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
299 291
300 } 292 }
301 } 293 }
@@ -309,11 +301,94 @@ public class BSShapeCollection : IDisposable
309 { 301 {
310 hullDesc.referenceCount--; 302 hullDesc.referenceCount--;
311 // TODO: release the Bullet storage (aging old entries?) 303 // TODO: release the Bullet storage (aging old entries?)
304
305 // Tell upper layers that, if they have dependencies on this shape, this link is going away
312 if (shapeCallback != null) shapeCallback(shape); 306 if (shapeCallback != null) shapeCallback(shape);
307
313 hullDesc.lastReferenced = System.DateTime.Now; 308 hullDesc.lastReferenced = System.DateTime.Now;
314 Hulls[shape.shapeKey] = hullDesc; 309 Hulls[shape.shapeKey] = hullDesc;
315 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", 310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
316 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 311 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 }
313 }
314
315 // Remove a reference to a compound shape.
316 // Taking a compound shape apart is a little tricky because if you just delete the
317 // physical shape, it will free all the underlying children. We can't do that because
318 // they could be shared. So, this removes each of the children from the compound and
319 // dereferences them separately before destroying the compound collision object itself.
320 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr))
324 {
325 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return;
331 }
332
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335
336 for (int ii = numChildren - 1; ii >= 0; ii--)
337 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
339 DereferenceAnonCollisionShape(childShape);
340 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
342 }
343
344 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine.
346 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape)
348 {
349 MeshDesc meshDesc;
350 HullDesc hullDesc;
351
352 BulletShape shapeInfo = new BulletShape(cShape);
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 {
355 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey;
357 }
358 else
359 {
360 if (TryGetHullByPtr(cShape, out hullDesc))
361 {
362 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey;
364 }
365 else
366 {
367 if (BulletSimAPI.IsCompound2(cShape))
368 {
369 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND;
370 }
371 else
372 {
373 if (BulletSimAPI.IsNativeShape2(cShape))
374 {
375 shapeInfo.isNativeShape = true;
376 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
377 }
378 }
379 }
380 }
381
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383
384 if (shapeInfo.type != ShapeData.PhysicsShapeType.SHAPE_UNKNOWN)
385 {
386 DereferenceShape(shapeInfo, true, null);
387 }
388 else
389 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X"));
317 } 392 }
318 } 393 }
319 394
@@ -325,22 +400,46 @@ public class BSShapeCollection : IDisposable
325 // Info in prim.BSShape is updated to the new shape. 400 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt. 401 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time! 402 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, 403 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 { 404 {
331 bool ret = false; 405 bool ret = false;
332 bool haveShape = false; 406 bool haveShape = false;
333 bool nativeShapePossible = true;
334 407
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 408 if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 { 409 {
337 // an avatar capsule is close to a native shape (it is not shared) 410 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 411 ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 412 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); 413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
341 ret = true; 414 ret = true;
342 haveShape = true; 415 haveShape = true;
343 } 416 }
417
418 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == ShapeData.PhysicsShapeType.SHAPE_COMPOUND)
421 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true;
425 }
426
427 if (!haveShape)
428 {
429 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
430 }
431
432 return ret;
433 }
434
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 {
438 bool ret = false;
439 bool haveShape = false;
440 bool nativeShapePossible = true;
441 PrimitiveBaseShape pbs = prim.BaseShape;
442
344 // If the prim attributes are simple, this could be a simple Bullet native shape 443 // If the prim attributes are simple, this could be a simple Bullet native shape
345 if (!haveShape 444 if (!haveShape
346 && pbs != null 445 && pbs != null
@@ -354,98 +453,110 @@ public class BSShapeCollection : IDisposable
354 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
355 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
356 { 455 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
357 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
358 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
359 { 459 {
360 haveShape = true; 460 haveShape = true;
361 if (forceRebuild 461 if (forceRebuild
362 || prim.Scale != shapeData.Size 462 || prim.Scale != prim.Size
363 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 463 || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
364 ) 464 )
365 { 465 {
366 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 466 ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
367 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 467 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
368 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
369 prim.LocalID, forceRebuild, prim.BSShape); 469 prim.LocalID, forceRebuild, prim.PhysShape);
370 } 470 }
371 } 471 }
372 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
373 { 473 {
374 haveShape = true; 474 haveShape = true;
375 if (forceRebuild 475 if (forceRebuild
376 || prim.Scale != shapeData.Size 476 || prim.Scale != prim.Size
377 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 477 || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
378 ) 478 )
379 { 479 {
380 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, 480 ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX,
381 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 481 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
382 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
383 prim.LocalID, forceRebuild, prim.BSShape); 483 prim.LocalID, forceRebuild, prim.PhysShape);
384 } 484 }
385 } 485 }
386 } 486 }
487
387 // If a simple shape is not happening, create a mesh and possibly a hull. 488 // If a simple shape is not happening, create a mesh and possibly a hull.
388 // Note that if it's a native shape, the check for physical/non-physical is not
389 // made. Native shapes are best used in either case.
390 if (!haveShape && pbs != null) 489 if (!haveShape && pbs != null)
391 { 490 {
392 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 491 ret = CreateGeomMeshOrHull(prim, shapeCallback);
393 { 492 }
394 // Update prim.BSShape to reference a hull of this shape. 493
395 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); 494 return ret;
396 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 495 }
397 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 496
398 } 497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
399 else 498 {
400 { 499
401 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback); 500 bool ret = false;
402 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 501 // Note that if it's a native shape, the check for physical/non-physical is not
403 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 502 // made. Native shapes work in either case.
404 } 503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
504 {
505 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 }
510 else
511 {
512 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
405 } 515 }
406 return ret; 516 return ret;
407 } 517 }
408 518
409 // Creates a native shape and assignes it to prim.BSShape. 519 // Creates a native shape and assignes it to prim.BSShape.
410 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). 520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
411 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, 521 private bool GetReferenceToNativeShape(BSPhysObject prim,
412 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 522 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
413 ShapeDestructionCallback shapeCallback) 523 ShapeDestructionCallback shapeCallback)
414 { 524 {
415 // release any previous shape 525 // release any previous shape
416 DereferenceShape(prim.BSShape, true, shapeCallback); 526 DereferenceShape(prim.PhysShape, true, shapeCallback);
417 527
418 shapeData.Type = shapeType;
419 // Bullet native objects are scaled by the Bullet engine so pass the size in 528 // Bullet native objects are scaled by the Bullet engine so pass the size in
420 prim.Scale = shapeData.Size; 529 prim.Scale = prim.Size;
421 shapeData.Scale = shapeData.Size;
422 530
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); 531 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
424 532
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 533 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 534 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale); 535 prim.LocalID, newShape, prim.Scale);
428 536
429 prim.BSShape = newShape; 537 prim.PhysShape = newShape;
430 return true; 538 return true;
431 } 539 }
432 540
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, 541 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) 542 ShapeData.FixedShapeKey shapeKey)
435 { 543 {
436 BulletShape newShape; 544 BulletShape newShape;
437 // Need to make sure the passed shape information is for the native type. 545 // Need to make sure the passed shape information is for the native type.
438 ShapeData nativeShapeData = shapeData; 546 ShapeData nativeShapeData = new ShapeData();
439 nativeShapeData.Type = shapeType; 547 nativeShapeData.Type = shapeType;
548 nativeShapeData.ID = prim.LocalID;
549 nativeShapeData.Scale = prim.Scale;
550 nativeShapeData.Size = prim.Scale;
440 nativeShapeData.MeshKey = (ulong)shapeKey; 551 nativeShapeData.MeshKey = (ulong)shapeKey;
441 nativeShapeData.HullKey = (ulong)shapeKey; 552 nativeShapeData.HullKey = (ulong)shapeKey;
442 553
443 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 554 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
444 { 555 {
445 newShape = new BulletShape( 556 newShape = new BulletShape(
446 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale) 557 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
447 , shapeType); 558 , shapeType);
448 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale); 559 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
449 } 560 }
450 else 561 else
451 { 562 {
@@ -454,7 +565,7 @@ public class BSShapeCollection : IDisposable
454 if (newShape.ptr == IntPtr.Zero) 565 if (newShape.ptr == IntPtr.Zero)
455 { 566 {
456 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 567 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
457 LogHeader, nativeShapeData.ID, nativeShapeData.Type); 568 LogHeader, prim.LocalID, shapeType);
458 } 569 }
459 newShape.shapeKey = (System.UInt64)shapeKey; 570 newShape.shapeKey = (System.UInt64)shapeKey;
460 newShape.isNativeShape = true; 571 newShape.isNativeShape = true;
@@ -466,33 +577,32 @@ public class BSShapeCollection : IDisposable
466 // Dereferences previous shape in BSShape and adds a reference for this new shape. 577 // Dereferences previous shape in BSShape and adds a reference for this new shape.
467 // Returns 'true' of a mesh was actually built. Otherwise . 578 // Returns 'true' of a mesh was actually built. Otherwise .
468 // Called at taint-time! 579 // Called at taint-time!
469 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 580 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
470 ShapeDestructionCallback shapeCallback)
471 { 581 {
472 BulletShape newShape = new BulletShape(IntPtr.Zero); 582 BulletShape newShape = new BulletShape(IntPtr.Zero);
473 583
474 float lod; 584 float lod;
475 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); 585 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
476 586
477 // if this new shape is the same as last time, don't recreate the mesh 587 // if this new shape is the same as last time, don't recreate the mesh
478 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 588 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
479 return false; 589 return false;
480 590
481 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", 591 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
482 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 592 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
483 593
484 // Since we're recreating new, get rid of the reference to the previous shape 594 // Since we're recreating new, get rid of the reference to the previous shape
485 DereferenceShape(prim.BSShape, true, shapeCallback); 595 DereferenceShape(prim.PhysShape, true, shapeCallback);
486 596
487 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 597 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
488 // Take evasive action if the mesh was not constructed. 598 // Take evasive action if the mesh was not constructed.
489 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 599 newShape = VerifyMeshCreated(newShape, prim);
490 600
491 ReferenceShape(newShape); 601 ReferenceShape(newShape);
492 602
493 // meshes are already scaled by the meshmerizer 603 // meshes are already scaled by the meshmerizer
494 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 604 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
495 prim.BSShape = newShape; 605 prim.PhysShape = newShape;
496 606
497 return true; // 'true' means a new shape has been added to this prim 607 return true; // 'true' means a new shape has been added to this prim
498 } 608 }
@@ -526,7 +636,7 @@ public class BSShapeCollection : IDisposable
526 verticesAsFloats[vi++] = vv.Z; 636 verticesAsFloats[vi++] = vv.Z;
527 } 637 }
528 638
529 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 639 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
530 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 640 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
531 641
532 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 642 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
@@ -541,32 +651,31 @@ public class BSShapeCollection : IDisposable
541 651
542 // See that hull shape exists in the physical world and update prim.BSShape. 652 // See that hull shape exists in the physical world and update prim.BSShape.
543 // We could be creating the hull because scale changed or whatever. 653 // We could be creating the hull because scale changed or whatever.
544 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 654 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
545 ShapeDestructionCallback shapeCallback)
546 { 655 {
547 BulletShape newShape; 656 BulletShape newShape;
548 657
549 float lod; 658 float lod;
550 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); 659 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
551 660
552 // if the hull hasn't changed, don't rebuild it 661 // if the hull hasn't changed, don't rebuild it
553 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 662 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
554 return false; 663 return false;
555 664
556 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", 665 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
557 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 666 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
558 667
559 // Remove usage of the previous shape. 668 // Remove usage of the previous shape.
560 DereferenceShape(prim.BSShape, true, shapeCallback); 669 DereferenceShape(prim.PhysShape, true, shapeCallback);
561 670
562 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 671 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
563 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 672 newShape = VerifyMeshCreated(newShape, prim);
564 673
565 ReferenceShape(newShape); 674 ReferenceShape(newShape);
566 675
567 // hulls are already scaled by the meshmerizer 676 // hulls are already scaled by the meshmerizer
568 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 677 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
569 prim.BSShape = newShape; 678 prim.PhysShape = newShape;
570 return true; // 'true' means a new shape has been added to this prim 679 return true; // 'true' means a new shape has been added to this prim
571 } 680 }
572 681
@@ -685,9 +794,31 @@ public class BSShapeCollection : IDisposable
685 return; 794 return;
686 } 795 }
687 796
797 // Compound shapes are always built from scratch.
798 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
799 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
800 {
801 // Remove reference to the old shape
802 // Don't need to do this as the shape is freed when the new root shape is created below.
803 // DereferenceShape(prim.PhysShape, true, shapeCallback);
804
805 BulletShape cShape = new BulletShape(
806 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
807
808 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
809 CreateGeomMeshOrHull(prim, shapeCallback);
810 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
811 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
812 prim.LocalID, cShape, prim.PhysShape);
813
814 prim.PhysShape = cShape;
815
816 return true;
817 }
818
688 // Create a hash of all the shape parameters to be used as a key 819 // Create a hash of all the shape parameters to be used as a key
689 // for this particular shape. 820 // for this particular shape.
690 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) 821 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
691 { 822 {
692 // level of detail based on size and type of the object 823 // level of detail based on size and type of the object
693 float lod = PhysicsScene.MeshLOD; 824 float lod = PhysicsScene.MeshLOD;
@@ -695,40 +826,40 @@ public class BSShapeCollection : IDisposable
695 lod = PhysicsScene.SculptLOD; 826 lod = PhysicsScene.SculptLOD;
696 827
697 // Mega prims usually get more detail because one can interact with shape approximations at this size. 828 // Mega prims usually get more detail because one can interact with shape approximations at this size.
698 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); 829 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
699 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 830 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
700 lod = PhysicsScene.MeshMegaPrimLOD; 831 lod = PhysicsScene.MeshMegaPrimLOD;
701 832
702 retLod = lod; 833 retLod = lod;
703 return pbs.GetMeshKey(shapeData.Size, lod); 834 return pbs.GetMeshKey(size, lod);
704 } 835 }
705 // For those who don't want the LOD 836 // For those who don't want the LOD
706 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) 837 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
707 { 838 {
708 float lod; 839 float lod;
709 return ComputeShapeKey(shapeData, pbs, out lod); 840 return ComputeShapeKey(size, pbs, out lod);
710 } 841 }
711 842
712 // The creation of a mesh or hull can fail if an underlying asset is not available. 843 // The creation of a mesh or hull can fail if an underlying asset is not available.
713 // There are two cases: 1) the asset is not in the cache and it needs to be fetched; 844 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
714 // and 2) the asset cannot be converted (like decompressing JPEG2000s). 845 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
715 // The first case causes the asset to be fetched. The second case just requires 846 // The first case causes the asset to be fetched. The second case requires
716 // us to not loop forever. 847 // us to not loop forever.
717 // Called after creating a physical mesh or hull. If the physical shape was created, 848 // Called after creating a physical mesh or hull. If the physical shape was created,
718 // just return. 849 // just return.
719 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) 850 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
720 { 851 {
721 // If the shape was successfully created, nothing more to do 852 // If the shape was successfully created, nothing more to do
722 if (newShape.ptr != IntPtr.Zero) 853 if (newShape.ptr != IntPtr.Zero)
723 return newShape; 854 return newShape;
724 855
725 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 856 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
726 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) 857 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
727 { 858 {
728 prim.LastAssetBuildFailed = true; 859 prim.LastAssetBuildFailed = true;
729 BSPhysObject xprim = prim; 860 BSPhysObject xprim = prim;
730 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", 861 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
731 LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed); 862 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
732 Util.FireAndForget(delegate 863 Util.FireAndForget(delegate
733 { 864 {
734 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 865 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -745,7 +876,7 @@ public class BSShapeCollection : IDisposable
745 yprim.BaseShape.SculptData = asset.Data; 876 yprim.BaseShape.SculptData = asset.Data;
746 // This will cause the prim to see that the filler shape is not the right 877 // This will cause the prim to see that the filler shape is not the right
747 // one and try again to build the object. 878 // one and try again to build the object.
748 // No race condition with the native sphere setting since the rebuild is at taint time. 879 // No race condition with the normal shape setting since the rebuild is at taint time.
749 yprim.ForceBodyShapeRebuild(false); 880 yprim.ForceBodyShapeRebuild(false);
750 881
751 }); 882 });
@@ -757,13 +888,13 @@ public class BSShapeCollection : IDisposable
757 if (prim.LastAssetBuildFailed) 888 if (prim.LastAssetBuildFailed)
758 { 889 {
759 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", 890 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
760 LogHeader, shapeData.ID, pbs.SculptTexture); 891 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
761 } 892 }
762 } 893 }
763 894
764 // While we figure out the real problem, stick a simple native shape on the object. 895 // While we figure out the real problem, stick a simple native shape on the object.
765 BulletShape fillinShape = 896 BulletShape fillinShape =
766 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX); 897 BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX);
767 898
768 return fillinShape; 899 return fillinShape;
769 } 900 }
@@ -773,18 +904,18 @@ public class BSShapeCollection : IDisposable
773 // Returns 'true' if an object was actually created. 904 // Returns 'true' if an object was actually created.
774 // Called at taint-time. 905 // Called at taint-time.
775 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 906 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
776 ShapeData shapeData, BodyDestructionCallback bodyCallback) 907 BodyDestructionCallback bodyCallback)
777 { 908 {
778 bool ret = false; 909 bool ret = false;
779 910
780 // the mesh, hull or native shape must have already been created in Bullet 911 // the mesh, hull or native shape must have already been created in Bullet
781 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero); 912 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
782 913
783 // If there is an existing body, verify it's of an acceptable type. 914 // If there is an existing body, verify it's of an acceptable type.
784 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 915 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
785 if (!mustRebuild) 916 if (!mustRebuild)
786 { 917 {
787 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr); 918 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
788 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 919 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
789 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 920 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
790 { 921 {
@@ -796,27 +927,27 @@ public class BSShapeCollection : IDisposable
796 if (mustRebuild || forceRebuild) 927 if (mustRebuild || forceRebuild)
797 { 928 {
798 // Free any old body 929 // Free any old body
799 DereferenceBody(prim.BSBody, true, bodyCallback); 930 DereferenceBody(prim.PhysBody, true, bodyCallback);
800 931
801 BulletBody aBody; 932 BulletBody aBody;
802 IntPtr bodyPtr = IntPtr.Zero; 933 IntPtr bodyPtr = IntPtr.Zero;
803 if (prim.IsSolid) 934 if (prim.IsSolid)
804 { 935 {
805 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 936 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
806 shapeData.ID, shapeData.Position, shapeData.Rotation); 937 prim.LocalID, prim.RawPosition, prim.RawOrientation);
807 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 938 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
808 } 939 }
809 else 940 else
810 { 941 {
811 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 942 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
812 shapeData.ID, shapeData.Position, shapeData.Rotation); 943 prim.LocalID, prim.ForcePosition, prim.ForceOrientation);
813 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 944 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
814 } 945 }
815 aBody = new BulletBody(shapeData.ID, bodyPtr); 946 aBody = new BulletBody(prim.LocalID, bodyPtr);
816 947
817 ReferenceBody(aBody, true); 948 ReferenceBody(aBody, true);
818 949
819 prim.BSBody = aBody; 950 prim.PhysBody = aBody;
820 951
821 ret = true; 952 ret = true;
822 } 953 }
@@ -824,6 +955,42 @@ public class BSShapeCollection : IDisposable
824 return ret; 955 return ret;
825 } 956 }
826 957
958 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc)
959 {
960 bool ret = false;
961 MeshDesc foundDesc = new MeshDesc();
962 foreach (MeshDesc md in Meshes.Values)
963 {
964 if (md.ptr == addr)
965 {
966 foundDesc = md;
967 ret = true;
968 break;
969 }
970
971 }
972 outDesc = foundDesc;
973 return ret;
974 }
975
976 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc)
977 {
978 bool ret = false;
979 HullDesc foundDesc = new HullDesc();
980 foreach (HullDesc hd in Hulls.Values)
981 {
982 if (hd.ptr == addr)
983 {
984 foundDesc = hd;
985 ret = true;
986 break;
987 }
988
989 }
990 outDesc = foundDesc;
991 return ret;
992 }
993
827 private void DetailLog(string msg, params Object[] args) 994 private void DetailLog(string msg, params Object[] args)
828 { 995 {
829 if (PhysicsScene.PhysicsLogging.Enabled) 996 if (PhysicsScene.PhysicsLogging.Enabled)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 880859a..7c34af2 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -40,7 +40,7 @@ using OpenMetaverse;
40 40
41namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
42{ 42{
43public class BSTerrainManager 43public sealed class BSTerrainManager
44{ 44{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46 46
@@ -238,7 +238,7 @@ public class BSTerrainManager
238 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", 238 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
239 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); 239 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
240 240
241 BSScene.TaintCallback rebuildOperation = delegate() 241 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate()
242 { 242 {
243 if (MegaRegionParentPhysicsScene != null) 243 if (MegaRegionParentPhysicsScene != null)
244 { 244 {
@@ -337,14 +337,7 @@ public class BSTerrainManager
337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 337 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
338 338
339 m_terrainModified = true; 339 m_terrainModified = true;
340 }; 340 });
341
342 // There is the option to do the changes now (we're already in 'taint time'), or
343 // to do the Bullet operations later.
344 if (inTaintTime)
345 rebuildOperation();
346 else
347 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
348 } 341 }
349 else 342 else
350 { 343 {
@@ -364,7 +357,7 @@ public class BSTerrainManager
364 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 357 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
365 358
366 // Code that must happen at taint-time 359 // Code that must happen at taint-time
367 BSScene.TaintCallback createOperation = delegate() 360 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate()
368 { 361 {
369 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); 362 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
370 // Create a new mapInfo that will be filled with the new info 363 // Create a new mapInfo that will be filled with the new info
@@ -377,13 +370,7 @@ public class BSTerrainManager
377 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true); 370 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
378 371
379 m_terrainModified = true; 372 m_terrainModified = true;
380 }; 373 });
381
382 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
383 if (inTaintTime)
384 createOperation();
385 else
386 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
387 } 374 }
388 } 375 }
389 376
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 5ffd591..702bd77 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -194,6 +194,7 @@ public struct ShapeData
194 // following defined by BulletSim 194 // following defined by BulletSim
195 SHAPE_GROUNDPLANE = 20, 195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21, 196 SHAPE_TERRAIN = 21,
197 SHAPE_COMPOUND = 22,
197 }; 198 };
198 public uint ID; 199 public uint ID;
199 public PhysicsShapeType Type; 200 public PhysicsShapeType Type;
@@ -299,6 +300,7 @@ public struct ConfigurationParameters
299 public float shouldEnableFrictionCaching; 300 public float shouldEnableFrictionCaching;
300 public float numberOfSolverIterations; 301 public float numberOfSolverIterations;
301 302
303 public float linksetImplementation;
302 public float linkConstraintUseFrameOffset; 304 public float linkConstraintUseFrameOffset;
303 public float linkConstraintEnableTransMotor; 305 public float linkConstraintEnableTransMotor;
304 public float linkConstraintTransMotorMaxVel; 306 public float linkConstraintTransMotorMaxVel;
@@ -378,6 +380,7 @@ public enum CollisionFilterGroups : uint
378 BTerrainFilter = 1 << 11, 380 BTerrainFilter = 1 << 11,
379 BRaycastFilter = 1 << 12, 381 BRaycastFilter = 1 << 12,
380 BSolidFilter = 1 << 13, 382 BSolidFilter = 1 << 13,
383 BLinksetFilter = 1 << 14,
381 384
382 // The collsion filters and masked are defined in one place -- don't want them scattered 385 // The collsion filters and masked are defined in one place -- don't want them scattered
383 AvatarFilter = BCharacterFilter, 386 AvatarFilter = BCharacterFilter,
@@ -386,6 +389,8 @@ public enum CollisionFilterGroups : uint
386 ObjectMask = BAllFilter, 389 ObjectMask = BAllFilter,
387 StaticObjectFilter = BStaticFilter, 390 StaticObjectFilter = BStaticFilter,
388 StaticObjectMask = BAllFilter, 391 StaticObjectMask = BAllFilter,
392 LinksetFilter = BLinksetFilter,
393 LinksetMask = BAllFilter & ~BLinksetFilter,
389 VolumeDetectFilter = BSensorTrigger, 394 VolumeDetectFilter = BSensorTrigger,
390 VolumeDetectMask = ~BSensorTrigger, 395 VolumeDetectMask = ~BSensorTrigger,
391 TerrainFilter = BTerrainFilter, 396 TerrainFilter = BTerrainFilter,
@@ -395,8 +400,6 @@ public enum CollisionFilterGroups : uint
395 400
396}; 401};
397 402
398
399
400// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 403// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
401// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. 404// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
402public enum ConstraintParams : int 405public enum ConstraintParams : int
@@ -611,13 +614,22 @@ public static extern bool IsNativeShape2(IntPtr shape);
611public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 614public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
612 615
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr CreateCompoundShape2(IntPtr sim); 617public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
618
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
621
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
624
625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
626public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
615 627
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
617public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); 629public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
618 630
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 632public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
621 633
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); 635public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
@@ -881,10 +893,10 @@ public static extern float GetCcdMotionThreshold2(IntPtr obj);
881public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); 893public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
882 894
883[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
884public static extern float GetCcdSweepSphereRadius2(IntPtr obj); 896public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
885 897
886[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
887public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val); 899public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
888 900
889[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
890public static extern IntPtr GetUserPointer2(IntPtr obj); 902public static extern IntPtr GetUserPointer2(IntPtr obj);
diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
index 677bd7b..784f136 100644
--- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
+++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs
@@ -460,6 +460,15 @@ namespace OpenSim.Services.HypergridService
460 460
461 if (folders != null && folders.Length > 0) 461 if (folders != null && folders.Length > 0)
462 return folders[0]; 462 return folders[0];
463
464 // OK, so the RootFolder type didn't work. Let's look for any type with parent UUID.Zero.
465 folders = m_Database.GetFolders(
466 new string[] { "agentID", "folderName", "parentFolderID" },
467 new string[] { principalID.ToString(), "My Inventory", UUID.Zero.ToString() });
468
469 if (folders != null && folders.Length > 0)
470 return folders[0];
471
463 return null; 472 return null;
464 } 473 }
465 474