aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs814
1 files changed, 305 insertions, 509 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 6a5461a..15b7090 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
41 [Serializable] 41 [Serializable]
42public class BSPrim : BSPhysObject 42public class BSPrim : BSPhysObject
43{ 43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
@@ -51,15 +51,8 @@ public class BSPrim : BSPhysObject
51 private bool _isSelected; 51 private bool _isSelected;
52 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53 53
54 // _position is what the simulator thinks the positions of the prim is.
55 private OMV.Vector3 _position;
56
57 private float _mass; // the mass of this object 54 private float _mass; // the mass of this object
58 private OMV.Vector3 _force;
59 private OMV.Vector3 _velocity;
60 private OMV.Vector3 _torque;
61 private OMV.Vector3 _acceleration; 55 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 56 private int _physicsActorType;
64 private bool _isPhysical; 57 private bool _isPhysical;
65 private bool _flying; 58 private bool _flying;
@@ -72,16 +65,18 @@ public class BSPrim : BSPhysObject
72 65
73 private int CrossingFailures { get; set; } 66 private int CrossingFailures { get; set; }
74 67
75 public BSDynamics VehicleController { get; private set; } 68 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
76 69 public const string VehicleActorName = "BasicVehicle";
77 private BSVMotor _targetMotor;
78 private OMV.Vector3 _PIDTarget;
79 private float _PIDTau;
80 70
81 private BSFMotor _hoverMotor; 71 // Parameters for the hover actor
82 private float _PIDHoverHeight; 72 public const string HoverActorName = "BSPrim.HoverActor";
83 private PIDHoverType _PIDHoverType; 73 // Parameters for the axis lock actor
84 private float _PIDHoverTau; 74 public const String LockedAxisActorName = "BSPrim.LockedAxis";
75 // Parameters for the move to target actor
76 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
77 // Parameters for the setForce and setTorque actors
78 public const string SetForceActorName = "BSPrim.SetForceActor";
79 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
85 80
86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 81 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 82 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -89,31 +84,34 @@ public class BSPrim : BSPhysObject
89 { 84 {
90 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 85 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
91 _physicsActorType = (int)ActorTypes.Prim; 86 _physicsActorType = (int)ActorTypes.Prim;
92 _position = pos; 87 RawPosition = pos;
93 _size = size; 88 _size = size;
94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes). 89 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
95 _orientation = rotation; 90 RawOrientation = rotation;
96 _buoyancy = 0f; 91 _buoyancy = 0f;
97 _velocity = OMV.Vector3.Zero; 92 RawVelocity = OMV.Vector3.Zero;
98 _rotationalVelocity = OMV.Vector3.Zero; 93 _rotationalVelocity = OMV.Vector3.Zero;
99 BaseShape = pbs; 94 BaseShape = pbs;
100 _isPhysical = pisPhysical; 95 _isPhysical = pisPhysical;
101 _isVolumeDetect = false; 96 _isVolumeDetect = false;
102 97
103 VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness 98 // Add a dynamic vehicle to our set of actors that can move this prim.
99 // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName));
104 100
105 _mass = CalculateMass(); 101 _mass = CalculateMass();
106 102
107 DetailLog("{0},BSPrim.constructor,call", LocalID); 103 // DetailLog("{0},BSPrim.constructor,call", LocalID);
108 // do the actual object creation at taint time 104 // do the actual object creation at taint time
109 PhysicsScene.TaintedObject("BSPrim.create", delegate() 105 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
110 { 106 {
111 // Make sure the object is being created with some sanity. 107 // Make sure the object is being created with some sanity.
112 ExtremeSanityCheck(true /* inTaintTime */); 108 ExtremeSanityCheck(true /* inTaintTime */);
113 109
114 CreateGeomAndObject(true); 110 CreateGeomAndObject(true);
115 111
116 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); 112 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
113
114 IsInitialized = true;
117 }); 115 });
118 } 116 }
119 117
@@ -121,19 +119,21 @@ public class BSPrim : BSPhysObject
121 public override void Destroy() 119 public override void Destroy()
122 { 120 {
123 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 121 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
122 IsInitialized = false;
123
124 base.Destroy(); 124 base.Destroy();
125 125
126 // Undo any vehicle properties 126 // Undo any vehicle properties
127 this.VehicleType = (int)Vehicle.TYPE_NONE; 127 this.VehicleType = (int)Vehicle.TYPE_NONE;
128 128
129 PhysicsScene.TaintedObject("BSPrim.destroy", delegate() 129 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
130 { 130 {
131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
132 // If there are physical body and shape, release my use of same. 132 // If there are physical body and shape, release my use of same.
133 PhysicsScene.Shapes.DereferenceBody(PhysBody, null); 133 PhysScene.Shapes.DereferenceBody(PhysBody, null);
134 PhysBody.Clear(); 134 PhysBody.Clear();
135 PhysicsScene.Shapes.DereferenceShape(PhysShape, null); 135 PhysShape.Dereference(PhysScene);
136 PhysShape.Clear(); 136 PhysShape = new BSShapeNull();
137 }); 137 });
138 } 138 }
139 139
@@ -159,25 +159,13 @@ public class BSPrim : BSPhysObject
159 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
160 } 160 }
161 } 161 }
162 // 'unknown' says to choose the best type
163 public override BSPhysicsShapeType PreferredPhysicalShape
164 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
165
166 public override bool ForceBodyShapeRebuild(bool inTaintTime) 162 public override bool ForceBodyShapeRebuild(bool inTaintTime)
167 { 163 {
168 if (inTaintTime) 164 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
169 { 165 {
170 _mass = CalculateMass(); // changing the shape changes the mass 166 _mass = CalculateMass(); // changing the shape changes the mass
171 CreateGeomAndObject(true); 167 CreateGeomAndObject(true);
172 } 168 });
173 else
174 {
175 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
176 {
177 _mass = CalculateMass(); // changing the shape changes the mass
178 CreateGeomAndObject(true);
179 });
180 }
181 return true; 169 return true;
182 } 170 }
183 public override bool Grabbed { 171 public override bool Grabbed {
@@ -190,7 +178,7 @@ public class BSPrim : BSPhysObject
190 if (value != _isSelected) 178 if (value != _isSelected)
191 { 179 {
192 _isSelected = value; 180 _isSelected = value;
193 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 181 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
194 { 182 {
195 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 183 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
196 SetObjectDynamic(false); 184 SetObjectDynamic(false);
@@ -231,165 +219,93 @@ public class BSPrim : BSPhysObject
231 // Called at taint time! 219 // Called at taint time!
232 public override void ZeroMotion(bool inTaintTime) 220 public override void ZeroMotion(bool inTaintTime)
233 { 221 {
234 _velocity = OMV.Vector3.Zero; 222 RawVelocity = OMV.Vector3.Zero;
235 _acceleration = OMV.Vector3.Zero; 223 _acceleration = OMV.Vector3.Zero;
236 _rotationalVelocity = OMV.Vector3.Zero; 224 _rotationalVelocity = OMV.Vector3.Zero;
237 225
238 // Zero some other properties in the physics engine 226 // Zero some other properties in the physics engine
239 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 227 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
240 { 228 {
241 if (PhysBody.HasPhysicalBody) 229 if (PhysBody.HasPhysicalBody)
242 PhysicsScene.PE.ClearAllForces(PhysBody); 230 PhysScene.PE.ClearAllForces(PhysBody);
243 }); 231 });
244 } 232 }
245 public override void ZeroAngularMotion(bool inTaintTime) 233 public override void ZeroAngularMotion(bool inTaintTime)
246 { 234 {
247 _rotationalVelocity = OMV.Vector3.Zero; 235 _rotationalVelocity = OMV.Vector3.Zero;
248 // Zero some other properties in the physics engine 236 // Zero some other properties in the physics engine
249 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 237 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
250 { 238 {
251 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 239 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
252 if (PhysBody.HasPhysicalBody) 240 if (PhysBody.HasPhysicalBody)
253 { 241 {
254 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 242 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
255 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 243 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
256 } 244 }
257 }); 245 });
258 } 246 }
259 247
260 bool TryExperimentalLockAxisCode = false;
261 BSConstraint LockAxisConstraint = null;
262 public override void LockAngularMotion(OMV.Vector3 axis) 248 public override void LockAngularMotion(OMV.Vector3 axis)
263 { 249 {
264 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 250 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
265 251
266 // "1" means free, "0" means locked 252 // "1" means free, "0" means locked
267 OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); 253 OMV.Vector3 locking = LockedAxisFree;
268 if (axis.X != 1) locking.X = 0f; 254 if (axis.X != 1) locking.X = 0f;
269 if (axis.Y != 1) locking.Y = 0f; 255 if (axis.Y != 1) locking.Y = 0f;
270 if (axis.Z != 1) locking.Z = 0f; 256 if (axis.Z != 1) locking.Z = 0f;
271 LockedAxis = locking; 257 LockedAngularAxis = locking;
272 258
273 if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) 259 EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate()
274 { 260 {
275 // Lock that axis by creating a 6DOF constraint that has one end in the world and 261 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
276 // the other in the object. 262 });
277 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
278 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
279
280 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
281 {
282 CleanUpLockAxisPhysicals(true /* inTaintTime */);
283
284 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody,
285 OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation),
286 true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
287 LockAxisConstraint = axisConstrainer;
288 PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
289
290 // The constraint is tied to the world and oriented to the prim.
291
292 // Free to move linearly
293 OMV.Vector3 linearLow = OMV.Vector3.Zero;
294 OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
295 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
296
297 // Angular with some axis locked
298 float f2PI = (float)Math.PI * 2f;
299 OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
300 OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
301 if (LockedAxis.X != 1f)
302 {
303 angularLow.X = 0f;
304 angularHigh.X = 0f;
305 }
306 if (LockedAxis.Y != 1f)
307 {
308 angularLow.Y = 0f;
309 angularHigh.Y = 0f;
310 }
311 if (LockedAxis.Z != 1f)
312 {
313 angularLow.Z = 0f;
314 angularHigh.Z = 0f;
315 }
316 axisConstrainer.SetAngularLimits(angularLow, angularHigh);
317
318 DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
319 LocalID, linearLow, linearHigh, angularLow, angularHigh);
320
321 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
322 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
323 263
324 axisConstrainer.RecomputeConstraintVariables(RawMass); 264 // Update parameters so the new actor's Refresh() action is called at the right time.
325 }); 265 PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate()
326 }
327 else
328 { 266 {
329 // Everything seems unlocked 267 UpdatePhysicalParameters();
330 CleanUpLockAxisPhysicals(false /* inTaintTime */); 268 });
331 }
332 269
333 return; 270 return;
334 } 271 }
335 // Get rid of any constraint built for LockAxis
336 // Most often the constraint is removed when the constraint collection is cleaned for this prim.
337 private void CleanUpLockAxisPhysicals(bool inTaintTime)
338 {
339 if (LockAxisConstraint != null)
340 {
341 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate()
342 {
343 if (LockAxisConstraint != null)
344 {
345 PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
346 LockAxisConstraint = null;
347 DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID);
348 }
349 });
350 }
351 }
352 272
353 public override OMV.Vector3 RawPosition
354 {
355 get { return _position; }
356 set { _position = value; }
357 }
358 public override OMV.Vector3 Position { 273 public override OMV.Vector3 Position {
359 get { 274 get {
360 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 275 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
361 // _position = ForcePosition; 276 // RawPosition = ForcePosition;
362 return _position; 277 return RawPosition;
363 } 278 }
364 set { 279 set {
365 // If the position must be forced into the physics engine, use ForcePosition. 280 // If the position must be forced into the physics engine, use ForcePosition.
366 // All positions are given in world positions. 281 // All positions are given in world positions.
367 if (_position == value) 282 if (RawPosition == value)
368 { 283 {
369 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); 284 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
370 return; 285 return;
371 } 286 }
372 _position = value; 287 RawPosition = value;
373 PositionSanityCheck(false); 288 PositionSanityCheck(false);
374 289
375 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 290 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
376 { 291 {
377 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 292 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
378 ForcePosition = _position; 293 ForcePosition = RawPosition;
379 }); 294 });
380 } 295 }
381 } 296 }
382 297
298 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
383 public override OMV.Vector3 ForcePosition { 299 public override OMV.Vector3 ForcePosition {
384 get { 300 get {
385 _position = PhysicsScene.PE.GetPosition(PhysBody); 301 RawPosition = PhysScene.PE.GetPosition(PhysBody);
386 return _position; 302 return RawPosition;
387 } 303 }
388 set { 304 set {
389 _position = value; 305 RawPosition = value;
390 if (PhysBody.HasPhysicalBody) 306 if (PhysBody.HasPhysicalBody)
391 { 307 {
392 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 308 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
393 ActivateIfPhysical(false); 309 ActivateIfPhysical(false);
394 } 310 }
395 } 311 }
@@ -406,7 +322,7 @@ public class BSPrim : BSPhysObject
406 if (!IsPhysicallyActive) 322 if (!IsPhysicallyActive)
407 return ret; 323 return ret;
408 324
409 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 325 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
410 { 326 {
411 // The physical object is out of the known/simulated area. 327 // The physical object is out of the known/simulated area.
412 // Upper levels of code will handle the transition to other areas so, for 328 // Upper levels of code will handle the transition to other areas so, for
@@ -414,7 +330,7 @@ public class BSPrim : BSPhysObject
414 return ret; 330 return ret;
415 } 331 }
416 332
417 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 333 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
418 OMV.Vector3 upForce = OMV.Vector3.Zero; 334 OMV.Vector3 upForce = OMV.Vector3.Zero;
419 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); 335 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
420 if ((RawPosition.Z + approxSize / 2f) < terrainHeight) 336 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
@@ -423,10 +339,10 @@ public class BSPrim : BSPhysObject
423 float targetHeight = terrainHeight + (Size.Z / 2f); 339 float targetHeight = terrainHeight + (Size.Z / 2f);
424 // If the object is below ground it just has to be moved up because pushing will 340 // If the object is below ground it just has to be moved up because pushing will
425 // not get it through the terrain 341 // not get it through the terrain
426 _position.Z = targetHeight; 342 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
427 if (inTaintTime) 343 if (inTaintTime)
428 { 344 {
429 ForcePosition = _position; 345 ForcePosition = RawPosition;
430 } 346 }
431 // If we are throwing the object around, zero its other forces 347 // If we are throwing the object around, zero its other forces
432 ZeroMotion(inTaintTime); 348 ZeroMotion(inTaintTime);
@@ -435,7 +351,7 @@ public class BSPrim : BSPhysObject
435 351
436 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 352 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
437 { 353 {
438 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 354 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
439 // TODO: a floating motor so object will bob in the water 355 // TODO: a floating motor so object will bob in the water
440 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) 356 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
441 { 357 {
@@ -443,8 +359,8 @@ public class BSPrim : BSPhysObject
443 upForce.Z = (waterHeight - RawPosition.Z) * 1f; 359 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
444 360
445 // Apply upforce and overcome gravity. 361 // Apply upforce and overcome gravity.
446 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; 362 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
447 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); 363 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
448 AddForce(correctionForce, false, inTaintTime); 364 AddForce(correctionForce, false, inTaintTime);
449 ret = true; 365 ret = true;
450 } 366 }
@@ -463,17 +379,17 @@ public class BSPrim : BSPhysObject
463 uint wayOutThere = Constants.RegionSize * Constants.RegionSize; 379 uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
464 // There have been instances of objects getting thrown way out of bounds and crashing 380 // There have been instances of objects getting thrown way out of bounds and crashing
465 // the border crossing code. 381 // the border crossing code.
466 if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere 382 if ( RawPosition.X < -Constants.RegionSize || RawPosition.X > wayOutThere
467 || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere 383 || RawPosition.Y < -Constants.RegionSize || RawPosition.Y > wayOutThere
468 || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) 384 || RawPosition.Z < -Constants.RegionSize || RawPosition.Z > wayOutThere)
469 { 385 {
470 _position = new OMV.Vector3(10, 10, 50); 386 RawPosition = new OMV.Vector3(10, 10, 50);
471 ZeroMotion(inTaintTime); 387 ZeroMotion(inTaintTime);
472 ret = true; 388 ret = true;
473 } 389 }
474 if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) 390 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
475 { 391 {
476 _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); 392 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
477 ret = true; 393 ret = true;
478 } 394 }
479 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) 395 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
@@ -498,7 +414,7 @@ public class BSPrim : BSPhysObject
498 get { return _mass; } 414 get { return _mass; }
499 } 415 }
500 // used when we only want this prim's mass and not the linkset thing 416 // used when we only want this prim's mass and not the linkset thing
501 public override float RawMass { 417 public override float RawMass {
502 get { return _mass; } 418 get { return _mass; }
503 } 419 }
504 // Set the physical mass to the passed mass. 420 // Set the physical mass to the passed mass.
@@ -509,10 +425,10 @@ public class BSPrim : BSPhysObject
509 { 425 {
510 if (IsStatic) 426 if (IsStatic)
511 { 427 {
512 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); 428 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
513 Inertia = OMV.Vector3.Zero; 429 Inertia = OMV.Vector3.Zero;
514 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); 430 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
515 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 431 PhysScene.PE.UpdateInertiaTensor(PhysBody);
516 } 432 }
517 else 433 else
518 { 434 {
@@ -521,16 +437,19 @@ public class BSPrim : BSPhysObject
521 // Changing interesting properties doesn't change proxy and collision cache 437 // Changing interesting properties doesn't change proxy and collision cache
522 // information. The Bullet solution is to re-add the object to the world 438 // information. The Bullet solution is to re-add the object to the world
523 // after parameters are changed. 439 // after parameters are changed.
524 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 440 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
525 } 441 }
526 442
527 // The computation of mass props requires gravity to be set on the object. 443 // The computation of mass props requires gravity to be set on the object.
528 Gravity = ComputeGravity(Buoyancy); 444 Gravity = ComputeGravity(Buoyancy);
529 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 445 PhysScene.PE.SetGravity(PhysBody, Gravity);
530 446
531 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 447 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
532 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 448 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
533 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 449
450 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
451 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
452 PhysScene.PE.UpdateInertiaTensor(PhysBody);
534 453
535 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", 454 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
536 LocalID, physMass, Inertia, Gravity, inWorld); 455 LocalID, physMass, Inertia, Gravity, inWorld);
@@ -546,7 +465,7 @@ public class BSPrim : BSPhysObject
546 // Return what gravity should be set to this very moment 465 // Return what gravity should be set to this very moment
547 public OMV.Vector3 ComputeGravity(float buoyancy) 466 public OMV.Vector3 ComputeGravity(float buoyancy)
548 { 467 {
549 OMV.Vector3 ret = PhysicsScene.DefaultGravity; 468 OMV.Vector3 ret = PhysScene.DefaultGravity;
550 469
551 if (!IsStatic) 470 if (!IsStatic)
552 { 471 {
@@ -570,95 +489,121 @@ public class BSPrim : BSPhysObject
570 } 489 }
571 490
572 public override OMV.Vector3 Force { 491 public override OMV.Vector3 Force {
573 get { return _force; } 492 get { return RawForce; }
574 set { 493 set {
575 _force = value; 494 RawForce = value;
576 if (_force != OMV.Vector3.Zero) 495 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
577 { 496 {
578 // If the force is non-zero, it must be reapplied each tick because 497 return new BSActorSetForce(PhysScene, this, SetForceActorName);
579 // Bullet clears the forces applied last frame. 498 });
580 RegisterPreStepAction("BSPrim.setForce", LocalID, 499 }
581 delegate(float timeStep) 500 }
582 {
583 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
584 {
585 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
586 return;
587 }
588 501
589 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); 502 // Find and return a handle to the current vehicle actor.
590 if (PhysBody.HasPhysicalBody) 503 // Return 'null' if there is no vehicle actor.
591 { 504 public BSDynamics GetVehicleActor(bool createIfNone)
592 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); 505 {
593 ActivateIfPhysical(false); 506 BSDynamics ret = null;
594 } 507 BSActor actor;
595 } 508 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
596 ); 509 {
597 } 510 ret = actor as BSDynamics;
598 else 511 }
512 else
513 {
514 if (createIfNone)
599 { 515 {
600 UnRegisterPreStepAction("BSPrim.setForce", LocalID); 516 ret = new BSDynamics(PhysScene, this, VehicleActorName);
517 PhysicalActors.Add(ret.ActorName, ret);
601 } 518 }
602 } 519 }
520 return ret;
603 } 521 }
604 522
605 public override int VehicleType { 523 public override int VehicleType {
606 get { 524 get {
607 return (int)VehicleController.Type; // if we are a vehicle, return that type 525 int ret = (int)Vehicle.TYPE_NONE;
526 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
527 if (vehicleActor != null)
528 ret = (int)vehicleActor.Type;
529 return ret;
608 } 530 }
609 set { 531 set {
610 Vehicle type = (Vehicle)value; 532 Vehicle type = (Vehicle)value;
611 533
612 PhysicsScene.TaintedObject("setVehicleType", delegate() 534 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
613 { 535 {
614 // Done at taint time so we're sure the physics engine is not using the variables 536 // Some vehicle scripts change vehicle type on the fly as an easy way to
615 // Vehicle code changes the parameters for this vehicle type. 537 // change all the parameters. Like a plane changing to CAR when on the
616 VehicleController.ProcessTypeChange(type); 538 // ground. In this case, don't want to zero motion.
617 ActivateIfPhysical(false); 539 // ZeroMotion(true /* inTaintTime */);
618 540 if (type == Vehicle.TYPE_NONE)
619 // If an active vehicle, register the vehicle code to be called before each step
620 if (VehicleController.Type == Vehicle.TYPE_NONE)
621 { 541 {
622 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); 542 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
623 UnRegisterPostStepAction("BSPrim.Vehicle", LocalID); 543 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
544 if (vehicleActor != null)
545 {
546 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
547 }
624 } 548 }
625 else 549 else
626 { 550 {
627 RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step); 551 // Vehicle type is not 'none' so create an actor and set it running.
628 RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep); 552 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
553 if (vehicleActor != null)
554 {
555 vehicleActor.ProcessTypeChange(type);
556 ActivateIfPhysical(false);
557 }
629 } 558 }
630 }); 559 });
631 } 560 }
632 } 561 }
633 public override void VehicleFloatParam(int param, float value) 562 public override void VehicleFloatParam(int param, float value)
634 { 563 {
635 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 564 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
636 { 565 {
637 VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); 566 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
638 ActivateIfPhysical(false); 567 if (vehicleActor != null)
568 {
569 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
570 ActivateIfPhysical(false);
571 }
639 }); 572 });
640 } 573 }
641 public override void VehicleVectorParam(int param, OMV.Vector3 value) 574 public override void VehicleVectorParam(int param, OMV.Vector3 value)
642 { 575 {
643 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 576 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
644 { 577 {
645 VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); 578 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
646 ActivateIfPhysical(false); 579 if (vehicleActor != null)
580 {
581 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
582 ActivateIfPhysical(false);
583 }
647 }); 584 });
648 } 585 }
649 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 586 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
650 { 587 {
651 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 588 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
652 { 589 {
653 VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); 590 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
654 ActivateIfPhysical(false); 591 if (vehicleActor != null)
592 {
593 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
594 ActivateIfPhysical(false);
595 }
655 }); 596 });
656 } 597 }
657 public override void VehicleFlags(int param, bool remove) 598 public override void VehicleFlags(int param, bool remove)
658 { 599 {
659 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 600 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
660 { 601 {
661 VehicleController.ProcessVehicleFlags(param, remove); 602 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
603 if (vehicleActor != null)
604 {
605 vehicleActor.ProcessVehicleFlags(param, remove);
606 }
662 }); 607 });
663 } 608 }
664 609
@@ -668,7 +613,7 @@ public class BSPrim : BSPhysObject
668 if (_isVolumeDetect != newValue) 613 if (_isVolumeDetect != newValue)
669 { 614 {
670 _isVolumeDetect = newValue; 615 _isVolumeDetect = newValue;
671 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 616 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
672 { 617 {
673 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); 618 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
674 SetObjectDynamic(true); 619 SetObjectDynamic(true);
@@ -676,10 +621,14 @@ public class BSPrim : BSPhysObject
676 } 621 }
677 return; 622 return;
678 } 623 }
624 public override bool IsVolumeDetect
625 {
626 get { return _isVolumeDetect; }
627 }
679 public override void SetMaterial(int material) 628 public override void SetMaterial(int material)
680 { 629 {
681 base.SetMaterial(material); 630 base.SetMaterial(material);
682 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() 631 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
683 { 632 {
684 UpdatePhysicalParameters(); 633 UpdatePhysicalParameters();
685 }); 634 });
@@ -692,7 +641,7 @@ public class BSPrim : BSPhysObject
692 if (base.Friction != value) 641 if (base.Friction != value)
693 { 642 {
694 base.Friction = value; 643 base.Friction = value;
695 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() 644 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
696 { 645 {
697 UpdatePhysicalParameters(); 646 UpdatePhysicalParameters();
698 }); 647 });
@@ -707,7 +656,7 @@ public class BSPrim : BSPhysObject
707 if (base.Restitution != value) 656 if (base.Restitution != value)
708 { 657 {
709 base.Restitution = value; 658 base.Restitution = value;
710 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() 659 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
711 { 660 {
712 UpdatePhysicalParameters(); 661 UpdatePhysicalParameters();
713 }); 662 });
@@ -724,7 +673,7 @@ public class BSPrim : BSPhysObject
724 if (base.Density != value) 673 if (base.Density != value)
725 { 674 {
726 base.Density = value; 675 base.Density = value;
727 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() 676 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
728 { 677 {
729 UpdatePhysicalParameters(); 678 UpdatePhysicalParameters();
730 }); 679 });
@@ -739,93 +688,66 @@ public class BSPrim : BSPhysObject
739 if (base.GravModifier != value) 688 if (base.GravModifier != value)
740 { 689 {
741 base.GravModifier = value; 690 base.GravModifier = value;
742 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() 691 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
743 { 692 {
744 UpdatePhysicalParameters(); 693 UpdatePhysicalParameters();
745 }); 694 });
746 } 695 }
747 } 696 }
748 } 697 }
749 public override OMV.Vector3 RawVelocity
750 {
751 get { return _velocity; }
752 set { _velocity = value; }
753 }
754 public override OMV.Vector3 Velocity { 698 public override OMV.Vector3 Velocity {
755 get { return _velocity; } 699 get { return RawVelocity; }
756 set { 700 set {
757 _velocity = value; 701 RawVelocity = value;
758 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 702 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
759 { 703 {
760 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 704 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
761 ForceVelocity = _velocity; 705 ForceVelocity = RawVelocity;
762 }); 706 });
763 } 707 }
764 } 708 }
765 public override OMV.Vector3 ForceVelocity { 709 public override OMV.Vector3 ForceVelocity {
766 get { return _velocity; } 710 get { return RawVelocity; }
767 set { 711 set {
768 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); 712 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
769 713
770 _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 714 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
771 if (PhysBody.HasPhysicalBody) 715 if (PhysBody.HasPhysicalBody)
772 { 716 {
773 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); 717 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
774 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 718 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
775 ActivateIfPhysical(false); 719 ActivateIfPhysical(false);
776 } 720 }
777 } 721 }
778 } 722 }
779 public override OMV.Vector3 Torque { 723 public override OMV.Vector3 Torque {
780 get { return _torque; } 724 get { return RawTorque; }
781 set { 725 set {
782 _torque = value; 726 RawTorque = value;
783 if (_torque != OMV.Vector3.Zero) 727 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
784 { 728 {
785 // If the torque is non-zero, it must be reapplied each tick because 729 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
786 // Bullet clears the forces applied last frame. 730 });
787 RegisterPreStepAction("BSPrim.setTorque", LocalID, 731 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
788 delegate(float timeStep)
789 {
790 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
791 {
792 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
793 return;
794 }
795
796 if (PhysBody.HasPhysicalBody)
797 AddAngularForce(_torque, false, true);
798 }
799 );
800 }
801 else
802 {
803 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
804 }
805 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
806 } 732 }
807 } 733 }
808 public override OMV.Vector3 Acceleration { 734 public override OMV.Vector3 Acceleration {
809 get { return _acceleration; } 735 get { return _acceleration; }
810 set { _acceleration = value; } 736 set { _acceleration = value; }
811 } 737 }
812 public override OMV.Quaternion RawOrientation 738
813 {
814 get { return _orientation; }
815 set { _orientation = value; }
816 }
817 public override OMV.Quaternion Orientation { 739 public override OMV.Quaternion Orientation {
818 get { 740 get {
819 return _orientation; 741 return RawOrientation;
820 } 742 }
821 set { 743 set {
822 if (_orientation == value) 744 if (RawOrientation == value)
823 return; 745 return;
824 _orientation = value; 746 RawOrientation = value;
825 747
826 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 748 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
827 { 749 {
828 ForceOrientation = _orientation; 750 ForceOrientation = RawOrientation;
829 }); 751 });
830 } 752 }
831 } 753 }
@@ -834,14 +756,14 @@ public class BSPrim : BSPhysObject
834 { 756 {
835 get 757 get
836 { 758 {
837 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 759 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
838 return _orientation; 760 return RawOrientation;
839 } 761 }
840 set 762 set
841 { 763 {
842 _orientation = value; 764 RawOrientation = value;
843 if (PhysBody.HasPhysicalBody) 765 if (PhysBody.HasPhysicalBody)
844 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 766 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
845 } 767 }
846 } 768 }
847 public override int PhysicsActorType { 769 public override int PhysicsActorType {
@@ -854,7 +776,7 @@ public class BSPrim : BSPhysObject
854 if (_isPhysical != value) 776 if (_isPhysical != value)
855 { 777 {
856 _isPhysical = value; 778 _isPhysical = value;
857 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 779 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
858 { 780 {
859 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 781 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
860 SetObjectDynamic(true); 782 SetObjectDynamic(true);
@@ -898,24 +820,25 @@ public class BSPrim : BSPhysObject
898 // isSolid: other objects bounce off of this object 820 // isSolid: other objects bounce off of this object
899 // isVolumeDetect: other objects pass through but can generate collisions 821 // isVolumeDetect: other objects pass through but can generate collisions
900 // collisionEvents: whether this object returns collision events 822 // collisionEvents: whether this object returns collision events
823 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
901 public virtual void UpdatePhysicalParameters() 824 public virtual void UpdatePhysicalParameters()
902 { 825 {
903 if (!PhysBody.HasPhysicalBody) 826 if (!PhysBody.HasPhysicalBody)
904 { 827 {
905 // This would only happen if updates are called for during initialization when the body is not set up yet. 828 // This would only happen if updates are called for during initialization when the body is not set up yet.
906 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); 829 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
907 return; 830 return;
908 } 831 }
909 832
910 // Mangling all the physical properties requires the object not be in the physical world. 833 // Mangling all the physical properties requires the object not be in the physical world.
911 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 834 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
912 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 835 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
913 836
914 // Set up the object physicalness (does gravity and collisions move this object) 837 // Set up the object physicalness (does gravity and collisions move this object)
915 MakeDynamic(IsStatic); 838 MakeDynamic(IsStatic);
916 839
917 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 840 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
918 VehicleController.Refresh(); 841 PhysicalActors.Refresh();
919 842
920 // Arrange for collision events if the simulator wants them 843 // Arrange for collision events if the simulator wants them
921 EnableCollisions(SubscribedEvents()); 844 EnableCollisions(SubscribedEvents());
@@ -926,10 +849,11 @@ public class BSPrim : BSPhysObject
926 AddObjectToPhysicalWorld(); 849 AddObjectToPhysicalWorld();
927 850
928 // Rebuild its shape 851 // Rebuild its shape
929 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 852 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
930 853
931 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 854 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
932 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 855 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
856 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
933 } 857 }
934 858
935 // "Making dynamic" means changing to and from static. 859 // "Making dynamic" means changing to and from static.
@@ -942,28 +866,28 @@ public class BSPrim : BSPhysObject
942 if (makeStatic) 866 if (makeStatic)
943 { 867 {
944 // Become a Bullet 'static' object type 868 // Become a Bullet 'static' object type
945 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 869 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
946 // Stop all movement 870 // Stop all movement
947 ZeroMotion(true); 871 ZeroMotion(true);
948 872
949 // Set various physical properties so other object interact properly 873 // Set various physical properties so other object interact properly
950 PhysicsScene.PE.SetFriction(PhysBody, Friction); 874 PhysScene.PE.SetFriction(PhysBody, Friction);
951 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 875 PhysScene.PE.SetRestitution(PhysBody, Restitution);
952 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 876 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
953 877
954 // Mass is zero which disables a bunch of physics stuff in Bullet 878 // Mass is zero which disables a bunch of physics stuff in Bullet
955 UpdatePhysicalMassProperties(0f, false); 879 UpdatePhysicalMassProperties(0f, false);
956 // Set collision detection parameters 880 // Set collision detection parameters
957 if (BSParam.CcdMotionThreshold > 0f) 881 if (BSParam.CcdMotionThreshold > 0f)
958 { 882 {
959 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 883 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
960 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 884 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
961 } 885 }
962 886
963 // The activation state is 'disabled' so Bullet will not try to act on it. 887 // The activation state is 'disabled' so Bullet will not try to act on it.
964 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); 888 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
965 // Start it out sleeping and physical actions could wake it up. 889 // Start it out sleeping and physical actions could wake it up.
966 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); 890 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
967 891
968 // This collides like a static object 892 // This collides like a static object
969 PhysBody.collisionType = CollisionType.Static; 893 PhysBody.collisionType = CollisionType.Static;
@@ -971,11 +895,11 @@ public class BSPrim : BSPhysObject
971 else 895 else
972 { 896 {
973 // Not a Bullet static object 897 // Not a Bullet static object
974 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 898 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
975 899
976 // Set various physical properties so other object interact properly 900 // Set various physical properties so other object interact properly
977 PhysicsScene.PE.SetFriction(PhysBody, Friction); 901 PhysScene.PE.SetFriction(PhysBody, Friction);
978 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 902 PhysScene.PE.SetRestitution(PhysBody, Restitution);
979 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); 903 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
980 904
981 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 905 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
@@ -983,8 +907,8 @@ public class BSPrim : BSPhysObject
983 // PhysicsScene.PE.ClearAllForces(BSBody); 907 // PhysicsScene.PE.ClearAllForces(BSBody);
984 908
985 // For good measure, make sure the transform is set through to the motion state 909 // For good measure, make sure the transform is set through to the motion state
986 ForcePosition = _position; 910 ForcePosition = RawPosition;
987 ForceVelocity = _velocity; 911 ForceVelocity = RawVelocity;
988 ForceRotationalVelocity = _rotationalVelocity; 912 ForceRotationalVelocity = _rotationalVelocity;
989 913
990 // A dynamic object has mass 914 // A dynamic object has mass
@@ -993,22 +917,22 @@ public class BSPrim : BSPhysObject
993 // Set collision detection parameters 917 // Set collision detection parameters
994 if (BSParam.CcdMotionThreshold > 0f) 918 if (BSParam.CcdMotionThreshold > 0f)
995 { 919 {
996 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 920 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
997 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 921 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
998 } 922 }
999 923
1000 // Various values for simulation limits 924 // Various values for simulation limits
1001 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); 925 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
1002 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); 926 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
1003 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); 927 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
1004 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 928 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
1005 929
1006 // This collides like an object. 930 // This collides like an object.
1007 PhysBody.collisionType = CollisionType.Dynamic; 931 PhysBody.collisionType = CollisionType.Dynamic;
1008 932
1009 // Force activation of the object so Bullet will act on it. 933 // Force activation of the object so Bullet will act on it.
1010 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 934 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
1011 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 935 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
1012 } 936 }
1013 } 937 }
1014 938
@@ -1018,7 +942,7 @@ public class BSPrim : BSPhysObject
1018 // the functions after this one set up the state of a possibly newly created collision body. 942 // the functions after this one set up the state of a possibly newly created collision body.
1019 private void MakeSolid(bool makeSolid) 943 private void MakeSolid(bool makeSolid)
1020 { 944 {
1021 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); 945 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
1022 if (makeSolid) 946 if (makeSolid)
1023 { 947 {
1024 // Verify the previous code created the correct shape for this type of thing. 948 // Verify the previous code created the correct shape for this type of thing.
@@ -1026,7 +950,7 @@ public class BSPrim : BSPhysObject
1026 { 950 {
1027 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 951 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
1028 } 952 }
1029 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 953 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1030 } 954 }
1031 else 955 else
1032 { 956 {
@@ -1034,32 +958,23 @@ public class BSPrim : BSPhysObject
1034 { 958 {
1035 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 959 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1036 } 960 }
1037 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 961 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1038 962
1039 // Change collision info from a static object to a ghosty collision object 963 // Change collision info from a static object to a ghosty collision object
1040 PhysBody.collisionType = CollisionType.VolumeDetect; 964 PhysBody.collisionType = CollisionType.VolumeDetect;
1041 } 965 }
1042 } 966 }
1043 967
1044 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
1045 // they need waking up when parameters are changed.
1046 // Called in taint-time!!
1047 private void ActivateIfPhysical(bool forceIt)
1048 {
1049 if (IsPhysical && PhysBody.HasPhysicalBody)
1050 PhysicsScene.PE.Activate(PhysBody, forceIt);
1051 }
1052
1053 // Turn on or off the flag controlling whether collision events are returned to the simulator. 968 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1054 private void EnableCollisions(bool wantsCollisionEvents) 969 private void EnableCollisions(bool wantsCollisionEvents)
1055 { 970 {
1056 if (wantsCollisionEvents) 971 if (wantsCollisionEvents)
1057 { 972 {
1058 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 973 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1059 } 974 }
1060 else 975 else
1061 { 976 {
1062 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 977 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1063 } 978 }
1064 } 979 }
1065 980
@@ -1070,7 +985,7 @@ public class BSPrim : BSPhysObject
1070 { 985 {
1071 if (PhysBody.HasPhysicalBody) 986 if (PhysBody.HasPhysicalBody)
1072 { 987 {
1073 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 988 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1074 } 989 }
1075 else 990 else
1076 { 991 {
@@ -1105,12 +1020,12 @@ public class BSPrim : BSPhysObject
1105 public override bool FloatOnWater { 1020 public override bool FloatOnWater {
1106 set { 1021 set {
1107 _floatOnWater = value; 1022 _floatOnWater = value;
1108 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 1023 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1109 { 1024 {
1110 if (_floatOnWater) 1025 if (_floatOnWater)
1111 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 1026 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1112 else 1027 else
1113 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 1028 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1114 }); 1029 });
1115 } 1030 }
1116 } 1031 }
@@ -1122,7 +1037,7 @@ public class BSPrim : BSPhysObject
1122 _rotationalVelocity = value; 1037 _rotationalVelocity = value;
1123 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); 1038 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1124 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 1039 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1125 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 1040 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1126 { 1041 {
1127 ForceRotationalVelocity = _rotationalVelocity; 1042 ForceRotationalVelocity = _rotationalVelocity;
1128 }); 1043 });
@@ -1137,7 +1052,7 @@ public class BSPrim : BSPhysObject
1137 if (PhysBody.HasPhysicalBody) 1052 if (PhysBody.HasPhysicalBody)
1138 { 1053 {
1139 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 1054 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1140 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 1055 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1141 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 1056 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1142 ActivateIfPhysical(false); 1057 ActivateIfPhysical(false);
1143 } 1058 }
@@ -1153,7 +1068,7 @@ public class BSPrim : BSPhysObject
1153 get { return _buoyancy; } 1068 get { return _buoyancy; }
1154 set { 1069 set {
1155 _buoyancy = value; 1070 _buoyancy = value;
1156 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 1071 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1157 { 1072 {
1158 ForceBuoyancy = _buoyancy; 1073 ForceBuoyancy = _buoyancy;
1159 }); 1074 });
@@ -1171,179 +1086,54 @@ public class BSPrim : BSPhysObject
1171 } 1086 }
1172 } 1087 }
1173 1088
1174 // Used for MoveTo
1175 public override OMV.Vector3 PIDTarget {
1176 set
1177 {
1178 // TODO: add a sanity check -- don't move more than a region or something like that.
1179 _PIDTarget = value;
1180 }
1181 }
1182 public override float PIDTau {
1183 set { _PIDTau = value; }
1184 }
1185 public override bool PIDActive { 1089 public override bool PIDActive {
1186 set { 1090 set {
1187 if (value) 1091 base.MoveToTargetActive = value;
1092 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1188 { 1093 {
1189 // We're taking over after this. 1094 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1190 ZeroMotion(true); 1095 });
1191 1096 }
1192 _targetMotor = new BSVMotor("BSPrim.PIDTarget", 1097 }
1193 _PIDTau, // timeScale
1194 BSMotor.Infinite, // decay time scale
1195 BSMotor.InfiniteVector, // friction timescale
1196 1f // efficiency
1197 );
1198 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1199 _targetMotor.SetTarget(_PIDTarget);
1200 _targetMotor.SetCurrent(RawPosition);
1201 /*
1202 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1203 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1204
1205 _targetMotor.SetTarget(_PIDTarget);
1206 _targetMotor.SetCurrent(RawPosition);
1207 _targetMotor.TimeScale = _PIDTau;
1208 _targetMotor.Efficiency = 1f;
1209 */
1210
1211 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1212 {
1213 if (!IsPhysicallyActive)
1214 {
1215 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1216 return;
1217 }
1218
1219 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1220
1221 // 'movePosition' is where we'd like the prim to be at this moment.
1222 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1223 1098
1224 // If we are very close to our target, turn off the movement motor. 1099 public override OMV.Vector3 PIDTarget
1225 if (_targetMotor.ErrorIsZero()) 1100 {
1226 { 1101 set
1227 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", 1102 {
1228 LocalID, movePosition, RawPosition, Mass); 1103 base.PIDTarget = value;
1229 ForcePosition = _targetMotor.TargetValue; 1104 BSActor actor;
1230 _targetMotor.Enabled = false; 1105 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1231 }
1232 else
1233 {
1234 _position = movePosition;
1235 PositionSanityCheck(true /* intaintTime */);
1236 ForcePosition = _position;
1237 }
1238 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1239 });
1240 }
1241 else
1242 { 1106 {
1243 // Stop any targetting 1107 // if the actor exists, tell it to refresh its values.
1244 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); 1108 actor.Refresh();
1245 } 1109 }
1110
1246 } 1111 }
1247 } 1112 }
1248
1249 // Used for llSetHoverHeight and maybe vehicle height 1113 // Used for llSetHoverHeight and maybe vehicle height
1250 // Hover Height will override MoveTo target's Z 1114 // Hover Height will override MoveTo target's Z
1251 public override bool PIDHoverActive { 1115 public override bool PIDHoverActive {
1252 set { 1116 set {
1253 if (value) 1117 base.HoverActive = value;
1118 EnableActor(HoverActive, HoverActorName, delegate()
1254 { 1119 {
1255 // Turning the target on 1120 return new BSActorHover(PhysScene, this, HoverActorName);
1256 _hoverMotor = new BSFMotor("BSPrim.Hover", 1121 });
1257 _PIDHoverTau, // timeScale
1258 BSMotor.Infinite, // decay time scale
1259 BSMotor.Infinite, // friction timescale
1260 1f // efficiency
1261 );
1262 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1263 _hoverMotor.SetCurrent(RawPosition.Z);
1264 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1265
1266 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1267 {
1268 // Don't do hovering while the object is selected.
1269 if (!IsPhysicallyActive)
1270 return;
1271
1272 _hoverMotor.SetCurrent(RawPosition.Z);
1273 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1274 float targetHeight = _hoverMotor.Step(timeStep);
1275
1276 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1277 // Compute the amount of force to push us there.
1278 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1279 // Undo anything the object thinks it's doing at the moment
1280 moveForce = -RawVelocity.Z * Mass;
1281
1282 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1283 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1284 });
1285 }
1286 else
1287 {
1288 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1289 }
1290 }
1291 }
1292 public override float PIDHoverHeight {
1293 set { _PIDHoverHeight = value; }
1294 }
1295 public override PIDHoverType PIDHoverType {
1296 set { _PIDHoverType = value; }
1297 }
1298 public override float PIDHoverTau {
1299 set { _PIDHoverTau = value; }
1300 }
1301 // Based on current position, determine what we should be hovering at now.
1302 // Must recompute often. What if we walked offa cliff>
1303 private float ComputeCurrentPIDHoverHeight()
1304 {
1305 float ret = _PIDHoverHeight;
1306 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1307
1308 switch (_PIDHoverType)
1309 {
1310 case PIDHoverType.Ground:
1311 ret = groundHeight + _PIDHoverHeight;
1312 break;
1313 case PIDHoverType.GroundAndWater:
1314 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1315 if (groundHeight > waterHeight)
1316 {
1317 ret = groundHeight + _PIDHoverHeight;
1318 }
1319 else
1320 {
1321 ret = waterHeight + _PIDHoverHeight;
1322 }
1323 break;
1324 } 1122 }
1325 return ret;
1326 } 1123 }
1327 1124
1328
1329 // For RotLookAt
1330 public override OMV.Quaternion APIDTarget { set { return; } }
1331 public override bool APIDActive { set { return; } }
1332 public override float APIDStrength { set { return; } }
1333 public override float APIDDamping { set { return; } }
1334
1335 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1125 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1336 // Per documentation, max force is limited. 1126 // Per documentation, max force is limited.
1337 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 1127 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1338 1128
1339 // Since this force is being applied in only one step, make this a force per second. 1129 // Since this force is being applied in only one step, make this a force per second.
1340 addForce /= PhysicsScene.LastTimeStep; 1130 addForce /= PhysScene.LastTimeStep;
1341 AddForce(addForce, pushforce, false /* inTaintTime */); 1131 AddForce(addForce, pushforce, false /* inTaintTime */);
1342 } 1132 }
1343 1133
1344 // Applying a force just adds this to the total force on the object. 1134 // Applying a force just adds this to the total force on the object.
1345 // This added force will only last the next simulation tick. 1135 // This added force will only last the next simulation tick.
1346 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1136 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1347 // for an object, doesn't matter if force is a pushforce or not 1137 // for an object, doesn't matter if force is a pushforce or not
1348 if (IsPhysicallyActive) 1138 if (IsPhysicallyActive)
1349 { 1139 {
@@ -1352,13 +1142,15 @@ public class BSPrim : BSPhysObject
1352 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); 1142 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1353 1143
1354 OMV.Vector3 addForce = force; 1144 OMV.Vector3 addForce = force;
1355 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1145 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1356 { 1146 {
1357 // Bullet adds this central force to the total force for this tick 1147 // Bullet adds this central force to the total force for this tick.
1148 // Deep down in Bullet:
1149 // linearVelocity += totalForce / mass * timeStep;
1358 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); 1150 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1359 if (PhysBody.HasPhysicalBody) 1151 if (PhysBody.HasPhysicalBody)
1360 { 1152 {
1361 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 1153 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1362 ActivateIfPhysical(false); 1154 ActivateIfPhysical(false);
1363 } 1155 }
1364 }); 1156 });
@@ -1380,13 +1172,13 @@ public class BSPrim : BSPhysObject
1380 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); 1172 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1381 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); 1173 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1382 1174
1383 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() 1175 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1384 { 1176 {
1385 // Bullet adds this impulse immediately to the velocity 1177 // Bullet adds this impulse immediately to the velocity
1386 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); 1178 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1387 if (PhysBody.HasPhysicalBody) 1179 if (PhysBody.HasPhysicalBody)
1388 { 1180 {
1389 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); 1181 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1390 ActivateIfPhysical(false); 1182 ActivateIfPhysical(false);
1391 } 1183 }
1392 }); 1184 });
@@ -1399,20 +1191,18 @@ public class BSPrim : BSPhysObject
1399 } 1191 }
1400 } 1192 }
1401 1193
1402 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1194 // BSPhysObject.AddAngularForce()
1403 AddAngularForce(force, pushforce, false); 1195 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1404 }
1405 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1406 { 1196 {
1407 if (force.IsFinite()) 1197 if (force.IsFinite())
1408 { 1198 {
1409 OMV.Vector3 angForce = force; 1199 OMV.Vector3 angForce = force;
1410 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() 1200 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1411 { 1201 {
1412 if (PhysBody.HasPhysicalBody) 1202 if (PhysBody.HasPhysicalBody)
1413 { 1203 {
1414 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); 1204 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1415 PhysicsScene.PE.ApplyTorque(PhysBody, angForce); 1205 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1416 ActivateIfPhysical(false); 1206 ActivateIfPhysical(false);
1417 } 1207 }
1418 }); 1208 });
@@ -1431,11 +1221,11 @@ public class BSPrim : BSPhysObject
1431 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1221 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1432 { 1222 {
1433 OMV.Vector3 applyImpulse = impulse; 1223 OMV.Vector3 applyImpulse = impulse;
1434 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1224 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1435 { 1225 {
1436 if (PhysBody.HasPhysicalBody) 1226 if (PhysBody.HasPhysicalBody)
1437 { 1227 {
1438 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); 1228 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1439 ActivateIfPhysical(false); 1229 ActivateIfPhysical(false);
1440 } 1230 }
1441 }); 1231 });
@@ -1721,9 +1511,11 @@ public class BSPrim : BSPhysObject
1721 volume *= (profileEnd - profileBegin); 1511 volume *= (profileEnd - profileBegin);
1722 1512
1723 returnMass = Density * BSParam.DensityScaleFactor * volume; 1513 returnMass = Density * BSParam.DensityScaleFactor * volume;
1724 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1725 1514
1726 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); 1515 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1516 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1517 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1518 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1727 1519
1728 return returnMass; 1520 return returnMass;
1729 }// end CalculateMass 1521 }// end CalculateMass
@@ -1736,13 +1528,14 @@ public class BSPrim : BSPhysObject
1736 { 1528 {
1737 // Create the correct physical representation for this type of object. 1529 // Create the correct physical representation for this type of object.
1738 // Updates base.PhysBody and base.PhysShape with the new information. 1530 // Updates base.PhysBody and base.PhysShape with the new information.
1739 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1531 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1740 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1532 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1741 { 1533 {
1742 // Called if the current prim body is about to be destroyed. 1534 // Called if the current prim body is about to be destroyed.
1743 // Remove all the physical dependencies on the old body. 1535 // Remove all the physical dependencies on the old body.
1744 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1536 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1745 RemoveBodyDependencies(); 1537 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1538 RemoveDependencies();
1746 }); 1539 });
1747 1540
1748 // Make sure the properties are set on the new object 1541 // Make sure the properties are set on the new object
@@ -1750,33 +1543,45 @@ public class BSPrim : BSPhysObject
1750 return; 1543 return;
1751 } 1544 }
1752 1545
1753 protected virtual void RemoveBodyDependencies() 1546 // Called at taint-time
1547 protected virtual void RemoveDependencies()
1754 { 1548 {
1755 VehicleController.RemoveBodyDependencies(this); 1549 PhysicalActors.RemoveDependencies();
1550 }
1551
1552 #region Extension
1553 public override object Extension(string pFunct, params object[] pParams)
1554 {
1555 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1556 object ret = null;
1557 switch (pFunct)
1558 {
1559 default:
1560 ret = base.Extension(pFunct, pParams);
1561 break;
1562 }
1563 return ret;
1756 } 1564 }
1565 #endregion // Extension
1757 1566
1758 // The physics engine says that properties have updated. Update same and inform 1567 // The physics engine says that properties have updated. Update same and inform
1759 // the world that things have changed. 1568 // the world that things have changed.
1569 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1570 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1760 public override void UpdateProperties(EntityProperties entprop) 1571 public override void UpdateProperties(EntityProperties entprop)
1761 { 1572 {
1573 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1762 TriggerPreUpdatePropertyAction(ref entprop); 1574 TriggerPreUpdatePropertyAction(ref entprop);
1763 1575
1764 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1765 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1766 if (VehicleController.IsActive)
1767 {
1768 entprop.RotationalVelocity = OMV.Vector3.Zero;
1769 }
1770
1771 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG 1576 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1772 1577
1773 // Assign directly to the local variables so the normal set actions do not happen 1578 // Assign directly to the local variables so the normal set actions do not happen
1774 _position = entprop.Position; 1579 RawPosition = entprop.Position;
1775 _orientation = entprop.Rotation; 1580 RawOrientation = entprop.Rotation;
1776 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be 1581 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1777 // very sensitive to velocity changes. 1582 // very sensitive to velocity changes.
1778 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) 1583 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1779 _velocity = entprop.Velocity; 1584 RawVelocity = entprop.Velocity;
1780 _acceleration = entprop.Acceleration; 1585 _acceleration = entprop.Acceleration;
1781 _rotationalVelocity = entprop.RotationalVelocity; 1586 _rotationalVelocity = entprop.RotationalVelocity;
1782 1587
@@ -1785,29 +1590,20 @@ public class BSPrim : BSPhysObject
1785 // The sanity check can change the velocity and/or position. 1590 // The sanity check can change the velocity and/or position.
1786 if (PositionSanityCheck(true /* inTaintTime */ )) 1591 if (PositionSanityCheck(true /* inTaintTime */ ))
1787 { 1592 {
1788 entprop.Position = _position; 1593 entprop.Position = RawPosition;
1789 entprop.Velocity = _velocity; 1594 entprop.Velocity = RawVelocity;
1790 entprop.RotationalVelocity = _rotationalVelocity; 1595 entprop.RotationalVelocity = _rotationalVelocity;
1791 entprop.Acceleration = _acceleration; 1596 entprop.Acceleration = _acceleration;
1792 } 1597 }
1793 1598
1794 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG 1599 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1795 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); 1600 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1796 1601
1797 // remember the current and last set values 1602 // remember the current and last set values
1798 LastEntityProperties = CurrentEntityProperties; 1603 LastEntityProperties = CurrentEntityProperties;
1799 CurrentEntityProperties = entprop; 1604 CurrentEntityProperties = entprop;
1800 1605
1801 base.RequestPhysicsterseUpdate(); 1606 PhysScene.PostUpdate(this);
1802 /*
1803 else
1804 {
1805 // For debugging, report the movement of children
1806 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1807 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1808 entprop.Acceleration, entprop.RotationalVelocity);
1809 }
1810 */
1811 } 1607 }
1812} 1608}
1813} 1609}