aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs229
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs13
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs16
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs185
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs45
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs220
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs232
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs479
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs27
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs44
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs174
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdeScene.cs2
13 files changed, 1066 insertions, 602 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 2a52e01..623ac8f 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject
41 41
42 // private bool _stopped; 42 // private bool _stopped;
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private OMV.Vector3 _scale;
45 private PrimitiveBaseShape _pbs;
46 private bool _grabbed; 44 private bool _grabbed;
47 private bool _selected; 45 private bool _selected;
48 private OMV.Vector3 _position; 46 private OMV.Vector3 _position;
@@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject
67 private bool _kinematic; 65 private bool _kinematic;
68 private float _buoyancy; 66 private float _buoyancy;
69 67
68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71
70 private OMV.Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
71 private bool _usePID; 73 private bool _usePID;
72 private float _PIDTau; 74 private float _PIDTau;
@@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject
84 _flying = isFlying; 86 _flying = isFlying;
85 _orientation = OMV.Quaternion.Identity; 87 _orientation = OMV.Quaternion.Identity;
86 _velocity = OMV.Vector3.Zero; 88 _velocity = OMV.Vector3.Zero;
89 _appliedVelocity = OMV.Vector3.Zero;
87 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
92 _avatarDensity = PhysicsScene.Params.avatarDensity;
88 93
89 // The dimensions of the avatar capsule are kept in the scale. 94 // The dimensions of the avatar capsule are kept in the scale.
90 // Physics creates a unit capsule which is scaled by the physics engine. 95 // Physics creates a unit capsule which is scaled by the physics engine.
91 ComputeAvatarScale(_size); 96 ComputeAvatarScale(_size);
92 _avatarDensity = PhysicsScene.Params.avatarDensity; 97 // set _avatarVolume and _mass based on capsule size, _density and Scale
93 // set _avatarVolume and _mass based on capsule size, _density and _scale
94 ComputeAvatarVolumeAndMass(); 98 ComputeAvatarVolumeAndMass();
99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw);
95 101
96 ShapeData shapeData = new ShapeData(); 102 ShapeData shapeData = new ShapeData();
97 shapeData.ID = LocalID; 103 shapeData.ID = LocalID;
@@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject
99 shapeData.Position = _position; 105 shapeData.Position = _position;
100 shapeData.Rotation = _orientation; 106 shapeData.Rotation = _orientation;
101 shapeData.Velocity = _velocity; 107 shapeData.Velocity = _velocity;
102 shapeData.Scale = _scale; 108 shapeData.Size = Scale;
109 shapeData.Scale = Scale;
103 shapeData.Mass = _mass; 110 shapeData.Mass = _mass;
104 shapeData.Buoyancy = _buoyancy; 111 shapeData.Buoyancy = _buoyancy;
105 shapeData.Static = ShapeData.numericFalse; 112 shapeData.Static = ShapeData.numericFalse;
106 shapeData.Friction = PhysicsScene.Params.avatarFriction; 113 shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
107 shapeData.Restitution = PhysicsScene.Params.avatarRestitution; 114 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
108 115
109 // do actual create at taint time 116 // do actual create at taint time
110 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 117 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
111 { 118 {
112 DetailLog("{0},BSCharacter.create,taint", LocalID); 119 DetailLog("{0},BSCharacter.create,taint", LocalID);
113 BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData); 120 // New body and shape into BSBody and BSShape
114 121 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null);
115 // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
116 // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
117 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
118 122
119 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID)); 123 SetPhysicalProperties();
120
121 // This works here because CreateObject has already put the character into the physical world.
122 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
123 (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
124 }); 124 });
125 return; 125 return;
126 } 126 }
@@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject
131 DetailLog("{0},BSCharacter.Destroy", LocalID); 131 DetailLog("{0},BSCharacter.Destroy", LocalID);
132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
133 { 133 {
134 BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID); 134 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
135 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
135 }); 136 });
136 } 137 }
137 138
139 private void SetPhysicalProperties()
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
142
143 ZeroMotion();
144 ForcePosition = _position;
145 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity;
147 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution);
148 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
149 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
150 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
151 {
152 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
153 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
154 }
155
156 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
157 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
158
159 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
162
163 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
165
166 // Do this after the object has been added to the world
167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
168 (uint)CollisionFilterGroups.AvatarFilter,
169 (uint)CollisionFilterGroups.AvatarMask);
170 }
171
138 public override void RequestPhysicsterseUpdate() 172 public override void RequestPhysicsterseUpdate()
139 { 173 {
140 base.RequestPhysicsterseUpdate(); 174 base.RequestPhysicsterseUpdate();
141 } 175 }
142 // No one calls this method so I don't know what it could possibly mean 176 // No one calls this method so I don't know what it could possibly mean
143 public override bool Stopped { 177 public override bool Stopped { get { return false; } }
144 get { return false; }
145 }
146 public override OMV.Vector3 Size { 178 public override OMV.Vector3 Size {
147 get 179 get
148 { 180 {
149 // Avatar capsule size is kept in the scale parameter. 181 // Avatar capsule size is kept in the scale parameter.
150 return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 182 return _size;
151 } 183 }
152 184
153 set { 185 set {
154 // When an avatar's size is set, only the height is changed 186 // When an avatar's size is set, only the height is changed.
155 // and that really only depends on the radius.
156 _size = value; 187 _size = value;
157 ComputeAvatarScale(_size); 188 ComputeAvatarScale(_size);
158
159 // TODO: something has to be done with the avatar's vertical position
160
161 ComputeAvatarVolumeAndMass(); 189 ComputeAvatarVolumeAndMass();
190 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}",
191 LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw);
162 192
163 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 193 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
164 { 194 {
165 BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true); 195 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale);
196 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw);
197 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
166 }); 198 });
167 199
168 } 200 }
169 } 201 }
170 public override PrimitiveBaseShape Shape { 202 public override OMV.Vector3 Scale { get; set; }
171 set { _pbs = value; 203 public override PrimitiveBaseShape Shape
172 } 204 {
205 set { BaseShape = value; }
173 } 206 }
207
174 public override bool Grabbed { 208 public override bool Grabbed {
175 set { _grabbed = value; 209 set { _grabbed = value; }
176 }
177 } 210 }
178 public override bool Selected { 211 public override bool Selected {
179 set { _selected = value; 212 set { _selected = value; }
180 }
181 } 213 }
182 public override void CrossingFailure() { return; } 214 public override void CrossingFailure() { return; }
183 public override void link(PhysicsActor obj) { return; } 215 public override void link(PhysicsActor obj) { return; }
@@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject
204 236
205 public override OMV.Vector3 Position { 237 public override OMV.Vector3 Position {
206 get { 238 get {
207 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 239 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
208 return _position; 240 return _position;
209 } 241 }
210 set { 242 set {
@@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject
214 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 246 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
215 { 247 {
216 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 248 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
217 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 249 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
218 }); 250 });
219 } 251 }
220 } 252 }
@@ -263,7 +295,7 @@ public class BSCharacter : BSPhysObject
263 // A version of the sanity check that also makes sure a new position value is 295 // A version of the sanity check that also makes sure a new position value is
264 // pushed back to the physics engine. This routine would be used by anyone 296 // pushed back to the physics engine. This routine would be used by anyone
265 // who is not already pushing the value. 297 // who is not already pushing the value.
266 private bool PositionSanityCheck2(bool atTaintTime) 298 private bool PositionSanityCheck(bool inTaintTime)
267 { 299 {
268 bool ret = false; 300 bool ret = false;
269 if (PositionSanityCheck()) 301 if (PositionSanityCheck())
@@ -273,9 +305,9 @@ public class BSCharacter : BSPhysObject
273 BSScene.TaintCallback sanityOperation = delegate() 305 BSScene.TaintCallback sanityOperation = delegate()
274 { 306 {
275 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 307 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 308 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
277 }; 309 };
278 if (atTaintTime) 310 if (inTaintTime)
279 sanityOperation(); 311 sanityOperation();
280 else 312 else
281 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); 313 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
@@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject
284 return ret; 316 return ret;
285 } 317 }
286 318
287 public override float Mass { 319 public override float Mass { get { return _mass; } }
288 get {
289 return _mass;
290 }
291 }
292 320
293 // used when we only want this prim's mass and not the linkset thing 321 // used when we only want this prim's mass and not the linkset thing
294 public override float MassRaw { get {return _mass; } } 322 public override float MassRaw { get {return _mass; } }
@@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject
301 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 329 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
302 { 330 {
303 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 331 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
304 BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force); 332 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
305 }); 333 });
306 } 334 }
307 } 335 }
308 336
309 public override int VehicleType { 337 // Avatars don't do vehicles
310 get { return 0; } 338 public override int VehicleType { get { return 0; } set { return; } }
311 set { return; }
312 }
313 public override void VehicleFloatParam(int param, float value) { } 339 public override void VehicleFloatParam(int param, float value) { }
314 public override void VehicleVectorParam(int param, OMV.Vector3 value) {} 340 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
315 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } 341 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@@ -328,10 +354,39 @@ public class BSCharacter : BSPhysObject
328 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 354 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
329 { 355 {
330 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 356 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
331 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity); 357 ForceVelocity = _velocity;
332 }); 358 });
333 } 359 }
334 } 360 }
361 public override OMV.Vector3 ForceVelocity {
362 get { return _velocity; }
363 set {
364 // Depending on whether the avatar is moving or not, change the friction
365 // to keep the avatar from slipping around
366 if (_velocity.Length() == 0)
367 {
368 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
369 {
370 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
371 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
372 }
373 }
374 else
375 {
376 if (_currentFriction != PhysicsScene.Params.avatarFriction)
377 {
378 _currentFriction = PhysicsScene.Params.avatarFriction;
379 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction);
380 }
381 }
382 _velocity = value;
383 // Remember the set velocity so we can suppress the reduction by friction, ...
384 _appliedVelocity = value;
385
386 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
387 BulletSimAPI.Activate2(BSBody.ptr, true);
388 }
389 }
335 public override OMV.Vector3 Torque { 390 public override OMV.Vector3 Torque {
336 get { return _torque; } 391 get { return _torque; }
337 set { _torque = value; 392 set { _torque = value;
@@ -353,8 +408,8 @@ public class BSCharacter : BSPhysObject
353 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 408 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
354 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 409 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
355 { 410 {
356 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 411 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
357 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 412 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
358 }); 413 });
359 } 414 }
360 } 415 }
@@ -382,12 +437,18 @@ public class BSCharacter : BSPhysObject
382 set { _isPhysical = value; 437 set { _isPhysical = value;
383 } 438 }
384 } 439 }
440 public override bool IsSolid {
441 get { return true; }
442 }
443 public override bool IsStatic {
444 get { return false; }
445 }
385 public override bool Flying { 446 public override bool Flying {
386 get { return _flying; } 447 get { return _flying; }
387 set { 448 set {
388 _flying = value; 449 _flying = value;
389 // simulate flying by changing the effect of gravity 450 // simulate flying by changing the effect of gravity
390 this.Buoyancy = ComputeBuoyancyFromFlying(_flying); 451 Buoyancy = ComputeBuoyancyFromFlying(_flying);
391 } 452 }
392 } 453 }
393 // Flying is implimented by changing the avatar's buoyancy. 454 // Flying is implimented by changing the avatar's buoyancy.
@@ -432,6 +493,10 @@ public class BSCharacter : BSPhysObject
432 get { return _rotationalVelocity; } 493 get { return _rotationalVelocity; }
433 set { _rotationalVelocity = value; } 494 set { _rotationalVelocity = value; }
434 } 495 }
496 public override OMV.Vector3 ForceRotationalVelocity {
497 get { return _rotationalVelocity; }
498 set { _rotationalVelocity = value; }
499 }
435 public override bool Kinematic { 500 public override bool Kinematic {
436 get { return _kinematic; } 501 get { return _kinematic; }
437 set { _kinematic = value; } 502 set { _kinematic = value; }
@@ -443,10 +508,19 @@ public class BSCharacter : BSPhysObject
443 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 508 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
444 { 509 {
445 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 510 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
446 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy); 511 ForceBuoyancy = _buoyancy;
447 }); 512 });
448 } 513 }
449 } 514 }
515 public override float ForceBuoyancy {
516 get { return _buoyancy; }
517 set { _buoyancy = value;
518 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
519 // Buoyancy is faked by changing the gravity applied to the object
520 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
521 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
522 }
523 }
450 524
451 // Used for MoveTo 525 // Used for MoveTo
452 public override OMV.Vector3 PIDTarget { 526 public override OMV.Vector3 PIDTarget {
@@ -507,27 +581,32 @@ public class BSCharacter : BSPhysObject
507 581
508 private void ComputeAvatarScale(OMV.Vector3 size) 582 private void ComputeAvatarScale(OMV.Vector3 size)
509 { 583 {
510 _scale.X = PhysicsScene.Params.avatarCapsuleRadius; 584 // The 'size' given by the simulator is the mid-point of the avatar
511 _scale.Y = PhysicsScene.Params.avatarCapsuleRadius; 585 // and X and Y are unspecified.
586
587 OMV.Vector3 newScale = OMV.Vector3.Zero;
588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius;
589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius;
512 590
513 // The 1.15 came from ODE but it seems to cause the avatar to float off the ground 591 // From the total height, remote the capsule half spheres that are at each end
514 // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y);
515 _scale.Z = (_size.Z) - (_scale.X + _scale.Y); 593 // newScale.Z = (size.Z * 2f);
594 Scale = newScale;
516 } 595 }
517 596
518 // set _avatarVolume and _mass based on capsule size, _density and _scale 597 // set _avatarVolume and _mass based on capsule size, _density and Scale
519 private void ComputeAvatarVolumeAndMass() 598 private void ComputeAvatarVolumeAndMass()
520 { 599 {
521 _avatarVolume = (float)( 600 _avatarVolume = (float)(
522 Math.PI 601 Math.PI
523 * _scale.X 602 * Scale.X
524 * _scale.Y // the area of capsule cylinder 603 * Scale.Y // the area of capsule cylinder
525 * _scale.Z // times height of capsule cylinder 604 * Scale.Z // times height of capsule cylinder
526 + 1.33333333f 605 + 1.33333333f
527 * Math.PI 606 * Math.PI
528 * _scale.X 607 * Scale.X
529 * Math.Min(_scale.X, _scale.Y) 608 * Math.Min(Scale.X, Scale.Y)
530 * _scale.Y // plus the volume of the capsule end caps 609 * Scale.Y // plus the volume of the capsule end caps
531 ); 610 );
532 _mass = _avatarDensity * _avatarVolume; 611 _mass = _avatarDensity * _avatarVolume;
533 } 612 }
@@ -542,7 +621,23 @@ public class BSCharacter : BSPhysObject
542 _acceleration = entprop.Acceleration; 621 _acceleration = entprop.Acceleration;
543 _rotationalVelocity = entprop.RotationalVelocity; 622 _rotationalVelocity = entprop.RotationalVelocity;
544 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 623 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
545 PositionSanityCheck2(true); 624 PositionSanityCheck(true);
625
626 // remember the current and last set values
627 LastEntityProperties = CurrentEntityProperties;
628 CurrentEntityProperties = entprop;
629
630 if (entprop.Velocity != LastEntityProperties.Velocity)
631 {
632 // Changes in the velocity are suppressed in avatars.
633 // That's just the way they are defined.
634 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
635 _velocity = avVel;
636 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel);
637 }
638
639 // Tell the linkset about this
640 Linkset.UpdateProperties(this);
546 641
547 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 642 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
548 // base.RequestPhysicsterseUpdate(); 643 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 63a4127..a20be3a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -49,9 +49,16 @@ public abstract class BSConstraint : IDisposable
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
51 m_enabled = false; 51 m_enabled = false;
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 52 if (m_constraint.ptr != IntPtr.Zero)
53 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); 53 {
54 m_constraint.ptr = System.IntPtr.Zero; 54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"),
59 success);
60 m_constraint.ptr = System.IntPtr.Zero;
61 }
55 } 62 }
56 } 63 }
57 64
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 4ba2f62..56342b8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -462,7 +462,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
462 return; 462 return;
463 463
464 // Set the prim's inertia to zero. The vehicle code handles that and this 464 // Set the prim's inertia to zero. The vehicle code handles that and this
465 // removes the torque action introduced by Bullet. 465 // removes the motion and torque actions introduced by Bullet.
466 Vector3 inertia = Vector3.Zero; 466 Vector3 inertia = Vector3.Zero;
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
@@ -481,7 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
481 m_lastPositionVector = Prim.ForcePosition; 481 m_lastPositionVector = Prim.ForcePosition;
482 482
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity); 484 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
485 }// end Step 485 }// end Step
486 486
487 // Apply the effect of the linear motor. 487 // Apply the effect of the linear motor.
@@ -540,7 +540,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
540 // add Gravity and Buoyancy 540 // add Gravity and Buoyancy
541 // There is some gravity, make a gravity force vector that is applied after object velocity. 541 // There is some gravity, make a gravity force vector that is applied after object velocity.
542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy)); 543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy));
544 544
545 /* 545 /*
546 * RA: Not sure why one would do this 546 * RA: Not sure why one would do this
@@ -678,10 +678,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
678 m_newVelocity.Z = 0; 678 m_newVelocity.Z = 0;
679 679
680 // Apply velocity 680 // Apply velocity
681 Prim.Velocity = m_newVelocity; 681 Prim.ForceVelocity = m_newVelocity;
682 // apply gravity force 682 // apply gravity force
683 // Why is this set here? The physics engine already does gravity. 683 // Why is this set here? The physics engine already does gravity.
684 // m_prim.AddForce(grav, false); 684 Prim.AddForce(grav, false, true);
685 685
686 // Apply friction 686 // Apply friction
687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
@@ -704,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
704 // m_lastAngularVelocity // what was last applied to body 704 // m_lastAngularVelocity // what was last applied to body
705 705
706 // Get what the body is doing, this includes 'external' influences 706 // Get what the body is doing, this includes 'external' influences
707 Vector3 angularVelocity = Prim.RotationalVelocity; 707 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
708 708
709 if (m_angularMotorApply > 0) 709 if (m_angularMotorApply > 0)
710 { 710 {
@@ -810,7 +810,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
811 811
812 // Apply to the body 812 // Apply to the body
813 Prim.RotationalVelocity = m_lastAngularVelocity; 813 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
814 814
815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); 815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
816 } //end MoveAngular 816 } //end MoveAngular
@@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
862 private void VDetailLog(string msg, params Object[] args) 862 private void VDetailLog(string msg, params Object[] args)
863 { 863 {
864 if (Prim.PhysicsScene.VehicleLoggingEnabled) 864 if (Prim.PhysicsScene.VehicleLoggingEnabled)
865 Prim.PhysicsScene.PhysicsLogging.Write(msg, args); 865 Prim.PhysicsScene.DetailLog(msg, args);
866 } 866 }
867 } 867 }
868} 868}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 3e82642..43b1262 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -52,8 +52,8 @@ public class BSLinkset
52 // the physical 'taint' children separately. 52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these 53 // After taint processing and before the simulation step, these
54 // two lists must be the same. 54 // two lists must be the same.
55 private List<BSPhysObject> m_children; 55 private HashSet<BSPhysObject> m_children;
56 private List<BSPhysObject> m_taintChildren; 56 private HashSet<BSPhysObject> m_taintChildren;
57 57
58 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
59 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -90,8 +90,8 @@ public class BSLinkset
90 m_nextLinksetID = 1; 90 m_nextLinksetID = 1;
91 PhysicsScene = scene; 91 PhysicsScene = scene;
92 LinksetRoot = parent; 92 LinksetRoot = parent;
93 m_children = new List<BSPhysObject>(); 93 m_children = new HashSet<BSPhysObject>();
94 m_taintChildren = new List<BSPhysObject>(); 94 m_taintChildren = new HashSet<BSPhysObject>();
95 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
96 } 96 }
97 97
@@ -160,6 +160,28 @@ public class BSLinkset
160 return ret; 160 return ret;
161 } 161 }
162 162
163 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime)
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184
163 // The object is going dynamic (physical). Do any setup necessary 185 // The object is going dynamic (physical). Do any setup necessary
164 // for a dynamic linkset. 186 // for a dynamic linkset.
165 // Only the state of the passed object can be modified. The rest of the linkset 187 // Only the state of the passed object can be modified. The rest of the linkset
@@ -182,22 +204,19 @@ public class BSLinkset
182 return false; 204 return false;
183 } 205 }
184 206
185 // When physical properties are changed the linkset needs to recalculate 207 // If the software is handling the movement of all the objects in a linkset
186 // its internal properties. 208 // (like if one doesn't use constraints for static linksets), this is called
187 // Called at runtime. 209 // when an update for the root of the linkset is received.
188 public void Refresh(BSPhysObject requestor) 210 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject)
189 { 212 {
190 // If there are no children, there can't be any constraints to recompute 213 // The root local properties have been updated. Apply to the children if appropriate.
191 if (!HasAnyChildren) 214 if (IsRoot(physObject) && HasAnyChildren)
192 return;
193
194 // Only the root does the recomputation
195 if (IsRoot(requestor))
196 { 215 {
197 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 216 if (!physObject.IsPhysical)
198 { 217 {
199 RecomputeLinksetConstraintVariables(); 218 // TODO: implement software linkset update for static object linksets
200 }); 219 }
201 } 220 }
202 } 221 }
203 222
@@ -215,13 +234,10 @@ public class BSLinkset
215 if (IsRoot(child)) 234 if (IsRoot(child))
216 { 235 {
217 // If the one with the dependency is root, must undo all children 236 // If the one with the dependency is root, must undo all children
218 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}", 237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
219 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); 238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
220 foreach (BSPhysObject bpo in m_taintChildren) 239
221 { 240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
222 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
223 ret = true;
224 }
225 } 241 }
226 else 242 else
227 { 243 {
@@ -229,20 +245,16 @@ public class BSLinkset
229 child.LocalID, 245 child.LocalID,
230 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), 246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
231 child.LocalID, child.BSBody.ptr.ToString("X")); 247 child.LocalID, child.BSBody.ptr.ToString("X"));
232 // Remove the dependency on the body of this one 248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
233 if (m_taintChildren.Contains(child)) 249 // Despite the function name, this removes any link to the specified object.
234 { 250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
235 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
236 ret = true;
237 }
238 } 251 }
239 } 252 }
240 return ret; 253 return ret;
241 } 254 }
242 255
243 // Routine used when rebuilding the body of the root of the linkset 256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
244 // This is called after RemoveAllLinksToRoot() to restore all the constraints. 257 // this routine will restore the removed constraints.
245 // This is called when the root body has been changed.
246 // Called at taint-time!! 258 // Called at taint-time!!
247 public void RestoreBodyDependencies(BSPrim child) 259 public void RestoreBodyDependencies(BSPrim child)
248 { 260 {
@@ -254,7 +266,7 @@ public class BSLinkset
254 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); 266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
255 foreach (BSPhysObject bpo in m_taintChildren) 267 foreach (BSPhysObject bpo in m_taintChildren)
256 { 268 {
257 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); 269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
258 } 270 }
259 } 271 }
260 else 272 else
@@ -263,7 +275,7 @@ public class BSLinkset
263 LinksetRoot.LocalID, 275 LinksetRoot.LocalID,
264 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), 276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
265 child.LocalID, child.BSBody.ptr.ToString("X")); 277 child.LocalID, child.BSBody.ptr.ToString("X"));
266 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); 278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
267 } 279 }
268 } 280 }
269 } 281 }
@@ -330,22 +342,22 @@ public class BSLinkset
330 { 342 {
331 m_children.Add(child); 343 m_children.Add(child);
332 344
333 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now 345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
334 BSPhysObject childx = child; 346 BSPhysObject childx = child;
335 347
336 DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
337 rootx.LocalID,
338 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
339 childx.LocalID, childx.BSBody.ptr.ToString("X"));
340 349
341 PhysicsScene.TaintedObject("AddChildToLinkset", delegate() 350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
342 { 351 {
343 DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); 352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
344 // build the physical binding between me and the child 353 rootx.LocalID,
345 m_taintChildren.Add(childx); 354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
346 355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
347 // Since this is taint-time, the body and shape could have changed for the child 356 // Since this is taint-time, the body and shape could have changed for the child
348 PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); 357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
349 }); 361 });
350 } 362 }
351 return; 363 return;
@@ -378,10 +390,8 @@ public class BSLinkset
378 390
379 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
380 { 392 {
381 if (m_taintChildren.Contains(childx)) 393 m_taintChildren.Remove(child);
382 m_taintChildren.Remove(childx); 394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
383
384 PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
385 RecomputeLinksetConstraintVariables(); 395 RecomputeLinksetConstraintVariables();
386 }); 396 });
387 397
@@ -396,8 +406,7 @@ public class BSLinkset
396 406
397 // Create a constraint between me (root of linkset) and the passed prim (the child). 407 // Create a constraint between me (root of linkset) and the passed prim (the child).
398 // Called at taint time! 408 // Called at taint time!
399 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, 409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
400 BSPhysObject childPrim, BulletBody childBody)
401 { 410 {
402 // Zero motion for children so they don't interpolate 411 // Zero motion for children so they don't interpolate
403 childPrim.ZeroMotion(); 412 childPrim.ZeroMotion();
@@ -409,33 +418,17 @@ public class BSLinkset
409 // real world coordinate of midpoint between the two objects 418 // real world coordinate of midpoint between the two objects
410 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
411 420
412 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
413 rootPrim.LocalID, 422 rootPrim.LocalID,
414 rootPrim.LocalID, rootBody.ptr.ToString("X"), 423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
415 childPrim.LocalID, childBody.ptr.ToString("X"), 424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
416 rootPrim.Position, childPrim.Position, midPoint); 425 rootPrim.Position, childPrim.Position, midPoint);
417 426
418 // create a constraint that allows no freedom of movement between the two objects 427 // create a constraint that allows no freedom of movement between the two objects
419 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
420 429
421 // There is great subtlty in these paramters. Notice the check for a ptr of zero.
422 // We pass the BulletBody structure into the taint in order to capture the pointer
423 // of the body at the time of constraint creation. This doesn't work for the very first
424 // construction because there is no body yet. The body
425 // is constructed later at taint time. Thus we use the body address at time of the
426 // taint creation but, if it is zero, use what's in the prim at the moment.
427 // There is a possible race condition since shape can change without a taint call
428 // (like changing to a mesh that is already constructed). The fix for that would be
429 // to only change BSShape at taint time thus syncronizing these operations at
430 // the cost of efficiency and lag.
431 BS6DofConstraint constrain = new BS6DofConstraint( 430 BS6DofConstraint constrain = new BS6DofConstraint(
432 PhysicsScene.World, 431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
433 rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
434 childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
435 midPoint,
436 true,
437 true
438 );
439 432
440 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
441 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms 434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@@ -452,7 +445,7 @@ public class BSLinkset
452 445
453 // create a constraint that allows no freedom of movement between the two objects 446 // create a constraint that allows no freedom of movement between the two objects
454 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
455 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
456 BS6DofConstraint constrain = new BS6DofConstraint( 449 BS6DofConstraint constrain = new BS6DofConstraint(
457 PhysicsScene.World, rootPrim.Body, childPrim.Body, 450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
458 OMV.Vector3.Zero, 451 OMV.Vector3.Zero,
@@ -486,39 +479,44 @@ public class BSLinkset
486 { 479 {
487 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
488 } 481 }
489
490 RecomputeLinksetConstraintVariables();
491 } 482 }
492 483
493 // Remove linkage between myself and a particular child 484 // Remove linkage between myself and a particular child
494 // The root and child bodies are passed in because we need to remove the constraint between 485 // The root and child bodies are passed in because we need to remove the constraint between
495 // the bodies that were at unlink time. 486 // the bodies that were at unlink time.
496 // Called at taint time! 487 // Called at taint time!
497 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, 488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
498 BSPhysObject childPrim, BulletBody childBody)
499 { 489 {
500 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 490 bool ret = false;
491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
501 rootPrim.LocalID, 492 rootPrim.LocalID,
502 rootPrim.LocalID, rootBody.ptr.ToString("X"), 493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
503 childPrim.LocalID, childBody.ptr.ToString("X")); 494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
504 495
505 // Find the constraint for this link and get rid of it from the overall collection and from my list 496 // Find the constraint for this link and get rid of it from the overall collection and from my list
506 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); 497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
507 503
508 // Make the child refresh its location 504 return ret;
509 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
510 } 505 }
511 506
512 /*
513 // Remove linkage between myself and any possible children I might have. 507 // Remove linkage between myself and any possible children I might have.
514 // Called at taint time! 508 // Called at taint time!
515 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
516 { 510 {
517 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
512 bool ret = false;
518 513
519 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); 514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
520 } 519 }
521 */
522 520
523 // Call each of the constraints that make up this linkset and recompute the 521 // Call each of the constraints that make up this linkset and recompute the
524 // various transforms and variables. Used when objects are added or removed 522 // various transforms and variables. Used when objects are added or removed
@@ -550,11 +548,17 @@ public class BSLinkset
550 { 548 {
551 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass 549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
552 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); 550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
553 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); 551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
554 foreach (BSPhysObject child in m_taintChildren) 555 foreach (BSPhysObject child in m_taintChildren)
555 { 556 {
556 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); 557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
557 } 559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
558 } 562 }
559 return; 563 return;
560 } 564 }
@@ -563,7 +567,8 @@ public class BSLinkset
563 // Invoke the detailed logger and output something if it's enabled. 567 // Invoke the detailed logger and output something if it's enabled.
564 private void DetailLog(string msg, params Object[] args) 568 private void DetailLog(string msg, params Object[] args)
565 { 569 {
566 PhysicsScene.PhysicsLogging.Write(msg, args); 570 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args);
567 } 572 }
568 573
569} 574}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 1ac8c59..ead6a08 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor
47 TypeName = typeName; 47 TypeName = typeName;
48 48
49 Linkset = new BSLinkset(PhysicsScene, this); 49 Linkset = new BSLinkset(PhysicsScene, this);
50 LastAssetBuildFailed = false;
50 51
51 CollisionCollection = new CollisionEventUpdate(); 52 CollisionCollection = new CollisionEventUpdate();
52 SubscribedEventsMs = 0; 53 SubscribedEventsMs = 0;
@@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor
69 // Reference to the physical shape (btCollisionShape) of this object 70 // Reference to the physical shape (btCollisionShape) of this object
70 public BulletShape BSShape; 71 public BulletShape BSShape;
71 72
73 // 'true' if the mesh's underlying asset failed to build.
74 // This will keep us from looping after the first time the build failed.
75 public bool LastAssetBuildFailed { get; set; }
76
77 // The objects base shape information. Null if not a prim type shape.
78 public PrimitiveBaseShape BaseShape { get; protected set; }
79
80 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; }
85
86 public abstract OMV.Vector3 Scale { get; set; }
87 public abstract bool IsSolid { get; }
88 public abstract bool IsStatic { get; }
89
72 // Stop all physical motion. 90 // Stop all physical motion.
73 public abstract void ZeroMotion(); 91 public abstract void ZeroMotion();
74 92
@@ -85,6 +103,14 @@ public abstract class BSPhysObject : PhysicsActor
85 103
86 public abstract OMV.Quaternion ForceOrientation { get; set; } 104 public abstract OMV.Quaternion ForceOrientation { get; set; }
87 105
106 public abstract OMV.Vector3 ForceVelocity { get; set; }
107
108 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
109
110 public abstract float ForceBuoyancy { get; set; }
111
112 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
113
88 #region Collisions 114 #region Collisions
89 115
90 // Requested number of milliseconds between collision events. Zero means disabled. 116 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -125,30 +151,28 @@ public abstract class BSPhysObject : PhysicsActor
125 // if someone has subscribed for collision events.... 151 // if someone has subscribed for collision events....
126 if (SubscribedEvents()) { 152 if (SubscribedEvents()) {
127 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 153 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
128 // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 154 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
129 // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 155 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
130 156
131 ret = true; 157 ret = true;
132 } 158 }
133 return ret; 159 return ret;
134 } 160 }
135 161
136 // Routine to send the collected collisions into the simulator. 162 // Send the collected collisions into the simulator.
137 // Also handles removal of this from the collection of objects with collisions if
138 // there are no collisions from this object. Mechanism is create one last
139 // collision event to make collision_end work.
140 // Called at taint time from within the Step() function thus no locking problems 163 // Called at taint time from within the Step() function thus no locking problems
141 // with CollisionCollection and ObjectsWithNoMoreCollisions. 164 // with CollisionCollection and ObjectsWithNoMoreCollisions.
142 // Return 'true' if there were some actual collisions passed up 165 // Return 'true' if there were some actual collisions passed up
143 public virtual bool SendCollisions() 166 public virtual bool SendCollisions()
144 { 167 {
145 bool ret = true; 168 bool ret = true;
169 // If the 'no collision' call, force it to happen right now so quick collision_end
170 bool force = CollisionCollection.Count == 0;
146 171
147 // throttle the collisions to the number of milliseconds specified in the subscription 172 // throttle the collisions to the number of milliseconds specified in the subscription
148 int nowTime = PhysicsScene.SimulationNowTime; 173 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
149 if (nowTime >= NextCollisionOkTime)
150 { 174 {
151 NextCollisionOkTime = nowTime + SubscribedEventsMs; 175 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
152 176
153 // We are called if we previously had collisions. If there are no collisions 177 // We are called if we previously had collisions. If there are no collisions
154 // this time, send up one last empty event so OpenSim can sense collision end. 178 // this time, send up one last empty event so OpenSim can sense collision end.
@@ -207,7 +231,8 @@ public abstract class BSPhysObject : PhysicsActor
207 // High performance detailed logging routine used by the physical objects. 231 // High performance detailed logging routine used by the physical objects.
208 protected void DetailLog(string msg, params Object[] args) 232 protected void DetailLog(string msg, params Object[] args)
209 { 233 {
210 PhysicsScene.PhysicsLogging.Write(msg, args); 234 if (PhysicsScene.PhysicsLogging.Enabled)
235 PhysicsScene.DetailLog(msg, args);
211 } 236 }
212} 237}
213} 238}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index f7b68ba..aeeb4dd 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -46,12 +46,10 @@ public sealed class BSPrim : BSPhysObject
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private static readonly string LogHeader = "[BULLETS PRIM]"; 47 private static readonly string LogHeader = "[BULLETS PRIM]";
48 48
49 private PrimitiveBaseShape _pbs; 49 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
50 50 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
51 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
52 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
53 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 51 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
54 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer 52 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
55 53
56 private bool _grabbed; 54 private bool _grabbed;
57 private bool _isSelected; 55 private bool _isSelected;
@@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject
98 _physicsActorType = (int)ActorTypes.Prim; 96 _physicsActorType = (int)ActorTypes.Prim;
99 _position = pos; 97 _position = pos;
100 _size = size; 98 _size = size;
101 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 99 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
102 _orientation = rotation; 100 _orientation = rotation;
103 _buoyancy = 1f; 101 _buoyancy = 1f;
104 _velocity = OMV.Vector3.Zero; 102 _velocity = OMV.Vector3.Zero;
105 _rotationalVelocity = OMV.Vector3.Zero; 103 _rotationalVelocity = OMV.Vector3.Zero;
106 _pbs = pbs; 104 BaseShape = pbs;
107 _isPhysical = pisPhysical; 105 _isPhysical = pisPhysical;
108 _isVolumeDetect = false; 106 _isVolumeDetect = false;
109 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 107 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
@@ -160,33 +158,32 @@ public sealed class BSPrim : BSPhysObject
160 get { return _size; } 158 get { return _size; }
161 set { 159 set {
162 _size = value; 160 _size = value;
163 PhysicsScene.TaintedObject("BSPrim.setSize", delegate() 161 ForceBodyShapeRebuild(false);
164 {
165 _mass = CalculateMass(); // changing size changes the mass
166 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
167 // scale and margins are set.
168 CreateGeomAndObject(true);
169 // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
170 });
171 } 162 }
172 } 163 }
173 // Scale is what we set in the physics engine. It is different than 'size' in that 164 // Scale is what we set in the physics engine. It is different than 'size' in that
174 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. 165 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
175 public OMV.Vector3 Scale 166 public override OMV.Vector3 Scale { get; set; }
176 { 167
177 get { return _scale; }
178 set { _scale = value; }
179 }
180 public override PrimitiveBaseShape Shape { 168 public override PrimitiveBaseShape Shape {
181 set { 169 set {
182 _pbs = value; 170 BaseShape = value;
183 PhysicsScene.TaintedObject("BSPrim.setShape", delegate() 171 ForceBodyShapeRebuild(false);
184 {
185 _mass = CalculateMass(); // changing the shape changes the mass
186 CreateGeomAndObject(true);
187 });
188 } 172 }
189 } 173 }
174 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 {
176 BSScene.TaintCallback rebuildOperation = delegate()
177 {
178 _mass = CalculateMass(); // changing the shape changes the mass
179 CreateGeomAndObject(true);
180 };
181 if (inTaintTime)
182 rebuildOperation();
183 else
184 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
185 return true;
186 }
190 public override bool Grabbed { 187 public override bool Grabbed {
191 set { _grabbed = value; 188 set { _grabbed = value;
192 } 189 }
@@ -196,7 +193,7 @@ public sealed class BSPrim : BSPhysObject
196 _isSelected = value; 193 _isSelected = value;
197 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 { 195 {
199 // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
200 SetObjectDynamic(false); 197 SetObjectDynamic(false);
201 }); 198 });
202 } 199 }
@@ -265,6 +262,11 @@ public sealed class BSPrim : BSPhysObject
265 return _position; 262 return _position;
266 } 263 }
267 set { 264 set {
265 // If you must push the position into the physics engine, use ForcePosition.
266 if (_position == value)
267 {
268 return;
269 }
268 _position = value; 270 _position = value;
269 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 271 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
270 PositionSanityCheck(); 272 PositionSanityCheck();
@@ -320,9 +322,9 @@ public sealed class BSPrim : BSPhysObject
320 } 322 }
321 323
322 // A version of the sanity check that also makes sure a new position value is 324 // A version of the sanity check that also makes sure a new position value is
323 // pushed back to the physics engine. This routine would be used by anyone 325 // pushed to the physics engine. This routine would be used by anyone
324 // who is not already pushing the value. 326 // who is not already pushing the value.
325 private bool PositionSanityCheck2(bool atTaintTime) 327 private bool PositionSanityCheck(bool inTaintTime)
326 { 328 {
327 bool ret = false; 329 bool ret = false;
328 if (PositionSanityCheck()) 330 if (PositionSanityCheck())
@@ -332,9 +334,9 @@ public sealed class BSPrim : BSPhysObject
332 BSScene.TaintCallback sanityOperation = delegate() 334 BSScene.TaintCallback sanityOperation = delegate()
333 { 335 {
334 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 336 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); 337 ForcePosition = _position;
336 }; 338 };
337 if (atTaintTime) 339 if (inTaintTime)
338 sanityOperation(); 340 sanityOperation();
339 else 341 else
340 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); 342 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
@@ -453,7 +455,6 @@ public sealed class BSPrim : BSPhysObject
453 } 455 }
454 return; 456 return;
455 } 457 }
456
457 public override OMV.Vector3 Velocity { 458 public override OMV.Vector3 Velocity {
458 get { return _velocity; } 459 get { return _velocity; }
459 set { 460 set {
@@ -465,6 +466,13 @@ public sealed class BSPrim : BSPhysObject
465 }); 466 });
466 } 467 }
467 } 468 }
469 public override OMV.Vector3 ForceVelocity {
470 get { return _velocity; }
471 set {
472 _velocity = value;
473 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
474 }
475 }
468 public override OMV.Vector3 Torque { 476 public override OMV.Vector3 Torque {
469 get { return _torque; } 477 get { return _torque; }
470 set { _torque = value; 478 set { _torque = value;
@@ -490,6 +498,8 @@ public sealed class BSPrim : BSPhysObject
490 return _orientation; 498 return _orientation;
491 } 499 }
492 set { 500 set {
501 if (_orientation == value)
502 return;
493 _orientation = value; 503 _orientation = value;
494 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 504 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
495 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 505 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
@@ -534,13 +544,13 @@ public sealed class BSPrim : BSPhysObject
534 } 544 }
535 545
536 // An object is static (does not move) if selected or not physical 546 // An object is static (does not move) if selected or not physical
537 private bool IsStatic 547 public override bool IsStatic
538 { 548 {
539 get { return _isSelected || !IsPhysical; } 549 get { return _isSelected || !IsPhysical; }
540 } 550 }
541 551
542 // An object is solid if it's not phantom and if it's not doing VolumeDetect 552 // An object is solid if it's not phantom and if it's not doing VolumeDetect
543 public bool IsSolid 553 public override bool IsSolid
544 { 554 {
545 get { return !IsPhantom && !_isVolumeDetect; } 555 get { return !IsPhantom && !_isVolumeDetect; }
546 } 556 }
@@ -570,7 +580,7 @@ public sealed class BSPrim : BSPhysObject
570 // Set up the object physicalness (does gravity and collisions move this object) 580 // Set up the object physicalness (does gravity and collisions move this object)
571 MakeDynamic(IsStatic); 581 MakeDynamic(IsStatic);
572 582
573 // Update vehicle specific parameters 583 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
574 _vehicle.Refresh(); 584 _vehicle.Refresh();
575 585
576 // Arrange for collision events if the simulator wants them 586 // Arrange for collision events if the simulator wants them
@@ -593,7 +603,7 @@ public sealed class BSPrim : BSPhysObject
593 // Recompute any linkset parameters. 603 // Recompute any linkset parameters.
594 // When going from non-physical to physical, this re-enables the constraints that 604 // When going from non-physical to physical, this re-enables the constraints that
595 // had been automatically disabled when the mass was set to zero. 605 // had been automatically disabled when the mass was set to zero.
596 Linkset.Refresh(this); 606 Linkset.Refresh(this, true);
597 607
598 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 608 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
599 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); 609 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
@@ -618,10 +628,18 @@ public sealed class BSPrim : BSPhysObject
618 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); 628 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
619 // There is no inertia in a static object 629 // There is no inertia in a static object
620 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); 630 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
631 // Set collision detection parameters
632 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
633 {
634 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
635 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
636 }
621 // There can be special things needed for implementing linksets 637 // There can be special things needed for implementing linksets
622 Linkset.MakeStatic(this); 638 Linkset.MakeStatic(this);
623 // The activation state is 'disabled' so Bullet will not try to act on it 639 // The activation state is 'disabled' so Bullet will not try to act on it.
624 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); 640 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
641 // Start it out sleeping and physical actions could wake it up.
642 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
625 643
626 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 644 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
627 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 645 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@@ -638,12 +656,22 @@ public sealed class BSPrim : BSPhysObject
638 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 656 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
639 BulletSimAPI.ClearAllForces2(BSBody.ptr); 657 BulletSimAPI.ClearAllForces2(BSBody.ptr);
640 658
659 // For good measure, make sure the transform is set through to the motion state
660 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
661
641 // A dynamic object has mass 662 // A dynamic object has mass
642 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); 663 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
643 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); 664 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
644 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); 665 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
645 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); 666 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
646 667
668 // Set collision detection parameters
669 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
670 {
671 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
672 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
673 }
674
647 // Various values for simulation limits 675 // Various values for simulation limits
648 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 676 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
649 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); 677 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
@@ -655,8 +683,8 @@ public sealed class BSPrim : BSPhysObject
655 683
656 // Force activation of the object so Bullet will act on it. 684 // Force activation of the object so Bullet will act on it.
657 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 685 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
658 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 686 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
659 BulletSimAPI.Activate2(BSBody.ptr, true); 687 // BulletSimAPI.Activate2(BSBody.ptr, true);
660 688
661 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 689 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
662 BSBody.collisionMask = CollisionFilterGroups.ObjectMask; 690 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
@@ -774,6 +802,15 @@ public sealed class BSPrim : BSPhysObject
774 }); 802 });
775 } 803 }
776 } 804 }
805 public override OMV.Vector3 ForceRotationalVelocity {
806 get {
807 return _rotationalVelocity;
808 }
809 set {
810 _rotationalVelocity = value;
811 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
812 }
813 }
777 public override bool Kinematic { 814 public override bool Kinematic {
778 get { return _kinematic; } 815 get { return _kinematic; }
779 set { _kinematic = value; 816 set { _kinematic = value;
@@ -786,13 +823,20 @@ public sealed class BSPrim : BSPhysObject
786 _buoyancy = value; 823 _buoyancy = value;
787 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 824 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
788 { 825 {
789 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 826 ForceBuoyancy = _buoyancy;
790 // Buoyancy is faked by changing the gravity applied to the object
791 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
792 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
793 }); 827 });
794 } 828 }
795 } 829 }
830 public override float ForceBuoyancy {
831 get { return _buoyancy; }
832 set {
833 _buoyancy = value;
834 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
835 // Buoyancy is faked by changing the gravity applied to the object
836 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
837 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
838 }
839 }
796 840
797 // Used for MoveTo 841 // Used for MoveTo
798 public override OMV.Vector3 PIDTarget { 842 public override OMV.Vector3 PIDTarget {
@@ -828,6 +872,9 @@ public sealed class BSPrim : BSPhysObject
828 872
829 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 873 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
830 public override void AddForce(OMV.Vector3 force, bool pushforce) { 874 public override void AddForce(OMV.Vector3 force, bool pushforce) {
875 AddForce(force, pushforce, false);
876 }
877 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
831 // for an object, doesn't matter if force is a pushforce or not 878 // for an object, doesn't matter if force is a pushforce or not
832 if (force.IsFinite()) 879 if (force.IsFinite())
833 { 880 {
@@ -840,11 +887,12 @@ public sealed class BSPrim : BSPhysObject
840 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 887 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
841 return; 888 return;
842 } 889 }
843 PhysicsScene.TaintedObject("BSPrim.AddForce", delegate() 890 BSScene.TaintCallback addForceOperation = delegate()
844 { 891 {
845 OMV.Vector3 fSum = OMV.Vector3.Zero; 892 OMV.Vector3 fSum = OMV.Vector3.Zero;
846 lock (m_accumulatedForces) 893 lock (m_accumulatedForces)
847 { 894 {
895 // Sum the accumulated additional forces for one big force to apply once.
848 foreach (OMV.Vector3 v in m_accumulatedForces) 896 foreach (OMV.Vector3 v in m_accumulatedForces)
849 { 897 {
850 fSum += v; 898 fSum += v;
@@ -854,7 +902,11 @@ public sealed class BSPrim : BSPhysObject
854 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); 902 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
855 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. 903 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
856 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); 904 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
857 }); 905 };
906 if (inTaintTime)
907 addForceOperation();
908 else
909 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
858 } 910 }
859 911
860 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 912 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -872,19 +924,19 @@ public sealed class BSPrim : BSPhysObject
872 float tmp; 924 float tmp;
873 925
874 float returnMass = 0; 926 float returnMass = 0;
875 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 927 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
876 float hollowVolume = hollowAmount * hollowAmount; 928 float hollowVolume = hollowAmount * hollowAmount;
877 929
878 switch (_pbs.ProfileShape) 930 switch (BaseShape.ProfileShape)
879 { 931 {
880 case ProfileShape.Square: 932 case ProfileShape.Square:
881 // default box 933 // default box
882 934
883 if (_pbs.PathCurve == (byte)Extrusion.Straight) 935 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
884 { 936 {
885 if (hollowAmount > 0.0) 937 if (hollowAmount > 0.0)
886 { 938 {
887 switch (_pbs.HollowShape) 939 switch (BaseShape.HollowShape)
888 { 940 {
889 case HollowShape.Square: 941 case HollowShape.Square:
890 case HollowShape.Same: 942 case HollowShape.Same:
@@ -908,19 +960,19 @@ public sealed class BSPrim : BSPhysObject
908 } 960 }
909 } 961 }
910 962
911 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 963 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
912 { 964 {
913 //a tube 965 //a tube
914 966
915 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 967 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
916 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 968 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
917 volume -= volume*tmp*tmp; 969 volume -= volume*tmp*tmp;
918 970
919 if (hollowAmount > 0.0) 971 if (hollowAmount > 0.0)
920 { 972 {
921 hollowVolume *= hollowAmount; 973 hollowVolume *= hollowAmount;
922 974
923 switch (_pbs.HollowShape) 975 switch (BaseShape.HollowShape)
924 { 976 {
925 case HollowShape.Square: 977 case HollowShape.Square:
926 case HollowShape.Same: 978 case HollowShape.Same:
@@ -945,13 +997,13 @@ public sealed class BSPrim : BSPhysObject
945 997
946 case ProfileShape.Circle: 998 case ProfileShape.Circle:
947 999
948 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1000 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
949 { 1001 {
950 volume *= 0.78539816339f; // elipse base 1002 volume *= 0.78539816339f; // elipse base
951 1003
952 if (hollowAmount > 0.0) 1004 if (hollowAmount > 0.0)
953 { 1005 {
954 switch (_pbs.HollowShape) 1006 switch (BaseShape.HollowShape)
955 { 1007 {
956 case HollowShape.Same: 1008 case HollowShape.Same:
957 case HollowShape.Circle: 1009 case HollowShape.Circle:
@@ -973,10 +1025,10 @@ public sealed class BSPrim : BSPhysObject
973 } 1025 }
974 } 1026 }
975 1027
976 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1028 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
977 { 1029 {
978 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 1030 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
979 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1031 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
980 volume *= (1.0f - tmp * tmp); 1032 volume *= (1.0f - tmp * tmp);
981 1033
982 if (hollowAmount > 0.0) 1034 if (hollowAmount > 0.0)
@@ -985,7 +1037,7 @@ public sealed class BSPrim : BSPhysObject
985 // calculate the hollow volume by it's shape compared to the prim shape 1037 // calculate the hollow volume by it's shape compared to the prim shape
986 hollowVolume *= hollowAmount; 1038 hollowVolume *= hollowAmount;
987 1039
988 switch (_pbs.HollowShape) 1040 switch (BaseShape.HollowShape)
989 { 1041 {
990 case HollowShape.Same: 1042 case HollowShape.Same:
991 case HollowShape.Circle: 1043 case HollowShape.Circle:
@@ -1009,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject
1009 break; 1061 break;
1010 1062
1011 case ProfileShape.HalfCircle: 1063 case ProfileShape.HalfCircle:
1012 if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1064 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1013 { 1065 {
1014 volume *= 0.52359877559829887307710723054658f; 1066 volume *= 0.52359877559829887307710723054658f;
1015 } 1067 }
@@ -1017,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject
1017 1069
1018 case ProfileShape.EquilateralTriangle: 1070 case ProfileShape.EquilateralTriangle:
1019 1071
1020 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1072 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1021 { 1073 {
1022 volume *= 0.32475953f; 1074 volume *= 0.32475953f;
1023 1075
@@ -1025,7 +1077,7 @@ public sealed class BSPrim : BSPhysObject
1025 { 1077 {
1026 1078
1027 // calculate the hollow volume by it's shape compared to the prim shape 1079 // calculate the hollow volume by it's shape compared to the prim shape
1028 switch (_pbs.HollowShape) 1080 switch (BaseShape.HollowShape)
1029 { 1081 {
1030 case HollowShape.Same: 1082 case HollowShape.Same:
1031 case HollowShape.Triangle: 1083 case HollowShape.Triangle:
@@ -1050,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject
1050 volume *= (1.0f - hollowVolume); 1102 volume *= (1.0f - hollowVolume);
1051 } 1103 }
1052 } 1104 }
1053 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1105 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1054 { 1106 {
1055 volume *= 0.32475953f; 1107 volume *= 0.32475953f;
1056 volume *= 0.01f * (float)(200 - _pbs.PathScaleX); 1108 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1057 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1109 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1058 volume *= (1.0f - tmp * tmp); 1110 volume *= (1.0f - tmp * tmp);
1059 1111
1060 if (hollowAmount > 0.0) 1112 if (hollowAmount > 0.0)
@@ -1062,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject
1062 1114
1063 hollowVolume *= hollowAmount; 1115 hollowVolume *= hollowAmount;
1064 1116
1065 switch (_pbs.HollowShape) 1117 switch (BaseShape.HollowShape)
1066 { 1118 {
1067 case HollowShape.Same: 1119 case HollowShape.Same:
1068 case HollowShape.Triangle: 1120 case HollowShape.Triangle:
@@ -1102,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject
1102 float profileBegin; 1154 float profileBegin;
1103 float profileEnd; 1155 float profileEnd;
1104 1156
1105 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) 1157 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1106 { 1158 {
1107 taperX1 = _pbs.PathScaleX * 0.01f; 1159 taperX1 = BaseShape.PathScaleX * 0.01f;
1108 if (taperX1 > 1.0f) 1160 if (taperX1 > 1.0f)
1109 taperX1 = 2.0f - taperX1; 1161 taperX1 = 2.0f - taperX1;
1110 taperX = 1.0f - taperX1; 1162 taperX = 1.0f - taperX1;
1111 1163
1112 taperY1 = _pbs.PathScaleY * 0.01f; 1164 taperY1 = BaseShape.PathScaleY * 0.01f;
1113 if (taperY1 > 1.0f) 1165 if (taperY1 > 1.0f)
1114 taperY1 = 2.0f - taperY1; 1166 taperY1 = 2.0f - taperY1;
1115 taperY = 1.0f - taperY1; 1167 taperY = 1.0f - taperY1;
1116 } 1168 }
1117 else 1169 else
1118 { 1170 {
1119 taperX = _pbs.PathTaperX * 0.01f; 1171 taperX = BaseShape.PathTaperX * 0.01f;
1120 if (taperX < 0.0f) 1172 if (taperX < 0.0f)
1121 taperX = -taperX; 1173 taperX = -taperX;
1122 taperX1 = 1.0f - taperX; 1174 taperX1 = 1.0f - taperX;
1123 1175
1124 taperY = _pbs.PathTaperY * 0.01f; 1176 taperY = BaseShape.PathTaperY * 0.01f;
1125 if (taperY < 0.0f) 1177 if (taperY < 0.0f)
1126 taperY = -taperY; 1178 taperY = -taperY;
1127 taperY1 = 1.0f - taperY; 1179 taperY1 = 1.0f - taperY;
@@ -1131,13 +1183,13 @@ public sealed class BSPrim : BSPhysObject
1131 1183
1132 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 1184 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1133 1185
1134 pathBegin = (float)_pbs.PathBegin * 2.0e-5f; 1186 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1135 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; 1187 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1136 volume *= (pathEnd - pathBegin); 1188 volume *= (pathEnd - pathBegin);
1137 1189
1138 // this is crude aproximation 1190 // this is crude aproximation
1139 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; 1191 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1140 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; 1192 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1141 volume *= (profileEnd - profileBegin); 1193 volume *= (profileEnd - profileBegin);
1142 1194
1143 returnMass = _density * volume; 1195 returnMass = _density * volume;
@@ -1172,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject
1172 shape.Position = _position; 1224 shape.Position = _position;
1173 shape.Rotation = _orientation; 1225 shape.Rotation = _orientation;
1174 shape.Velocity = _velocity; 1226 shape.Velocity = _velocity;
1175 shape.Scale = _scale; 1227 shape.Size = _size;
1228 shape.Scale = Scale;
1176 shape.Mass = _isPhysical ? _mass : 0f; 1229 shape.Mass = _isPhysical ? _mass : 0f;
1177 shape.Buoyancy = _buoyancy; 1230 shape.Buoyancy = _buoyancy;
1178 shape.HullKey = 0; 1231 shape.HullKey = 0;
@@ -1182,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject
1182 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1235 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1183 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1236 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1184 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; 1237 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1185 shape.Size = _size;
1186 } 1238 }
1187 // Rebuild the geometry and object. 1239 // Rebuild the geometry and object.
1188 // This is called when the shape changes so we need to recreate the mesh/hull. 1240 // This is called when the shape changes so we need to recreate the mesh/hull.
@@ -1199,11 +1251,12 @@ public sealed class BSPrim : BSPhysObject
1199 // Create the correct physical representation for this type of object. 1251 // Create the correct physical representation for this type of object.
1200 // Updates BSBody and BSShape with the new information. 1252 // Updates BSBody and BSShape with the new information.
1201 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1253 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1202 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs, 1254 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
1203 null, delegate(BulletBody dBody) 1255 null, delegate(BulletBody dBody)
1204 { 1256 {
1205 // Called if the current prim body is about to be destroyed. 1257 // Called if the current prim body is about to be destroyed.
1206 // Remove all the physical dependencies on the old body. 1258 // Remove all the physical dependencies on the old body.
1259 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1207 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1260 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1208 }); 1261 });
1209 1262
@@ -1292,7 +1345,11 @@ public sealed class BSPrim : BSPhysObject
1292 _acceleration = entprop.Acceleration; 1345 _acceleration = entprop.Acceleration;
1293 _rotationalVelocity = entprop.RotationalVelocity; 1346 _rotationalVelocity = entprop.RotationalVelocity;
1294 1347
1295 PositionSanityCheck2(true); 1348 // remember the current and last set values
1349 LastEntityProperties = CurrentEntityProperties;
1350 CurrentEntityProperties = entprop;
1351
1352 PositionSanityCheck(true);
1296 1353
1297 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1354 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1298 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1355 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
@@ -1304,12 +1361,15 @@ public sealed class BSPrim : BSPhysObject
1304 /* 1361 /*
1305 else 1362 else
1306 { 1363 {
1307 // For debugging, we can also report the movement of children 1364 // For debugging, report the movement of children
1308 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1365 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1309 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1366 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1310 entprop.Acceleration, entprop.RotationalVelocity); 1367 entprop.Acceleration, entprop.RotationalVelocity);
1311 } 1368 }
1312 */ 1369 */
1370 // The linkset implimentation might want to know about this.
1371
1372 Linkset.UpdateProperties(this);
1313 } 1373 }
1314} 1374}
1315} 1375}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index aaed7de..6621d39 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,7 +39,6 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Move all logic out of the C++ code and into the C# code for easier future modifications.
43// Test sculpties (verified that they don't work) 42// Test sculpties (verified that they don't work)
44// Compute physics FPS reasonably 43// Compute physics FPS reasonably
45// Based on material, set density and friction 44// Based on material, set density and friction
@@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
90 // let my minuions use my logger 89 // let my minuions use my logger
91 public ILog Logger { get { return m_log; } } 90 public ILog Logger { get { return m_log; } }
92 91
93 // If non-zero, the number of simulation steps between calls to the physics
94 // engine to output detailed physics stats. Debug logging level must be on also.
95 private int m_detailedStatsStep = 0;
96
97 public IMesher mesher; 92 public IMesher mesher;
98 // Level of Detail values kept as float because that's what the Meshmerizer wants 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD { get; private set; } 94 public float MeshLOD { get; private set; }
@@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
112 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
113 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
114 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep;
115 111
116 // A value of the time now so all the collision and update routines do not have to get their own 112 // A value of the time now so all the collision and update routines do not have to get their own
117 // Set to 'now' just before all the prims and actors are called for collisions and updates 113 // Set to 'now' just before all the prims and actors are called for collisions and updates
@@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
131 127
132 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed 128 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes 129 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
130 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
134 131
135 public float PID_D { get; private set; } // derivative 132 public float PID_D { get; private set; } // derivative
136 public float PID_P { get; private set; } // proportional 133 public float PID_P { get; private set; } // proportional
@@ -254,19 +251,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
254 251
255 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 252 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
256 // a child in a mega-region. 253 // a child in a mega-region.
257 // Turns out that Bullet really doesn't care about the extents of the simulated 254 // Bullet actually doesn't care about the extents of the simulated
258 // area. It tracks active objects no matter where they are. 255 // area. It tracks active objects no matter where they are.
259 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 256 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
260 257
261 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 258 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
262 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 259 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
263 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 260 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
264 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), 261 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
265 m_DebugLogCallbackHandle); 262 m_DebugLogCallbackHandle));
266
267 // Initialization to support the transition to a new API which puts most of the logic
268 // into the C# code so it is easier to modify and add to.
269 World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID));
270 263
271 Constraints = new BSConstraintCollection(World); 264 Constraints = new BSConstraintCollection(World);
272 265
@@ -331,7 +324,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
331 // Called directly from unmanaged code so don't do much 324 // Called directly from unmanaged code so don't do much
332 private void BulletLoggerPhysLog(string msg) 325 private void BulletLoggerPhysLog(string msg)
333 { 326 {
334 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 327 DetailLog("[BULLETS UNMANAGED]:" + msg);
335 } 328 }
336 329
337 public override void Dispose() 330 public override void Dispose()
@@ -363,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
363 } 356 }
364 357
365 // Anything left in the unmanaged code should be cleaned out 358 // Anything left in the unmanaged code should be cleaned out
366 BulletSimAPI.Shutdown(WorldID); 359 BulletSimAPI.Shutdown2(World.ptr);
367 360
368 // Not logging any more 361 // Not logging any more
369 PhysicsLogging.Close(); 362 PhysicsLogging.Close();
@@ -494,19 +487,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
494 m_simulationStep++; 487 m_simulationStep++;
495 int numSubSteps = 0; 488 int numSubSteps = 0;
496 489
497 // Sometimes needed for debugging to find out what happened before the step 490 // DEBUG
498 // PhysicsLogging.Flush(); 491 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
499 492
500 try 493 try
501 { 494 {
502 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 495 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
503 496
504 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 497 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
505 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 498 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
506 499
507 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 500 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
508 DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}", 501 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
509 DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 502 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
510 } 503 }
511 catch (Exception e) 504 catch (Exception e)
512 { 505 {
@@ -539,26 +532,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters
539 } 532 }
540 } 533 }
541 534
542 // This is a kludge to get avatar movement updates.
543 // the simulator expects collisions for avatars even if there are have been no collisions. This updates
544 // avatar animations and stuff.
545 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
546 foreach (BSPhysObject bsp in m_avatars)
547 bsp.SendCollisions();
548
549 // The above SendCollision's batch up the collisions on the objects. 535 // The above SendCollision's batch up the collisions on the objects.
550 // Now push the collisions into the simulator. 536 // Now push the collisions into the simulator.
551 if (ObjectsWithCollisions.Count > 0) 537 if (ObjectsWithCollisions.Count > 0)
552 { 538 {
553 foreach (BSPhysObject bsp in ObjectsWithCollisions) 539 foreach (BSPhysObject bsp in ObjectsWithCollisions)
554 if (!m_avatars.Contains(bsp)) // don't call avatars twice 540 if (!bsp.SendCollisions())
555 if (!bsp.SendCollisions()) 541 {
556 { 542 // If the object is done colliding, see that it's removed from the colliding list
557 // If the object is done colliding, see that it's removed from the colliding list 543 ObjectsWithNoMoreCollisions.Add(bsp);
558 ObjectsWithNoMoreCollisions.Add(bsp); 544 }
559 }
560 } 545 }
561 546
547 // This is a kludge to get avatar movement updates.
548 // The simulator expects collisions for avatars even if there are have been no collisions.
549 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars)
552 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
553 bsp.SendCollisions();
554
562 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 555 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
563 // Not done above because it is inside an iteration of ObjectWithCollisions. 556 // Not done above because it is inside an iteration of ObjectWithCollisions.
564 if (ObjectsWithNoMoreCollisions.Count > 0) 557 if (ObjectsWithNoMoreCollisions.Count > 0)
@@ -582,19 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
582 } 575 }
583 } 576 }
584 577
585 // If enabled, call into the physics engine to dump statistics 578 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
586 if (m_detailedStatsStep > 0) 579 // Only enable this in a limited test world with few objects.
587 { 580 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
588 if ((m_simulationStep % m_detailedStatsStep) == 0)
589 {
590 BulletSimAPI.DumpBulletStatistics();
591 }
592 }
593 581
594 // The physics engine returns the number of milliseconds it simulated this call. 582 // The physics engine returns the number of milliseconds it simulated this call.
595 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 583 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
596 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. 584 // We multiply by 55 to give a recognizable running rate (55 or less).
597 return numSubSteps * m_fixedTimeStep * 1000; 585 return numSubSteps * m_fixedTimeStep * 1000 * 55;
586 // return timeStep * 1000 * 55;
598 } 587 }
599 588
600 // Something has collided 589 // Something has collided
@@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
617 BSPhysObject collidee = null; 606 BSPhysObject collidee = null;
618 PhysObjects.TryGetValue(collidingWith, out collidee); 607 PhysObjects.TryGetValue(collidingWith, out collidee);
619 608
620 DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); 609 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
621 610
622 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 611 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
623 { 612 {
@@ -704,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters
704 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process
705 { 694 {
706 // swizzle a new list into the list location so we can process what's there 695 // swizzle a new list into the list location so we can process what's there
696 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0)
699 {
700 bool gotOne = false;
701 lock (_taintLock)
702 {
703 if (_taintedObjects.Count > 0)
704 {
705 oneCallback = _taintedObjects[0];
706 _taintedObjects.RemoveAt(0);
707 gotOne = true;
708 }
709 }
710 if (gotOne)
711 {
712 try
713 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
715 oneCallback.callback();
716 }
717 catch (Exception e)
718 {
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 }
721 }
722 }
723 /*
724 // swizzle a new list into the list location so we can process what's there
707 List<TaintCallbackEntry> oldList; 725 List<TaintCallbackEntry> oldList;
708 lock (_taintLock) 726 lock (_taintLock)
709 { 727 {
@@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
715 { 733 {
716 try 734 try
717 { 735 {
736 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
718 tcbe.callback(); 737 tcbe.callback();
719 } 738 }
720 catch (Exception e) 739 catch (Exception e)
@@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
723 } 742 }
724 } 743 }
725 oldList.Clear(); 744 oldList.Clear();
745 */
726 } 746 }
727 } 747 }
728 748
@@ -780,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
780 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 800 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
781 delegate float ParamGet(BSScene scene); 801 delegate float ParamGet(BSScene scene);
782 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); 802 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
803 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
783 804
784 private struct ParameterDefn 805 private struct ParameterDefn
785 { 806 {
@@ -789,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
789 public ParamUser userParam; // get the value from the configuration file 810 public ParamUser userParam; // get the value from the configuration file
790 public ParamGet getter; // return the current value stored for this parameter 811 public ParamGet getter; // return the current value stored for this parameter
791 public ParamSet setter; // set the current value for this parameter 812 public ParamSet setter; // set the current value for this parameter
813 public SetOnObject onObject; // set the value on an object in the physical domain
792 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) 814 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
793 { 815 {
794 name = n; 816 name = n;
@@ -797,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
797 userParam = u; 819 userParam = u;
798 getter = g; 820 getter = g;
799 setter = s; 821 setter = s;
822 onObject = null;
823 }
824 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
825 {
826 name = n;
827 desc = d;
828 defaultValue = v;
829 userParam = u;
830 getter = g;
831 setter = s;
832 onObject = o;
800 } 833 }
801 } 834 }
802 835
@@ -818,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
818 // 851 //
819 // The single letter parameters for the delegates are: 852 // The single letter parameters for the delegates are:
820 // s = BSScene 853 // s = BSScene
854 // o = BSPhysObject
821 // p = string parameter name 855 // p = string parameter name
822 // l = localID of referenced object 856 // l = localID of referenced object
823 // v = float value 857 // v = float value
@@ -834,6 +868,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
834 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 868 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
835 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, 869 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
836 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), 870 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
871 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
872 ConfigurationParameters.numericTrue,
873 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
874 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
875 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
837 876
838 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 877 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
839 8f, 878 8f,
@@ -876,6 +915,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
876 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 915 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
877 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 916 (s) => { return (float)s.m_maxUpdatesPerFrame; },
878 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 917 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
918 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
919 100f,
920 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
921 (s) => { return (float)s.m_taintsToProcessPerStep; },
922 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
879 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 923 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
880 10000.01f, 924 10000.01f,
881 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, 925 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
@@ -917,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters
917 -9.80665f, 961 -9.80665f,
918 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, 962 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
919 (s) => { return s.m_params[0].gravity; }, 963 (s) => { return s.m_params[0].gravity; },
920 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), 964 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
965 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
921 966
922 967
923 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", 968 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
924 0f, 969 0f,
925 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 970 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
926 (s) => { return s.m_params[0].linearDamping; }, 971 (s) => { return s.m_params[0].linearDamping; },
927 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ), 972 (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); } ),
928 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 974 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
929 0f, 975 0f,
930 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 976 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
931 (s) => { return s.m_params[0].angularDamping; }, 977 (s) => { return s.m_params[0].angularDamping; },
932 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ), 978 (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); } ),
933 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 980 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
934 0.2f, 981 0.2f,
935 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 982 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
936 (s) => { return s.m_params[0].deactivationTime; }, 983 (s) => { return s.m_params[0].deactivationTime; },
937 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ), 984 (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); } ),
938 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 986 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
939 0.8f, 987 0.8f,
940 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 988 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
941 (s) => { return s.m_params[0].linearSleepingThreshold; }, 989 (s) => { return s.m_params[0].linearSleepingThreshold; },
942 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 990 (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); } ),
943 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 992 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
944 1.0f, 993 1.0f,
945 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 994 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
946 (s) => { return s.m_params[0].angularSleepingThreshold; }, 995 (s) => { return s.m_params[0].angularSleepingThreshold; },
947 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 996 (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); } ),
948 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 998 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
949 0f, // set to zero to disable 999 0f, // set to zero to disable
950 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1000 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
951 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1001 (s) => { return s.m_params[0].ccdMotionThreshold; },
952 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 1002 (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); } ),
953 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1004 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
954 0f, 1005 0f,
955 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1006 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
956 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1007 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
957 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 1008 (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); } ),
958 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
959 0.1f, 1011 0.1f,
960 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
961 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1013 (s) => { return s.m_params[0].contactProcessingThreshold; },
962 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 1014 (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); } ),
963 1016
964 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1017 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
965 0.5f, 1018 0.5f,
966 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1019 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
967 (s) => { return s.m_params[0].terrainFriction; }, 1020 (s) => { return s.m_params[0].terrainFriction; },
968 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), 1021 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
969 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , 1022 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
970 0.8f, 1023 0.8f,
971 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, 1024 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
972 (s) => { return s.m_params[0].terrainHitFraction; }, 1025 (s) => { return s.m_params[0].terrainHitFraction; },
973 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), 1026 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
974 new ParameterDefn("TerrainRestitution", "Bouncyness" , 1027 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
975 0f, 1028 0f,
976 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1029 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
977 (s) => { return s.m_params[0].terrainRestitution; }, 1030 (s) => { return s.m_params[0].terrainRestitution; },
978 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1031 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
979 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1032 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
980 0.2f, 1033 0.2f,
981 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1034 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
982 (s) => { return s.m_params[0].avatarFriction; }, 1035 (s) => { return s.m_params[0].avatarFriction; },
983 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), 1036 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1037 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1038 10f,
1039 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1040 (s) => { return s.m_params[0].avatarStandingFriction; },
1041 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
984 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 1042 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
985 60f, 1043 60f,
986 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1044 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
@@ -1070,12 +1128,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1070 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1128 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1071 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1129 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1072 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 1130 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1073 0.1f, 1131 0.001f,
1074 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1132 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1075 (s) => { return s.m_params[0].linkConstraintCFM; }, 1133 (s) => { return s.m_params[0].linkConstraintCFM; },
1076 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1134 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1077 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1135 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1078 0.2f, 1136 0.8f,
1079 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1137 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1080 (s) => { return s.m_params[0].linkConstraintERP; }, 1138 (s) => { return s.m_params[0].linkConstraintERP; },
1081 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1139 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@@ -1085,11 +1143,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1085 (s) => { return s.m_params[0].linkConstraintSolverIterations; }, 1143 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1086 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), 1144 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1087 1145
1088 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1146 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1089 0f, 1147 0f,
1090 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1148 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1091 (s) => { return (float)s.m_detailedStatsStep; }, 1149 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1092 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1150 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1093 }; 1151 };
1094 1152
1095 // Convert a boolean to our numeric true and false values 1153 // Convert a boolean to our numeric true and false values
@@ -1197,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1197 return ret; 1255 return ret;
1198 } 1256 }
1199 1257
1200 // check to see if we are updating a parameter for a particular or all of the prims
1201 protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val)
1202 {
1203 List<uint> operateOn;
1204 lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys);
1205 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1206 }
1207
1208 // update all the localIDs specified 1258 // update all the localIDs specified
1209 // If the local ID is APPLY_TO_NONE, just change the default value 1259 // If the local ID is APPLY_TO_NONE, just change the default value
1210 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1260 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1211 // If the localID is a specific object, apply the parameter change to only that object 1261 // If the localID is a specific object, apply the parameter change to only that object
1212 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1262 protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1213 { 1263 {
1264 List<uint> objectIDs = new List<uint>();
1214 switch (localID) 1265 switch (localID)
1215 { 1266 {
1216 case PhysParameterEntry.APPLY_TO_NONE: 1267 case PhysParameterEntry.APPLY_TO_NONE:
1217 defaultLoc = val; // setting only the default value 1268 defaultLoc = val; // setting only the default value
1269 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1270 objectIDs.Add(TERRAIN_ID);
1271 TaintedUpdateParameter(parm, objectIDs, val);
1218 break; 1272 break;
1219 case PhysParameterEntry.APPLY_TO_ALL: 1273 case PhysParameterEntry.APPLY_TO_ALL:
1220 defaultLoc = val; // setting ALL also sets the default value 1274 defaultLoc = val; // setting ALL also sets the default value
1221 List<uint> objectIDs = lIDs; 1275 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1222 string xparm = parm.ToLower(); 1276 TaintedUpdateParameter(parm, objectIDs, val);
1223 float xval = val;
1224 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1225 foreach (uint lID in objectIDs)
1226 {
1227 BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval);
1228 }
1229 });
1230 break; 1277 break;
1231 default: 1278 default:
1232 // setting only one localID 1279 // setting only one localID
1233 TaintedUpdateParameter(parm, localID, val); 1280 objectIDs.Add(localID);
1281 TaintedUpdateParameter(parm, objectIDs, val);
1234 break; 1282 break;
1235 } 1283 }
1236 } 1284 }
1237 1285
1238 // schedule the actual updating of the paramter to when the phys engine is not busy 1286 // schedule the actual updating of the paramter to when the phys engine is not busy
1239 protected void TaintedUpdateParameter(string parm, uint localID, float val) 1287 protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1240 { 1288 {
1241 uint xlocalID = localID;
1242 string xparm = parm.ToLower();
1243 float xval = val; 1289 float xval = val;
1244 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1290 List<uint> xlIDs = lIDs;
1245 BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval); 1291 string xparm = parm;
1292 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1293 ParameterDefn thisParam;
1294 if (TryGetParameter(xparm, out thisParam))
1295 {
1296 if (thisParam.onObject != null)
1297 {
1298 foreach (uint lID in xlIDs)
1299 {
1300 BSPhysObject theObject = null;
1301 PhysObjects.TryGetValue(lID, out theObject);
1302 thisParam.onObject(this, theObject, xval);
1303 }
1304 }
1305 }
1246 }); 1306 });
1247 } 1307 }
1248 1308
@@ -1270,6 +1330,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1270 public void DetailLog(string msg, params Object[] args) 1330 public void DetailLog(string msg, params Object[] args)
1271 { 1331 {
1272 PhysicsLogging.Write(msg, args); 1332 PhysicsLogging.Write(msg, args);
1333 // Add the Flush() if debugging crashes to get all the messages written out.
1334 // PhysicsLogging.Flush();
1273 } 1335 }
1274 // used to fill in the LocalID when there isn't one 1336 // used to fill in the LocalID when there isn't one
1275 public const string DetailLogZero = "0000000000"; 1337 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 399a133..d3ba273 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable
51 } 51 }
52 52
53 // Description of a hull. 53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects 54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
55 private struct HullDesc 55 private struct HullDesc
56 { 56 {
57 public IntPtr ptr; 57 public IntPtr ptr;
@@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable
59 public DateTime lastReferenced; 59 public DateTime lastReferenced;
60 } 60 }
61 61
62 private struct BodyDesc 62 // The sharable set of meshes and hulls. Indexed by their shape hash.
63 { 63 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
64 public IntPtr ptr; 64 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
71 private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73 65
74 public BSShapeCollection(BSScene physScene) 66 public BSShapeCollection(BSScene physScene)
75 { 67 {
@@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable
92 // First checks the shape and updates that if necessary then makes 84 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type. 85 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed. 86 // Return 'true' if either the body or the shape changed.
87 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
88 // the current shape or body is destroyed. This allows the caller to remove any
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed.
95 // Called at taint-time!! 91 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs, 93 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 { 95 {
@@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable
103 lock (m_collectionActivityLock) 99 lock (m_collectionActivityLock)
104 { 100 {
105 // Do we have the correct geometry for this type of object? 101 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape 102 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape.
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object, 105 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it. 106 // rebuild the body around it.
@@ -120,26 +117,24 @@ public class BSShapeCollection : IDisposable
120 117
121 // Track another user of a body 118 // Track another user of a body
122 // We presume the caller has allocated the body. 119 // We presume the caller has allocated the body.
123 // Bodies only have one user so the reference count is either 1 or 0. 120 // Bodies only have one user so the body is just put into the world if not already there.
124 public void ReferenceBody(BulletBody body, bool atTaintTime) 121 public void ReferenceBody(BulletBody body, bool inTaintTime)
125 { 122 {
126 lock (m_collectionActivityLock) 123 lock (m_collectionActivityLock)
127 { 124 {
128 BodyDesc bodyDesc; 125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body);
129 if (Bodies.TryGetValue(body.ID, out bodyDesc)) 126 BSScene.TaintCallback createOperation = delegate()
130 { 127 {
131 bodyDesc.referenceCount++; 128 if (!BulletSimAPI.IsInWorld2(body.ptr))
132 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount); 129 {
133 } 130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
132 }
133 };
134 if (inTaintTime)
135 createOperation();
134 else 136 else
135 { 137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
136 // New entry
137 bodyDesc.ptr = body.ptr;
138 bodyDesc.referenceCount = 1;
139 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
140 }
141 bodyDesc.lastReferenced = System.DateTime.Now;
142 Bodies[body.ID] = bodyDesc;
143 } 138 }
144 } 139 }
145 140
@@ -152,42 +147,25 @@ public class BSShapeCollection : IDisposable
152 147
153 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
154 { 149 {
155 BodyDesc bodyDesc; 150 BSScene.TaintCallback removeOperation = delegate()
156 if (Bodies.TryGetValue(body.ID, out bodyDesc))
157 { 151 {
158 bodyDesc.referenceCount--; 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
159 bodyDesc.lastReferenced = System.DateTime.Now; 153 body.ID, body.ptr.ToString("X"), inTaintTime);
160 Bodies[body.ID] = bodyDesc; 154 // If the caller needs to know the old body is going away, pass the event up.
161 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); 155 if (bodyCallback != null) bodyCallback(body);
162 156
163 // If body is no longer being used, free it -- bodies are never shared. 157 // It may have already been removed from the world in which case the next is a NOOP.
164 if (bodyDesc.referenceCount == 0) 158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
165 { 159
166 Bodies.Remove(body.ID); 160 // Zero any reference to the shape so it is not freed when the body is deleted.
167 BSScene.TaintCallback removeOperation = delegate() 161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
168 { 162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
169 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", 163 };
170 body.ID, body.ptr.ToString("X")); 164 // If already in taint-time, do the operations now. Otherwise queue for later.
171 // If the caller needs to know the old body is going away, pass the event up. 165 if (inTaintTime)
172 if (bodyCallback != null) bodyCallback(body); 166 removeOperation();
173
174 // Zero any reference to the shape so it is not freed when the body is deleted.
175 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
176 // It may have already been removed from the world in which case the next is a NOOP.
177 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
178 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
179 };
180 // If already in taint-time, do the operations now. Otherwise queue for later.
181 if (inTaintTime)
182 removeOperation();
183 else
184 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
185 }
186 }
187 else 167 else
188 { 168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
189 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
190 }
191 } 169 }
192 } 170 }
193 171
@@ -208,7 +186,7 @@ public class BSShapeCollection : IDisposable
208 { 186 {
209 // There is an existing instance of this mesh. 187 // There is an existing instance of this mesh.
210 meshDesc.referenceCount++; 188 meshDesc.referenceCount++;
211 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", 189 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
212 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 190 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
213 } 191 }
214 else 192 else
@@ -217,7 +195,7 @@ public class BSShapeCollection : IDisposable
217 meshDesc.ptr = shape.ptr; 195 meshDesc.ptr = shape.ptr;
218 // We keep a reference to the underlying IMesh data so a hull can be built 196 // We keep a reference to the underlying IMesh data so a hull can be built
219 meshDesc.referenceCount = 1; 197 meshDesc.referenceCount = 1;
220 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", 198 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
221 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 199 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
222 ret = true; 200 ret = true;
223 } 201 }
@@ -230,7 +208,7 @@ public class BSShapeCollection : IDisposable
230 { 208 {
231 // There is an existing instance of this hull. 209 // There is an existing instance of this hull.
232 hullDesc.referenceCount++; 210 hullDesc.referenceCount++;
233 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", 211 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
234 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 212 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
235 } 213 }
236 else 214 else
@@ -238,7 +216,7 @@ public class BSShapeCollection : IDisposable
238 // This is a new reference to a hull 216 // This is a new reference to a hull
239 hullDesc.ptr = shape.ptr; 217 hullDesc.ptr = shape.ptr;
240 hullDesc.referenceCount = 1; 218 hullDesc.referenceCount = 1;
241 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", 219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
242 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
243 ret = true; 221 ret = true;
244 222
@@ -256,37 +234,42 @@ public class BSShapeCollection : IDisposable
256 } 234 }
257 235
258 // Release the usage of a shape. 236 // Release the usage of a shape.
259 // The collisionObject is released since it is a copy of the real collision shape. 237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
260 public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
261 { 238 {
262 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
263 return; 240 return;
264 241
265 BSScene.TaintCallback dereferenceOperation = delegate() 242 BSScene.TaintCallback dereferenceOperation = delegate()
266 { 243 {
267 switch (shape.type) 244 if (shape.ptr != IntPtr.Zero)
268 { 245 {
269 case ShapeData.PhysicsShapeType.SHAPE_HULL: 246 if (shape.isNativeShape)
270 DereferenceHull(shape, shapeCallback); 247 {
271 break;
272 case ShapeData.PhysicsShapeType.SHAPE_MESH:
273 DereferenceMesh(shape, shapeCallback);
274 break;
275 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
276 break;
277 default:
278 // Native shapes are not tracked and are released immediately 248 // Native shapes are not tracked and are released immediately
279 if (shape.ptr != IntPtr.Zero & shape.isNativeShape) 249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
253 }
254 else
255 {
256 switch (shape.type)
280 { 257 {
281 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 258 case ShapeData.PhysicsShapeType.SHAPE_HULL:
282 BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime); 259 DereferenceHull(shape, shapeCallback);
283 if (shapeCallback != null) shapeCallback(shape); 260 break;
284 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 261 case ShapeData.PhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback);
263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
265 break;
266 default:
267 break;
285 } 268 }
286 break; 269 }
287 } 270 }
288 }; 271 };
289 if (atTaintTime) 272 if (inTaintTime)
290 { 273 {
291 lock (m_collectionActivityLock) 274 lock (m_collectionActivityLock)
292 { 275 {
@@ -336,19 +319,31 @@ public class BSShapeCollection : IDisposable
336 319
337 // Create the geometry information in Bullet for later use. 320 // Create the geometry information in Bullet for later use.
338 // The objects needs a hull if it's physical otherwise a mesh is enough. 321 // The objects needs a hull if it's physical otherwise a mesh is enough.
339 // No locking here because this is done when we know physics is not simulating. 322 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
340 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. 323 // shared geometries will be used. If the parameters of the existing shape are the same
324 // as this request, the shape is not rebuilt.
325 // Info in prim.BSShape is updated to the new shape.
341 // Returns 'true' if the geometry was rebuilt. 326 // Returns 'true' if the geometry was rebuilt.
342 // Called at taint-time! 327 // Called at taint-time!
343 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, 328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData,
344 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) 329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
345 { 330 {
346 bool ret = false; 331 bool ret = false;
347 bool haveShape = false; 332 bool haveShape = false;
348 bool nativeShapePossible = true; 333 bool nativeShapePossible = true;
349 334
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
336 {
337 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape);
341 haveShape = true;
342 }
350 // If the prim attributes are simple, this could be a simple Bullet native shape 343 // If the prim attributes are simple, this could be a simple Bullet native shape
351 if (nativeShapePossible 344 if (!haveShape
345 && pbs != null
346 && nativeShapePossible
352 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 347 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
353 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 348 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
354 && pbs.ProfileHollow == 0 349 && pbs.ProfileHollow == 0
@@ -358,7 +353,8 @@ public class BSShapeCollection : IDisposable
358 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 353 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
359 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 354 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
360 { 355 {
361 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 356 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
357 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
362 { 358 {
363 haveShape = true; 359 haveShape = true;
364 if (forceRebuild 360 if (forceRebuild
@@ -372,7 +368,7 @@ public class BSShapeCollection : IDisposable
372 prim.LocalID, forceRebuild, prim.BSShape); 368 prim.LocalID, forceRebuild, prim.BSShape);
373 } 369 }
374 } 370 }
375 else 371 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
376 { 372 {
377 haveShape = true; 373 haveShape = true;
378 if (forceRebuild 374 if (forceRebuild
@@ -390,9 +386,9 @@ public class BSShapeCollection : IDisposable
390 // If a simple shape is not happening, create a mesh and possibly a hull. 386 // If a simple shape is not happening, create a mesh and possibly a hull.
391 // Note that if it's a native shape, the check for physical/non-physical is not 387 // Note that if it's a native shape, the check for physical/non-physical is not
392 // made. Native shapes are best used in either case. 388 // made. Native shapes are best used in either case.
393 if (!haveShape) 389 if (!haveShape && pbs != null)
394 { 390 {
395 if (prim.IsPhysical) 391 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
396 { 392 {
397 // Update prim.BSShape to reference a hull of this shape. 393 // Update prim.BSShape to reference a hull of this shape.
398 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); 394 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
@@ -409,12 +405,12 @@ public class BSShapeCollection : IDisposable
409 return ret; 405 return ret;
410 } 406 }
411 407
412 // Creates a native shape and assignes it to prim.BSShape 408 // Creates a native shape and assignes it to prim.BSShape.
413 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData, 409 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
410 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData,
414 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
415 ShapeDestructionCallback shapeCallback) 412 ShapeDestructionCallback shapeCallback)
416 { 413 {
417 BulletShape newShape;
418 414
419 shapeData.Type = shapeType; 415 shapeData.Type = shapeType;
420 // Bullet native objects are scaled by the Bullet engine so pass the size in 416 // Bullet native objects are scaled by the Bullet engine so pass the size in
@@ -424,29 +420,48 @@ public class BSShapeCollection : IDisposable
424 // release any previous shape 420 // release any previous shape
425 DereferenceShape(prim.BSShape, true, shapeCallback); 421 DereferenceShape(prim.BSShape, true, shapeCallback);
426 422
427 // Native shapes are always built independently. 423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey);
428 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
429 newShape.shapeKey = (ulong)shapeKey;
430 newShape.isNativeShape = true;
431 424
432 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. 425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
433 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape); 426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale);
434 428
435 prim.BSShape = newShape; 429 prim.BSShape = newShape;
436 return true; 430 return true;
437 } 431 }
438 432
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey)
435 {
436 BulletShape newShape;
437
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR)
439 {
440 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale),
442 shapeType);
443 }
444 else
445 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
447 }
448 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true;
450
451 return newShape;
452 }
453
439 // Builds a mesh shape in the physical world and updates prim.BSShape. 454 // Builds a mesh shape in the physical world and updates prim.BSShape.
440 // Dereferences previous shape in BSShape and adds a reference for this new shape. 455 // Dereferences previous shape in BSShape and adds a reference for this new shape.
441 // Returns 'true' of a mesh was actually built. Otherwise . 456 // Returns 'true' of a mesh was actually built. Otherwise .
442 // Called at taint-time! 457 // Called at taint-time!
443 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 458 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
444 ShapeDestructionCallback shapeCallback) 459 ShapeDestructionCallback shapeCallback)
445 { 460 {
446 BulletShape newShape = new BulletShape(IntPtr.Zero); 461 BulletShape newShape = new BulletShape(IntPtr.Zero);
447 462
448 float lod; 463 float lod;
449 ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); 464 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
450 465
451 // if this new shape is the same as last time, don't recreate the mesh 466 // if this new shape is the same as last time, don't recreate the mesh
452 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 467 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH)
@@ -459,6 +474,8 @@ public class BSShapeCollection : IDisposable
459 DereferenceShape(prim.BSShape, true, shapeCallback); 474 DereferenceShape(prim.BSShape, true, shapeCallback);
460 475
461 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 476 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
477 // Take evasive action if the mesh was not constructed.
478 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
462 479
463 ReferenceShape(newShape); 480 ReferenceShape(newShape);
464 481
@@ -469,10 +486,10 @@ public class BSShapeCollection : IDisposable
469 return true; // 'true' means a new shape has been added to this prim 486 return true; // 'true' means a new shape has been added to this prim
470 } 487 }
471 488
472 private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 489 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
473 { 490 {
474 IMesh meshData = null; 491 IMesh meshData = null;
475 IntPtr meshPtr; 492 IntPtr meshPtr = IntPtr.Zero;
476 MeshDesc meshDesc; 493 MeshDesc meshDesc;
477 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 494 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
478 { 495 {
@@ -484,23 +501,26 @@ public class BSShapeCollection : IDisposable
484 // Pass false for physicalness as this creates some sort of bounding box which we don't need 501 // Pass false for physicalness as this creates some sort of bounding box which we don't need
485 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 502 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
486 503
487 int[] indices = meshData.getIndexListAsInt(); 504 if (meshData != null)
488 List<OMV.Vector3> vertices = meshData.getVertexList();
489
490 float[] verticesAsFloats = new float[vertices.Count * 3];
491 int vi = 0;
492 foreach (OMV.Vector3 vv in vertices)
493 { 505 {
494 verticesAsFloats[vi++] = vv.X; 506 int[] indices = meshData.getIndexListAsInt();
495 verticesAsFloats[vi++] = vv.Y; 507 List<OMV.Vector3> vertices = meshData.getVertexList();
496 verticesAsFloats[vi++] = vv.Z; 508
497 } 509 float[] verticesAsFloats = new float[vertices.Count * 3];
510 int vi = 0;
511 foreach (OMV.Vector3 vv in vertices)
512 {
513 verticesAsFloats[vi++] = vv.X;
514 verticesAsFloats[vi++] = vv.Y;
515 verticesAsFloats[vi++] = vv.Z;
516 }
498 517
499 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 518 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
500 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 519 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
501 520
502 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 521 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
503 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 522 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
523 }
504 } 524 }
505 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 525 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
506 newShape.shapeKey = newMeshKey; 526 newShape.shapeKey = newMeshKey;
@@ -510,13 +530,13 @@ public class BSShapeCollection : IDisposable
510 530
511 // See that hull shape exists in the physical world and update prim.BSShape. 531 // See that hull shape exists in the physical world and update prim.BSShape.
512 // We could be creating the hull because scale changed or whatever. 532 // We could be creating the hull because scale changed or whatever.
513 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, 533 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs,
514 ShapeDestructionCallback shapeCallback) 534 ShapeDestructionCallback shapeCallback)
515 { 535 {
516 BulletShape newShape; 536 BulletShape newShape;
517 537
518 float lod; 538 float lod;
519 ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); 539 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
520 540
521 // if the hull hasn't changed, don't rebuild it 541 // if the hull hasn't changed, don't rebuild it
522 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 542 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
@@ -525,10 +545,11 @@ public class BSShapeCollection : IDisposable
525 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", 545 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
526 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 546 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
527 547
528 // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull. 548 // Remove usage of the previous shape.
529 DereferenceShape(prim.BSShape, true, shapeCallback); 549 DereferenceShape(prim.BSShape, true, shapeCallback);
530 550
531 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 551 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
552 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs);
532 553
533 ReferenceShape(newShape); 554 ReferenceShape(newShape);
534 555
@@ -539,10 +560,10 @@ public class BSShapeCollection : IDisposable
539 } 560 }
540 561
541 List<ConvexResult> m_hulls; 562 List<ConvexResult> m_hulls;
542 private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 563 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
543 { 564 {
544 565
545 IntPtr hullPtr; 566 IntPtr hullPtr = IntPtr.Zero;
546 HullDesc hullDesc; 567 HullDesc hullDesc;
547 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 568 if (Hulls.TryGetValue(newHullKey, out hullDesc))
548 { 569 {
@@ -554,86 +575,89 @@ public class BSShapeCollection : IDisposable
554 // Build a new hull in the physical world 575 // Build a new hull in the physical world
555 // Pass false for physicalness as this creates some sort of bounding box which we don't need 576 // Pass false for physicalness as this creates some sort of bounding box which we don't need
556 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 577 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
557 578 if (meshData != null)
558 int[] indices = meshData.getIndexListAsInt();
559 List<OMV.Vector3> vertices = meshData.getVertexList();
560
561 //format conversion from IMesh format to DecompDesc format
562 List<int> convIndices = new List<int>();
563 List<float3> convVertices = new List<float3>();
564 for (int ii = 0; ii < indices.GetLength(0); ii++)
565 { 579 {
566 convIndices.Add(indices[ii]);
567 }
568 foreach (OMV.Vector3 vv in vertices)
569 {
570 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
571 }
572 580
573 // setup and do convex hull conversion 581 int[] indices = meshData.getIndexListAsInt();
574 m_hulls = new List<ConvexResult>(); 582 List<OMV.Vector3> vertices = meshData.getVertexList();
575 DecompDesc dcomp = new DecompDesc();
576 dcomp.mIndices = convIndices;
577 dcomp.mVertices = convVertices;
578 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
579 // create the hull into the _hulls variable
580 convexBuilder.process(dcomp);
581
582 // Convert the vertices and indices for passing to unmanaged.
583 // The hull information is passed as a large floating point array.
584 // The format is:
585 // convHulls[0] = number of hulls
586 // convHulls[1] = number of vertices in first hull
587 // convHulls[2] = hull centroid X coordinate
588 // convHulls[3] = hull centroid Y coordinate
589 // convHulls[4] = hull centroid Z coordinate
590 // convHulls[5] = first hull vertex X
591 // convHulls[6] = first hull vertex Y
592 // convHulls[7] = first hull vertex Z
593 // convHulls[8] = second hull vertex X
594 // ...
595 // convHulls[n] = number of vertices in second hull
596 // convHulls[n+1] = second hull centroid X coordinate
597 // ...
598 //
599 // TODO: is is very inefficient. Someday change the convex hull generator to return
600 // data structures that do not need to be converted in order to pass to Bullet.
601 // And maybe put the values directly into pinned memory rather than marshaling.
602 int hullCount = m_hulls.Count;
603 int totalVertices = 1; // include one for the count of the hulls
604 foreach (ConvexResult cr in m_hulls)
605 {
606 totalVertices += 4; // add four for the vertex count and centroid
607 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
608 }
609 float[] convHulls = new float[totalVertices];
610 583
611 convHulls[0] = (float)hullCount; 584 //format conversion from IMesh format to DecompDesc format
612 int jj = 1; 585 List<int> convIndices = new List<int>();
613 foreach (ConvexResult cr in m_hulls) 586 List<float3> convVertices = new List<float3>();
614 { 587 for (int ii = 0; ii < indices.GetLength(0); ii++)
615 // copy vertices for index access 588 {
616 float3[] verts = new float3[cr.HullVertices.Count]; 589 convIndices.Add(indices[ii]);
617 int kk = 0; 590 }
618 foreach (float3 ff in cr.HullVertices) 591 foreach (OMV.Vector3 vv in vertices)
592 {
593 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
594 }
595
596 // setup and do convex hull conversion
597 m_hulls = new List<ConvexResult>();
598 DecompDesc dcomp = new DecompDesc();
599 dcomp.mIndices = convIndices;
600 dcomp.mVertices = convVertices;
601 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
602 // create the hull into the _hulls variable
603 convexBuilder.process(dcomp);
604
605 // Convert the vertices and indices for passing to unmanaged.
606 // The hull information is passed as a large floating point array.
607 // The format is:
608 // convHulls[0] = number of hulls
609 // convHulls[1] = number of vertices in first hull
610 // convHulls[2] = hull centroid X coordinate
611 // convHulls[3] = hull centroid Y coordinate
612 // convHulls[4] = hull centroid Z coordinate
613 // convHulls[5] = first hull vertex X
614 // convHulls[6] = first hull vertex Y
615 // convHulls[7] = first hull vertex Z
616 // convHulls[8] = second hull vertex X
617 // ...
618 // convHulls[n] = number of vertices in second hull
619 // convHulls[n+1] = second hull centroid X coordinate
620 // ...
621 //
622 // TODO: is is very inefficient. Someday change the convex hull generator to return
623 // data structures that do not need to be converted in order to pass to Bullet.
624 // And maybe put the values directly into pinned memory rather than marshaling.
625 int hullCount = m_hulls.Count;
626 int totalVertices = 1; // include one for the count of the hulls
627 foreach (ConvexResult cr in m_hulls)
619 { 628 {
620 verts[kk++] = ff; 629 totalVertices += 4; // add four for the vertex count and centroid
630 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
621 } 631 }
632 float[] convHulls = new float[totalVertices];
622 633
623 // add to the array one hull's worth of data 634 convHulls[0] = (float)hullCount;
624 convHulls[jj++] = cr.HullIndices.Count; 635 int jj = 1;
625 convHulls[jj++] = 0f; // centroid x,y,z 636 foreach (ConvexResult cr in m_hulls)
626 convHulls[jj++] = 0f;
627 convHulls[jj++] = 0f;
628 foreach (int ind in cr.HullIndices)
629 { 637 {
630 convHulls[jj++] = verts[ind].x; 638 // copy vertices for index access
631 convHulls[jj++] = verts[ind].y; 639 float3[] verts = new float3[cr.HullVertices.Count];
632 convHulls[jj++] = verts[ind].z; 640 int kk = 0;
641 foreach (float3 ff in cr.HullVertices)
642 {
643 verts[kk++] = ff;
644 }
645
646 // add to the array one hull's worth of data
647 convHulls[jj++] = cr.HullIndices.Count;
648 convHulls[jj++] = 0f; // centroid x,y,z
649 convHulls[jj++] = 0f;
650 convHulls[jj++] = 0f;
651 foreach (int ind in cr.HullIndices)
652 {
653 convHulls[jj++] = verts[ind].x;
654 convHulls[jj++] = verts[ind].y;
655 convHulls[jj++] = verts[ind].z;
656 }
633 } 657 }
658 // create the hull data structure in Bullet
659 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
634 } 660 }
635 // create the hull data structure in Bullet
636 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
637 } 661 }
638 662
639 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 663 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
@@ -652,32 +676,77 @@ public class BSShapeCollection : IDisposable
652 676
653 // Create a hash of all the shape parameters to be used as a key 677 // Create a hash of all the shape parameters to be used as a key
654 // for this particular shape. 678 // for this particular shape.
655 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) 679 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
656 { 680 {
657 // level of detail based on size and type of the object 681 // level of detail based on size and type of the object
658 float lod = PhysicsScene.MeshLOD; 682 float lod = PhysicsScene.MeshLOD;
659 if (pbs.SculptEntry) 683 if (pbs.SculptEntry)
660 lod = PhysicsScene.SculptLOD; 684 lod = PhysicsScene.SculptLOD;
661 685
686 // Mega prims usually get more detail because one can interact with shape approximations at this size.
662 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); 687 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
663 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 688 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
664 lod = PhysicsScene.MeshMegaPrimLOD; 689 lod = PhysicsScene.MeshMegaPrimLOD;
665 690
666 retLod = lod; 691 retLod = lod;
667 return (ulong)pbs.GetMeshKey(shapeData.Size, lod); 692 return pbs.GetMeshKey(shapeData.Size, lod);
668 } 693 }
669 // For those who don't want the LOD 694 // For those who don't want the LOD
670 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) 695 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
671 { 696 {
672 float lod; 697 float lod;
673 return ComputeShapeKey(shapeData, pbs, out lod); 698 return ComputeShapeKey(shapeData, pbs, out lod);
674 } 699 }
675 700
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs)
702 {
703 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero)
705 return newShape;
706
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero)
711 {
712 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim;
714 Util.FireAndForget(delegate
715 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
717 if (assetProvider != null)
718 {
719 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
720 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
721 {
722 if (!yprim.BaseShape.SculptEntry)
723 return;
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return;
726
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length];
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object.
731 yprim.ForceBodyShapeRebuild(false);
732
733 });
734 }
735 });
736 }
737
738 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE);
741
742 return fillinShape;
743 }
744
676 // Create a body object in Bullet. 745 // Create a body object in Bullet.
677 // Updates prim.BSBody with the information about the new body if one is created. 746 // Updates prim.BSBody with the information about the new body if one is created.
678 // Returns 'true' if an object was actually created. 747 // Returns 'true' if an object was actually created.
679 // Called at taint-time. 748 // Called at taint-time.
680 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, 749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
681 ShapeData shapeData, BodyDestructionCallback bodyCallback) 750 ShapeData shapeData, BodyDestructionCallback bodyCallback)
682 { 751 {
683 bool ret = false; 752 bool ret = false;
@@ -701,6 +770,7 @@ public class BSShapeCollection : IDisposable
701 770
702 if (mustRebuild || forceRebuild) 771 if (mustRebuild || forceRebuild)
703 { 772 {
773 // Free any old body
704 DereferenceBody(prim.BSBody, true, bodyCallback); 774 DereferenceBody(prim.BSBody, true, bodyCallback);
705 775
706 BulletBody aBody; 776 BulletBody aBody;
@@ -709,13 +779,13 @@ public class BSShapeCollection : IDisposable
709 { 779 {
710 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 780 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
711 shapeData.ID, shapeData.Position, shapeData.Rotation); 781 shapeData.ID, shapeData.Position, shapeData.Rotation);
712 // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 782 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
713 } 783 }
714 else 784 else
715 { 785 {
716 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 786 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
717 shapeData.ID, shapeData.Position, shapeData.Rotation); 787 shapeData.ID, shapeData.Position, shapeData.Rotation);
718 // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 788 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
719 } 789 }
720 aBody = new BulletBody(shapeData.ID, bodyPtr); 790 aBody = new BulletBody(shapeData.ID, bodyPtr);
721 791
@@ -731,7 +801,8 @@ public class BSShapeCollection : IDisposable
731 801
732 private void DetailLog(string msg, params Object[] args) 802 private void DetailLog(string msg, params Object[] args)
733 { 803 {
734 PhysicsScene.PhysicsLogging.Write(msg, args); 804 if (PhysicsScene.PhysicsLogging.Enabled)
805 PhysicsScene.DetailLog(msg, args);
735 } 806 }
736} 807}
737} 808}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 70aa429..4106534 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -114,6 +114,9 @@ public class BSTerrainManager
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity)); 115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); 116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
118 // Ground plane does not move
119 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
117 // Everything collides with the ground plane. 120 // Everything collides with the ground plane.
118 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 121 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
119 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 122 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
@@ -201,10 +204,10 @@ public class BSTerrainManager
201 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 204 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
202 // calling this routine from initialization or taint-time routines) or whether to delay 205 // calling this routine from initialization or taint-time routines) or whether to delay
203 // all the unmanaged activities to taint-time. 206 // all the unmanaged activities to taint-time.
204 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime) 207 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
205 { 208 {
206 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}", 209 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
207 BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime); 210 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
208 211
209 float minZ = float.MaxValue; 212 float minZ = float.MaxValue;
210 float maxZ = float.MinValue; 213 float maxZ = float.MinValue;
@@ -296,16 +299,16 @@ public class BSTerrainManager
296 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, 299 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
297 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); 300 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
298 301
302 // Create the terrain shape from the mapInfo
303 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
304 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
305
299 // The terrain object initial position is at the center of the object 306 // The terrain object initial position is at the center of the object
300 Vector3 centerPos; 307 Vector3 centerPos;
301 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); 308 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
302 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); 309 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
303 centerPos.Z = minZ + ((maxZ - minZ) / 2f); 310 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
304 311
305 // Create the terrain shape from the mapInfo
306 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
307 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
308
309 mapInfo.terrainBody = new BulletBody(mapInfo.ID, 312 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
310 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, 313 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
311 id, centerPos, Quaternion.Identity)); 314 id, centerPos, Quaternion.Identity));
@@ -320,9 +323,6 @@ public class BSTerrainManager
320 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 323 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
321 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 324 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
322 325
323 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
324 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
325
326 // Return the new terrain to the world of physical objects 326 // Return the new terrain to the world of physical objects
327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); 327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
328 328
@@ -335,14 +335,15 @@ public class BSTerrainManager
335 335
336 // Make sure the new shape is processed. 336 // Make sure the new shape is processed.
337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); 337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
339 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
339 340
340 m_terrainModified = true; 341 m_terrainModified = true;
341 }; 342 };
342 343
343 // There is the option to do the changes now (we're already in 'taint time'), or 344 // There is the option to do the changes now (we're already in 'taint time'), or
344 // to do the Bullet operations later. 345 // to do the Bullet operations later.
345 if (atTaintTime) 346 if (inTaintTime)
346 rebuildOperation(); 347 rebuildOperation();
347 else 348 else
348 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); 349 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
@@ -381,7 +382,7 @@ public class BSTerrainManager
381 }; 382 };
382 383
383 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. 384 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
384 if (atTaintTime) 385 if (inTaintTime)
385 createOperation(); 386 createOperation();
386 else 387 else
387 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); 388 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index a43880d..5ffd591 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -101,9 +101,8 @@ public struct BulletShape
101 } 101 }
102 public IntPtr ptr; 102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type; 103 public ShapeData.PhysicsShapeType type;
104 public ulong shapeKey; 104 public System.UInt64 shapeKey;
105 public bool isNativeShape; 105 public bool isNativeShape;
106 // Hulls have an underlying mesh. A pointer to it is hidden here.
107 public override string ToString() 106 public override string ToString()
108 { 107 {
109 StringBuilder buff = new StringBuilder(); 108 StringBuilder buff = new StringBuilder();
@@ -192,8 +191,9 @@ public struct ShapeData
192 SHAPE_SPHERE = 5, 191 SHAPE_SPHERE = 5,
193 SHAPE_MESH = 6, 192 SHAPE_MESH = 6,
194 SHAPE_HULL = 7, 193 SHAPE_HULL = 7,
195 SHAPE_GROUNDPLANE = 8, 194 // following defined by BulletSim
196 SHAPE_TERRAIN = 9, 195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
197 }; 197 };
198 public uint ID; 198 public uint ID;
199 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -223,6 +223,7 @@ public struct ShapeData
223 KEY_SPHERE = 2, 223 KEY_SPHERE = 2,
224 KEY_CONE = 3, 224 KEY_CONE = 3,
225 KEY_CYLINDER = 4, 225 KEY_CYLINDER = 4,
226 KEY_CAPSULE = 5,
226 } 227 }
227} 228}
228[StructLayout(LayoutKind.Sequential)] 229[StructLayout(LayoutKind.Sequential)]
@@ -282,6 +283,7 @@ public struct ConfigurationParameters
282 public float terrainHitFraction; 283 public float terrainHitFraction;
283 public float terrainRestitution; 284 public float terrainRestitution;
284 public float avatarFriction; 285 public float avatarFriction;
286 public float avatarStandingFriction;
285 public float avatarDensity; 287 public float avatarDensity;
286 public float avatarRestitution; 288 public float avatarRestitution;
287 public float avatarCapsuleRadius; 289 public float avatarCapsuleRadius;
@@ -305,6 +307,8 @@ public struct ConfigurationParameters
305 public float linkConstraintCFM; 307 public float linkConstraintCFM;
306 public float linkConstraintSolverIterations; 308 public float linkConstraintSolverIterations;
307 309
310 public float physicsLoggingFrames;
311
308 public const float numericTrue = 1f; 312 public const float numericTrue = 1f;
309 public const float numericFalse = 0f; 313 public const float numericFalse = 0f;
310} 314}
@@ -386,7 +390,7 @@ public enum CollisionFilterGroups : uint
386 VolumeDetectMask = ~BSensorTrigger, 390 VolumeDetectMask = ~BSensorTrigger,
387 TerrainFilter = BTerrainFilter, 391 TerrainFilter = BTerrainFilter,
388 TerrainMask = BAllFilter & ~BStaticFilter, 392 TerrainMask = BAllFilter & ~BStaticFilter,
389 GroundPlaneFilter = BAllFilter, 393 GroundPlaneFilter = BGroundPlaneFilter,
390 GroundPlaneMask = BAllFilter 394 GroundPlaneMask = BAllFilter
391 395
392}; 396};
@@ -426,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
426[return: MarshalAs(UnmanagedType.LPStr)] 430[return: MarshalAs(UnmanagedType.LPStr)]
427public static extern string GetVersion(); 431public static extern string GetVersion();
428 432
433/* Remove the linkage to the old api methods
429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
430public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 435public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
431 int maxCollisions, IntPtr collisionArray, 436 int maxCollisions, IntPtr collisionArray,
@@ -529,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
529// =============================================================================== 534// ===============================================================================
530[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
531public static extern void DumpBulletStatistics(); 536public static extern void DumpBulletStatistics();
532 537*/
533// Log a debug message 538// Log a debug message
534[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
535public static extern void SetDebugLogCallback(DebugLogCallback callback); 540public static extern void SetDebugLogCallback(DebugLogCallback callback);
@@ -560,7 +565,8 @@ public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
561public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 566public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
562 int maxCollisions, IntPtr collisionArray, 567 int maxCollisions, IntPtr collisionArray,
563 int maxUpdates, IntPtr updateArray); 568 int maxUpdates, IntPtr updateArray,
569 DebugLogCallback logRoutine);
564 570
565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 571[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
566public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 572public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
@@ -602,6 +608,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
602public static extern bool IsNativeShape2(IntPtr shape); 608public static extern bool IsNativeShape2(IntPtr shape);
603 609
604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
611public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
612
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern IntPtr CreateCompoundShape2(IntPtr sim); 614public static extern IntPtr CreateCompoundShape2(IntPtr sim);
606 615
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1037,18 +1046,6 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1037public static extern int GetNumConstraintRefs2(IntPtr obj); 1046public static extern int GetNumConstraintRefs2(IntPtr obj);
1038 1047
1039[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1040public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj);
1041
1042[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1043public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj);
1044
1045[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1046public static extern Vector3 GetPushVelocity2(IntPtr obj);
1047
1048[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1049public static extern Vector3 GetTurnVelocity2(IntPtr obj);
1050
1051[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1052public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); 1049public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1053 1050
1054// ===================================================================================== 1051// =====================================================================================
@@ -1108,6 +1105,15 @@ public static extern float GetMargin2(IntPtr shape);
1108public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); 1105public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1109 1106
1110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1108public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1109
1110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1111public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1112
1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1114public static extern void DumpAllInfo2(IntPtr sim);
1115
1116[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1111public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); 1117public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1112 1118
1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1119[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 6a0558a..488900e 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -76,7 +76,7 @@ namespace OpenSim.Region.Physics.Manager
76 get { return new NullPhysicsScene(); } 76 get { return new NullPhysicsScene(); }
77 } 77 }
78 78
79 public RequestAssetDelegate RequestAssetMethod { private get; set; } 79 public RequestAssetDelegate RequestAssetMethod { get; set; }
80 80
81 public virtual void TriggerPhysicsBasedRestart() 81 public virtual void TriggerPhysicsBasedRestart()
82 { 82 {
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index e7b3b2b..2548648 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -67,6 +67,14 @@ namespace OpenSim.Region.Physics.OdePlugin
67 private int m_expectedCollisionContacts = 0; 67 private int m_expectedCollisionContacts = 0;
68 68
69 /// <summary> 69 /// <summary>
70 /// Gets collide bits so that we can still perform land collisions if a mesh fails to load.
71 /// </summary>
72 private int BadMeshAssetCollideBits
73 {
74 get { return m_isphysical ? (int)CollisionCategories.Land : 0; }
75 }
76
77 /// <summary>
70 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes. 78 /// Is this prim subject to physics? Even if not, it's still solid for collision purposes.
71 /// </summary> 79 /// </summary>
72 public override bool IsPhysical 80 public override bool IsPhysical
@@ -100,6 +108,9 @@ namespace OpenSim.Region.Physics.OdePlugin
100 private Vector3 m_taintAngularLock = Vector3.One; 108 private Vector3 m_taintAngularLock = Vector3.One;
101 private IntPtr Amotor = IntPtr.Zero; 109 private IntPtr Amotor = IntPtr.Zero;
102 110
111 private object m_assetsLock = new object();
112 private bool m_assetFailed = false;
113
103 private Vector3 m_PIDTarget; 114 private Vector3 m_PIDTarget;
104 private float m_PIDTau; 115 private float m_PIDTau;
105 private float PID_D = 35f; 116 private float PID_D = 35f;
@@ -282,6 +293,7 @@ namespace OpenSim.Region.Physics.OdePlugin
282 } 293 }
283 294
284 m_taintadd = true; 295 m_taintadd = true;
296 m_assetFailed = false;
285 _parent_scene.AddPhysicsActorTaint(this); 297 _parent_scene.AddPhysicsActorTaint(this);
286 } 298 }
287 299
@@ -337,8 +349,16 @@ namespace OpenSim.Region.Physics.OdePlugin
337 prim_geom = geom; 349 prim_geom = geom;
338//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); 350//Console.WriteLine("SetGeom to " + prim_geom + " for " + Name);
339 351
340 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 352 if (m_assetFailed)
341 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 353 {
354 d.GeomSetCategoryBits(prim_geom, 0);
355 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
356 }
357 else
358 {
359 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
360 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
361 }
342 362
343 _parent_scene.geom_name_map[prim_geom] = Name; 363 _parent_scene.geom_name_map[prim_geom] = Name;
344 _parent_scene.actor_name_map[prim_geom] = this; 364 _parent_scene.actor_name_map[prim_geom] = this;
@@ -401,8 +421,17 @@ namespace OpenSim.Region.Physics.OdePlugin
401 myrot.W = _orientation.W; 421 myrot.W = _orientation.W;
402 d.BodySetQuaternion(Body, ref myrot); 422 d.BodySetQuaternion(Body, ref myrot);
403 d.GeomSetBody(prim_geom, Body); 423 d.GeomSetBody(prim_geom, Body);
404 m_collisionCategories |= CollisionCategories.Body; 424
405 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); 425 if (m_assetFailed)
426 {
427 d.GeomSetCategoryBits(prim_geom, 0);
428 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
429 }
430 else
431 {
432 m_collisionCategories |= CollisionCategories.Body;
433 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
434 }
406 435
407 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 436 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
408 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 437 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
@@ -774,8 +803,16 @@ namespace OpenSim.Region.Physics.OdePlugin
774 m_collisionCategories &= ~CollisionCategories.Body; 803 m_collisionCategories &= ~CollisionCategories.Body;
775 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); 804 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
776 805
777 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 806 if (m_assetFailed)
778 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 807 {
808 d.GeomSetCategoryBits(prim_geom, 0);
809 d.GeomSetCollideBits(prim_geom, 0);
810 }
811 else
812 {
813 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
814 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
815 }
779 816
780 d.BodyDestroy(Body); 817 d.BodyDestroy(Body);
781 lock (childrenPrim) 818 lock (childrenPrim)
@@ -799,8 +836,17 @@ namespace OpenSim.Region.Physics.OdePlugin
799 m_collisionCategories &= ~CollisionCategories.Body; 836 m_collisionCategories &= ~CollisionCategories.Body;
800 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); 837 m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land);
801 838
802 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 839 if (m_assetFailed)
803 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 840 {
841 d.GeomSetCategoryBits(prim_geom, 0);
842 d.GeomSetCollideBits(prim_geom, 0);
843 }
844 else
845 {
846
847 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
848 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
849 }
804 850
805 Body = IntPtr.Zero; 851 Body = IntPtr.Zero;
806 } 852 }
@@ -1090,8 +1136,16 @@ Console.WriteLine("ZProcessTaints for " + Name);
1090 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); 1136 prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1091 1137
1092//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); 1138//Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name);
1093 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); 1139 if (prm.m_assetFailed)
1094 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); 1140 {
1141 d.GeomSetCategoryBits(prm.prim_geom, 0);
1142 d.GeomSetCollideBits(prm.prim_geom, prm.BadMeshAssetCollideBits);
1143 }
1144 else
1145 {
1146 d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories);
1147 d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags);
1148 }
1095 1149
1096 d.Quaternion quat = new d.Quaternion(); 1150 d.Quaternion quat = new d.Quaternion();
1097 quat.W = prm._orientation.W; 1151 quat.W = prm._orientation.W;
@@ -1136,10 +1190,18 @@ Console.WriteLine("ZProcessTaints for " + Name);
1136 m_collisionCategories |= CollisionCategories.Body; 1190 m_collisionCategories |= CollisionCategories.Body;
1137 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); 1191 m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind);
1138 1192
1139//Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); 1193 if (m_assetFailed)
1140 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 1194 {
1141//Console.WriteLine(" Post GeomSetCategoryBits 2"); 1195 d.GeomSetCategoryBits(prim_geom, 0);
1142 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1196 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1197 }
1198 else
1199 {
1200 //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name);
1201 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1202 //Console.WriteLine(" Post GeomSetCategoryBits 2");
1203 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1204 }
1143 1205
1144 d.Quaternion quat2 = new d.Quaternion(); 1206 d.Quaternion quat2 = new d.Quaternion();
1145 quat2.W = _orientation.W; 1207 quat2.W = _orientation.W;
@@ -1300,8 +1362,16 @@ Console.WriteLine("ZProcessTaints for " + Name);
1300 disableBodySoft(); 1362 disableBodySoft();
1301 } 1363 }
1302 1364
1303 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 1365 if (m_assetFailed)
1304 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1366 {
1367 d.GeomSetCategoryBits(prim_geom, 0);
1368 d.GeomSetCollideBits(prim_geom, 0);
1369 }
1370 else
1371 {
1372 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1373 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1374 }
1305 1375
1306 if (IsPhysical) 1376 if (IsPhysical)
1307 { 1377 {
@@ -1322,8 +1392,16 @@ Console.WriteLine("ZProcessTaints for " + Name);
1322 if (m_collidesWater) 1392 if (m_collidesWater)
1323 m_collisionFlags |= CollisionCategories.Water; 1393 m_collisionFlags |= CollisionCategories.Water;
1324 1394
1325 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); 1395 if (m_assetFailed)
1326 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 1396 {
1397 d.GeomSetCategoryBits(prim_geom, 0);
1398 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
1399 }
1400 else
1401 {
1402 d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories);
1403 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
1404 }
1327 1405
1328 if (IsPhysical) 1406 if (IsPhysical)
1329 { 1407 {
@@ -1498,6 +1576,10 @@ Console.WriteLine("CreateGeom:");
1498 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical); 1576 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, _parent_scene.meshSculptLOD, IsPhysical);
1499 // createmesh returns null when it's a shape that isn't a cube. 1577 // createmesh returns null when it's a shape that isn't a cube.
1500 // m_log.Debug(m_localID); 1578 // m_log.Debug(m_localID);
1579 if (mesh == null)
1580 CheckMeshAsset();
1581 else
1582 m_assetFailed = false;
1501 } 1583 }
1502 1584
1503#if SPAM 1585#if SPAM
@@ -1997,7 +2079,14 @@ Console.WriteLine(" JointCreateFixed");
1997 // Don't need to re-enable body.. it's done in SetMesh 2079 // Don't need to re-enable body.. it's done in SetMesh
1998 2080
1999 if (_parent_scene.needsMeshing(_pbs)) 2081 if (_parent_scene.needsMeshing(_pbs))
2082 {
2000 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); 2083 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2084 if (mesh == null)
2085 CheckMeshAsset();
2086 else
2087 m_assetFailed = false;
2088 }
2089
2001 } 2090 }
2002 2091
2003 CreateGeom(m_targetSpace, mesh); 2092 CreateGeom(m_targetSpace, mesh);
@@ -2049,14 +2138,19 @@ Console.WriteLine(" JointCreateFixed");
2049 m_collisionFlags &= ~CollisionCategories.Water; 2138 m_collisionFlags &= ~CollisionCategories.Water;
2050 } 2139 }
2051 2140
2052 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); 2141 if (m_assetFailed)
2053 } 2142 d.GeomSetCollideBits(prim_geom, BadMeshAssetCollideBits);
2143 else
2054 2144
2145 d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags);
2146 }
2055 /// <summary> 2147 /// <summary>
2056 /// Change prim in response to a shape taint. 2148 /// Change prim in response to a shape taint.
2057 /// </summary> 2149 /// </summary>
2058 private void changeshape() 2150 private void changeshape()
2059 { 2151 {
2152 m_taintshape = false;
2153
2060 // Cleanup of old prim geometry and Bodies 2154 // Cleanup of old prim geometry and Bodies
2061 if (IsPhysical && Body != IntPtr.Zero) 2155 if (IsPhysical && Body != IntPtr.Zero)
2062 { 2156 {
@@ -2084,6 +2178,7 @@ Console.WriteLine(" JointCreateFixed");
2084 2178
2085 IMesh mesh = null; 2179 IMesh mesh = null;
2086 2180
2181
2087 if (_parent_scene.needsMeshing(_pbs)) 2182 if (_parent_scene.needsMeshing(_pbs))
2088 { 2183 {
2089 // Don't need to re-enable body.. it's done in CreateMesh 2184 // Don't need to re-enable body.. it's done in CreateMesh
@@ -2094,6 +2189,10 @@ Console.WriteLine(" JointCreateFixed");
2094 2189
2095 // createmesh returns null when it doesn't mesh. 2190 // createmesh returns null when it doesn't mesh.
2096 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical); 2191 mesh = _parent_scene.mesher.CreateMesh(Name, _pbs, _size, meshlod, IsPhysical);
2192 if (mesh == null)
2193 CheckMeshAsset();
2194 else
2195 m_assetFailed = false;
2097 } 2196 }
2098 2197
2099 CreateGeom(m_targetSpace, mesh); 2198 CreateGeom(m_targetSpace, mesh);
@@ -2130,7 +2229,7 @@ Console.WriteLine(" JointCreateFixed");
2130 } 2229 }
2131 2230
2132 resetCollisionAccounting(); 2231 resetCollisionAccounting();
2133 m_taintshape = false; 2232// m_taintshape = false;
2134 } 2233 }
2135 2234
2136 /// <summary> 2235 /// <summary>
@@ -2396,6 +2495,7 @@ Console.WriteLine(" JointCreateFixed");
2396 set 2495 set
2397 { 2496 {
2398 _pbs = value; 2497 _pbs = value;
2498 m_assetFailed = false;
2399 m_taintshape = true; 2499 m_taintshape = true;
2400 } 2500 }
2401 } 2501 }
@@ -3234,5 +3334,37 @@ Console.WriteLine(" JointCreateFixed");
3234 { 3334 {
3235 m_material = pMaterial; 3335 m_material = pMaterial;
3236 } 3336 }
3337
3338
3339 private void CheckMeshAsset()
3340 {
3341 if (_pbs.SculptEntry && !m_assetFailed && _pbs.SculptTexture != UUID.Zero)
3342 {
3343 m_assetFailed = true;
3344 Util.FireAndForget(delegate
3345 {
3346 RequestAssetDelegate assetProvider = _parent_scene.RequestAssetMethod;
3347 if (assetProvider != null)
3348 assetProvider(_pbs.SculptTexture, MeshAssetReveived);
3349 });
3350 }
3351 }
3352
3353 void MeshAssetReveived(AssetBase asset)
3354 {
3355 if (asset.Data != null && asset.Data.Length > 0)
3356 {
3357 if (!_pbs.SculptEntry)
3358 return;
3359 if (_pbs.SculptTexture.ToString() != asset.ID)
3360 return;
3361
3362 _pbs.SculptData = new byte[asset.Data.Length];
3363 asset.Data.CopyTo(_pbs.SculptData, 0);
3364// m_assetFailed = false;
3365 m_taintshape = true;
3366 _parent_scene.AddPhysicsActorTaint(this);
3367 }
3368 }
3237 } 3369 }
3238} \ No newline at end of file 3370} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
index cbe21e2..d53bd90 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs
@@ -4320,4 +4320,4 @@ namespace OpenSim.Region.Physics.OdePlugin
4320 m_stats[ODEPrimUpdateFrameMsStatName] = 0; 4320 m_stats[ODEPrimUpdateFrameMsStatName] = 0;
4321 } 4321 }
4322 } 4322 }
4323} \ No newline at end of file 4323}