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.cs959
1 files changed, 588 insertions, 371 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..54bf063 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,19 +45,20 @@ public sealed class BSPrim : BSPhysObject
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.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 49
51 private bool _grabbed; 50 private bool _grabbed;
52 private bool _isSelected; 51 private bool _isSelected;
53 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53
54 // _position is what the simulator thinks the positions of the prim is.
54 private OMV.Vector3 _position; 55 private OMV.Vector3 _position;
56
55 private float _mass; // the mass of this object 57 private float _mass; // the mass of this object
56 private float _density; 58 private float _density;
57 private OMV.Vector3 _force; 59 private OMV.Vector3 _force;
58 private OMV.Vector3 _velocity; 60 private OMV.Vector3 _velocity;
59 private OMV.Vector3 _torque; 61 private OMV.Vector3 _torque;
60 private float _collisionScore;
61 private OMV.Vector3 _acceleration; 62 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation; 63 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 64 private int _physicsActorType;
@@ -67,23 +68,21 @@ public sealed class BSPrim : BSPhysObject
67 private float _restitution; 68 private float _restitution;
68 private bool _setAlwaysRun; 69 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 70 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 71 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 72 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 73 private bool _kinematic;
76 private float _buoyancy; 74 private float _buoyancy;
77 75
78 private BSDynamics _vehicle; 76 public BSDynamics VehicleController { get; private set; }
79 77
78 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 79 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 80 private float _PIDTau;
83 private bool _useHoverPID; 81
82 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 83 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 84 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 85 private float _PIDHoverTau;
87 86
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,23 +92,27 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 92 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 93 _position = pos;
95 _size = size; 94 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 96 _orientation = rotation;
98 _buoyancy = 1f; 97 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 98 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 99 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 100 BaseShape = pbs;
102 _isPhysical = pisPhysical; 101 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 102 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 103
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material 104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
106 _density = PhysicsScene.Params.defaultDensity;
107 _friction = PhysicsScene.Params.defaultFriction;
106 _restitution = PhysicsScene.Params.defaultRestitution; 108 _restitution = PhysicsScene.Params.defaultRestitution;
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness 109
110 VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness
111
108 _mass = CalculateMass(); 112 _mass = CalculateMass();
109 113
110 // No body or shape yet 114 // Cause linkset variables to be initialized (like mass)
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 115 Linkset.Refresh(this);
112 PhysShape = new BulletShape(IntPtr.Zero);
113 116
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 117 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 118 // do the actual object creation at taint time
@@ -117,7 +120,7 @@ public sealed class BSPrim : BSPhysObject
117 { 120 {
118 CreateGeomAndObject(true); 121 CreateGeomAndObject(true);
119 122
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 123 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 124 });
122 } 125 }
123 126
@@ -125,10 +128,11 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 128 public override void Destroy()
126 { 129 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
131 base.Destroy();
128 132
129 // Undo any links between me and any other object 133 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot; 134 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG DEBUG
131 int childrenBefore = Linkset.NumberOfChildren; 135 int childrenBefore = Linkset.NumberOfChildren; // DEBUG DEBUG
132 136
133 Linkset = Linkset.RemoveMeFromLinkset(this); 137 Linkset = Linkset.RemoveMeFromLinkset(this);
134 138
@@ -142,8 +146,10 @@ public sealed class BSPrim : BSPhysObject
142 { 146 {
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 147 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 148 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 149 PhysicsScene.Shapes.DereferenceBody(PhysBody, null);
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 150 PhysBody.Clear();
151 PhysicsScene.Shapes.DereferenceShape(PhysShape, null);
152 PhysShape.Clear();
147 }); 153 });
148 } 154 }
149 155
@@ -157,16 +163,15 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 163 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built. 164 // the physical shape, that is done when the geometry is built.
159 _size = value; 165 _size = value;
166 Scale = _size;
160 ForceBodyShapeRebuild(false); 167 ForceBodyShapeRebuild(false);
161 } 168 }
162 } 169 }
163 // Scale is what we set in the physics engine. It is different than 'size' in that
164 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
165 public override OMV.Vector3 Scale { get; set; }
166 170
167 public override PrimitiveBaseShape Shape { 171 public override PrimitiveBaseShape Shape {
168 set { 172 set {
169 BaseShape = value; 173 BaseShape = value;
174 LastAssetBuildFailed = false;
170 ForceBodyShapeRebuild(false); 175 ForceBodyShapeRebuild(false);
171 } 176 }
172 } 177 }
@@ -176,12 +181,19 @@ public sealed class BSPrim : BSPhysObject
176 181
177 public override bool ForceBodyShapeRebuild(bool inTaintTime) 182 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 { 183 {
179 LastAssetBuildFailed = false; 184 if (inTaintTime)
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 { 185 {
182 _mass = CalculateMass(); // changing the shape changes the mass 186 _mass = CalculateMass(); // changing the shape changes the mass
183 CreateGeomAndObject(true); 187 CreateGeomAndObject(true);
184 }); 188 }
189 else
190 {
191 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
192 {
193 _mass = CalculateMass(); // changing the shape changes the mass
194 CreateGeomAndObject(true);
195 });
196 }
185 return true; 197 return true;
186 } 198 }
187 public override bool Grabbed { 199 public override bool Grabbed {
@@ -189,15 +201,23 @@ public sealed class BSPrim : BSPhysObject
189 } 201 }
190 } 202 }
191 public override bool Selected { 203 public override bool Selected {
192 set { 204 set
193 _isSelected = value; 205 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 206 if (value != _isSelected)
195 { 207 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 208 _isSelected = value;
197 SetObjectDynamic(false); 209 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 210 {
211 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
212 SetObjectDynamic(false);
213 });
214 }
199 } 215 }
200 } 216 }
217 public override bool IsSelected
218 {
219 get { return _isSelected; }
220 }
201 public override void CrossingFailure() { return; } 221 public override void CrossingFailure() { return; }
202 222
203 // link me to the specified parent 223 // link me to the specified parent
@@ -244,7 +264,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 264 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 265 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 266 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 267 if (PhysBody.HasPhysicalBody)
268 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 269 });
249 } 270 }
250 public override void ZeroAngularMotion(bool inTaintTime) 271 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,8 +274,12 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 274 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 275 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 276 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 277 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 278 if (PhysBody.HasPhysicalBody)
279 {
280 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
281 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
282 }
258 }); 283 });
259 } 284 }
260 285
@@ -271,41 +296,52 @@ public sealed class BSPrim : BSPhysObject
271 } 296 }
272 public override OMV.Vector3 Position { 297 public override OMV.Vector3 Position {
273 get { 298 get {
299 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
300 * and does not fetch this position info for children. Thus this is commented out.
274 // child prims move around based on their parent. Need to get the latest location 301 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this)) 302 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this); 303 _position = Linkset.PositionGet(this);
304 */
277 305
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 306 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 307 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody) - PositionDisplacement;
280 return _position; 308 return _position;
281 } 309 }
282 set { 310 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 311 // If the position must be forced into the physics engine, use ForcePosition.
312 // All positions are given in world positions.
284 if (_position == value) 313 if (_position == value)
285 { 314 {
315 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 316 return;
287 } 317 }
288 _position = value; 318 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 319 PositionSanityCheck(false);
320
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 321 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 322 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 323 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 324 ForcePosition = _position;
295 ActivateIfPhysical(false); 325
326 // A linkset might need to know if a component information changed.
327 Linkset.UpdateProperties(UpdatedProperties.Position, this);
328
296 }); 329 });
297 } 330 }
298 } 331 }
332
299 public override OMV.Vector3 ForcePosition { 333 public override OMV.Vector3 ForcePosition {
300 get { 334 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 335 _position = PhysicsScene.PE.GetPosition(PhysBody) - PositionDisplacement;
302 return _position; 336 return _position;
303 } 337 }
304 set { 338 set {
305 _position = value; 339 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 340 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 341 {
308 ActivateIfPhysical(false); 342 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
343 ActivateIfPhysical(false);
344 }
309 } 345 }
310 } 346 }
311 347
@@ -316,51 +352,64 @@ public sealed class BSPrim : BSPhysObject
316 { 352 {
317 bool ret = false; 353 bool ret = false;
318 354
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 355 // We don't care where non-physical items are placed
356 if (!IsPhysicallyActive)
357 return ret;
358
359 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
360 {
361 // The physical object is out of the known/simulated area.
362 // Upper levels of code will handle the transition to other areas so, for
363 // the time, we just ignore the position.
364 return ret;
365 }
366
367 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 368 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 369 if (RawPosition.Z < terrainHeight)
322 { 370 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 371 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 372 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 373 // If the object is below ground it just has to be moved up because pushing will
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 374 // not get it through the terrain
375 _position.Z = targetHeight;
376 if (inTaintTime)
377 {
378 ForcePosition = _position;
379 }
380 // If we are throwing the object around, zero its other forces
381 ZeroMotion(inTaintTime);
327 ret = true; 382 ret = true;
328 } 383 }
329 384
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 385 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 386 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 387 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 388 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 389 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 390 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 391 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 392 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
393
394 // Apply upforce and overcome gravity.
395 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
396 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
397 AddForce(correctionForce, false, inTaintTime);
338 ret = true; 398 ret = true;
339 } 399 }
340 } 400 }
341 401
342 // TODO: check for out of bounds
343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
345 if (ret)
346 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
348 {
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 }
353 return ret; 402 return ret;
354 } 403 }
355 404
356 // Return the effective mass of the object. 405 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 406 // The definition of this call is to return the mass of the prim.
407 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 408 public override float Mass
359 { 409 {
360 get 410 get
361 { 411 {
362 return Linkset.LinksetMass; 412 return _mass;
363 // return _mass;
364 } 413 }
365 } 414 }
366 415
@@ -370,25 +419,64 @@ public sealed class BSPrim : BSPhysObject
370 } 419 }
371 // Set the physical mass to the passed mass. 420 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 421 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 422 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 423 {
375 if (IsStatic) 424 if (PhysBody.HasPhysicalBody)
376 { 425 {
377 Inertia = OMV.Vector3.Zero; 426 if (IsStatic)
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia); 427 {
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 428 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
380 } 429 Inertia = OMV.Vector3.Zero;
381 else 430 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
382 { 431 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 432 }
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 433 else
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 434 {
386 // center of mass is at the zero of the object 435 OMV.Vector3 grav = ComputeGravity(Buoyancy);
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); 436
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); 437 if (inWorld)
438 {
439 // Changing interesting properties doesn't change proxy and collision cache
440 // information. The Bullet solution is to re-add the object to the world
441 // after parameters are changed.
442 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
443 }
444
445 // The computation of mass props requires gravity to be set on the object.
446 PhysicsScene.PE.SetGravity(PhysBody, grav);
447
448 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
449 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
450 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
451
452 // center of mass is at the zero of the object
453 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
454 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
455
456 if (inWorld)
457 {
458 AddObjectToPhysicalWorld();
459 }
460
461 // Must set gravity after it has been added to the world because, for unknown reasons,
462 // adding the object resets the object's gravity to world gravity
463 PhysicsScene.PE.SetGravity(PhysBody, grav);
464
465 }
389 } 466 }
390 } 467 }
391 468
469 // Return what gravity should be set to this very moment
470 public OMV.Vector3 ComputeGravity(float buoyancy)
471 {
472 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
473
474 if (!IsStatic)
475 ret *= (1f - buoyancy);
476
477 return ret;
478 }
479
392 // Is this used? 480 // Is this used?
393 public override OMV.Vector3 CenterOfMass 481 public override OMV.Vector3 CenterOfMass
394 { 482 {
@@ -405,30 +493,60 @@ public sealed class BSPrim : BSPhysObject
405 get { return _force; } 493 get { return _force; }
406 set { 494 set {
407 _force = value; 495 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 496 if (_force != OMV.Vector3.Zero)
409 { 497 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 498 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 499 // Bullet clears the forces applied last frame.
412 }); 500 RegisterPreStepAction("BSPrim.setForce", LocalID,
501 delegate(float timeStep)
502 {
503 if (!IsPhysicallyActive)
504 {
505 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
506 return;
507 }
508
509 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
510 if (PhysBody.HasPhysicalBody)
511 {
512 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
513 ActivateIfPhysical(false);
514 }
515 }
516 );
517 }
518 else
519 {
520 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
521 }
413 } 522 }
414 } 523 }
415 524
416 public override int VehicleType { 525 public override int VehicleType {
417 get { 526 get {
418 return (int)_vehicle.Type; // if we are a vehicle, return that type 527 return (int)VehicleController.Type; // if we are a vehicle, return that type
419 } 528 }
420 set { 529 set {
421 Vehicle type = (Vehicle)value; 530 Vehicle type = (Vehicle)value;
422 531
423 // Tell the scene about the vehicle so it will get processing each frame.
424 PhysicsScene.VehicleInSceneTypeChanged(this, type);
425
426 PhysicsScene.TaintedObject("setVehicleType", delegate() 532 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 533 {
428 // Done at taint time so we're sure the physics engine is not using the variables 534 // Done at taint time so we're sure the physics engine is not using the variables
429 // Vehicle code changes the parameters for this vehicle type. 535 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 536 VehicleController.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 537 ActivateIfPhysical(false);
538
539 // If an active vehicle, register the vehicle code to be called before each step
540 if (VehicleController.Type == Vehicle.TYPE_NONE)
541 {
542 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
543 PhysicsScene.AfterStep -= VehicleController.PostStep;
544 }
545 else
546 {
547 RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step);
548 PhysicsScene.AfterStep += VehicleController.PostStep;
549 }
432 }); 550 });
433 } 551 }
434 } 552 }
@@ -436,7 +554,7 @@ public sealed class BSPrim : BSPhysObject
436 { 554 {
437 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 555 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
438 { 556 {
439 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 557 VehicleController.ProcessFloatVehicleParam((Vehicle)param, value);
440 ActivateIfPhysical(false); 558 ActivateIfPhysical(false);
441 }); 559 });
442 } 560 }
@@ -444,7 +562,7 @@ public sealed class BSPrim : BSPhysObject
444 { 562 {
445 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 563 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
446 { 564 {
447 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 565 VehicleController.ProcessVectorVehicleParam((Vehicle)param, value);
448 ActivateIfPhysical(false); 566 ActivateIfPhysical(false);
449 }); 567 });
450 } 568 }
@@ -452,7 +570,7 @@ public sealed class BSPrim : BSPhysObject
452 { 570 {
453 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 571 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
454 { 572 {
455 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 573 VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation);
456 ActivateIfPhysical(false); 574 ActivateIfPhysical(false);
457 }); 575 });
458 } 576 }
@@ -460,27 +578,10 @@ public sealed class BSPrim : BSPhysObject
460 { 578 {
461 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 579 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
462 { 580 {
463 _vehicle.ProcessVehicleFlags(param, remove); 581 VehicleController.ProcessVehicleFlags(param, remove);
464 }); 582 });
465 } 583 }
466 584
467 // Called each simulation step to advance vehicle characteristics.
468 // Called from Scene when doing simulation step so we're in taint processing time.
469 public override void StepVehicle(float timeStep)
470 {
471 if (IsPhysical && _vehicle.IsActive)
472 {
473 _vehicle.Step(timeStep);
474 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
475 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
476 {
477 // This resets the interpolation values and recomputes the tensor variables
478 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
479 });
480 */
481 }
482 }
483
484 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 585 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 586 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 587 bool newValue = (param != 0);
@@ -495,6 +596,11 @@ public sealed class BSPrim : BSPhysObject
495 } 596 }
496 return; 597 return;
497 } 598 }
599 public override OMV.Vector3 RawVelocity
600 {
601 get { return _velocity; }
602 set { _velocity = value; }
603 }
498 public override OMV.Vector3 Velocity { 604 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 605 get { return _velocity; }
500 set { 606 set {
@@ -502,30 +608,53 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 608 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 609 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 610 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 611 ForceVelocity = _velocity;
506 }); 612 });
507 } 613 }
508 } 614 }
509 public override OMV.Vector3 ForceVelocity { 615 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 616 get { return _velocity; }
511 set { 617 set {
618 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
619
512 _velocity = value; 620 _velocity = value;
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 621 if (PhysBody.HasPhysicalBody)
622 {
623 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
624 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
625 ActivateIfPhysical(false);
626 }
514 } 627 }
515 } 628 }
516 public override OMV.Vector3 Torque { 629 public override OMV.Vector3 Torque {
517 get { return _torque; } 630 get { return _torque; }
518 set { 631 set {
519 _torque = value; 632 _torque = value;
520 AddAngularForce(_torque, false, false); 633 if (_torque != OMV.Vector3.Zero)
634 {
635 // If the torque is non-zero, it must be reapplied each tick because
636 // Bullet clears the forces applied last frame.
637 RegisterPreStepAction("BSPrim.setTorque", LocalID,
638 delegate(float timeStep)
639 {
640 if (!IsPhysicallyActive)
641 {
642 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
643 return;
644 }
645
646 if (PhysBody.HasPhysicalBody)
647 AddAngularForce(_torque, false, true);
648 }
649 );
650 }
651 else
652 {
653 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
654 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 655 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 656 }
523 } 657 }
524 public override float CollisionScore {
525 get { return _collisionScore; }
526 set { _collisionScore = value;
527 }
528 }
529 public override OMV.Vector3 Acceleration { 658 public override OMV.Vector3 Acceleration {
530 get { return _acceleration; } 659 get { return _acceleration; }
531 set { _acceleration = value; } 660 set { _acceleration = value; }
@@ -537,23 +666,28 @@ public sealed class BSPrim : BSPhysObject
537 } 666 }
538 public override OMV.Quaternion Orientation { 667 public override OMV.Quaternion Orientation {
539 get { 668 get {
669 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
670 * and does not fetch this position info for children. Thus this is commented out.
540 // Children move around because tied to parent. Get a fresh value. 671 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this)) 672 if (!Linkset.IsRoot(this))
542 { 673 {
543 _orientation = Linkset.Orientation(this); 674 _orientation = Linkset.OrientationGet(this);
544 } 675 }
676 */
545 return _orientation; 677 return _orientation;
546 } 678 }
547 set { 679 set {
548 if (_orientation == value) 680 if (_orientation == value)
549 return; 681 return;
550 _orientation = value; 682 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 683
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 684 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 685 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 686 ForceOrientation = _orientation;
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 687
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 688 // A linkset might need to know if a component information changed.
689 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
690
557 }); 691 });
558 } 692 }
559 } 693 }
@@ -562,13 +696,14 @@ public sealed class BSPrim : BSPhysObject
562 { 696 {
563 get 697 get
564 { 698 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 699 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 700 return _orientation;
567 } 701 }
568 set 702 set
569 { 703 {
570 _orientation = value; 704 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 705 if (PhysBody.HasPhysicalBody)
706 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
572 } 707 }
573 } 708 }
574 public override int PhysicsActorType { 709 public override int PhysicsActorType {
@@ -583,7 +718,7 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 718 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 719 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 720 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 721 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 722 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 723 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 724 ZeroMotion(true);
@@ -604,6 +739,12 @@ public sealed class BSPrim : BSPhysObject
604 get { return !IsPhantom && !_isVolumeDetect; } 739 get { return !IsPhantom && !_isVolumeDetect; }
605 } 740 }
606 741
742 // The object is moving and is actively being dynamic in the physical world
743 public override bool IsPhysicallyActive
744 {
745 get { return !_isSelected && IsPhysical; }
746 }
747
607 // Make gravity work if the object is physical and not selected 748 // Make gravity work if the object is physical and not selected
608 // Called at taint-time!! 749 // Called at taint-time!!
609 private void SetObjectDynamic(bool forceRebuild) 750 private void SetObjectDynamic(bool forceRebuild)
@@ -618,19 +759,19 @@ public sealed class BSPrim : BSPhysObject
618 // isSolid: other objects bounce off of this object 759 // isSolid: other objects bounce off of this object
619 // isVolumeDetect: other objects pass through but can generate collisions 760 // isVolumeDetect: other objects pass through but can generate collisions
620 // collisionEvents: whether this object returns collision events 761 // collisionEvents: whether this object returns collision events
621 private void UpdatePhysicalParameters() 762 public void UpdatePhysicalParameters()
622 { 763 {
623 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); 764 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
624 765
625 // Mangling all the physical properties requires the object not be in the physical world. 766 // Mangling all the physical properties requires the object not be in the physical world.
626 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 767 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
627 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 768 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 769
629 // Set up the object physicalness (does gravity and collisions move this object) 770 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 771 MakeDynamic(IsStatic);
631 772
632 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 773 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
633 _vehicle.Refresh(); 774 VehicleController.Refresh();
634 775
635 // Arrange for collision events if the simulator wants them 776 // Arrange for collision events if the simulator wants them
636 EnableCollisions(SubscribedEvents()); 777 EnableCollisions(SubscribedEvents());
@@ -638,16 +779,10 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 779 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 780 MakeSolid(IsSolid);
640 781
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 782 AddObjectToPhysicalWorld();
642 783
643 // Rebuild its shape 784 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 785 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
645
646 // Collision filter can be set only when the object is in the world
647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
648 {
649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
650 }
651 786
652 // Recompute any linkset parameters. 787 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that 788 // When going from non-physical to physical, this re-enables the constraints that
@@ -655,8 +790,8 @@ public sealed class BSPrim : BSPhysObject
655 // For compound based linksets, this enables and disables interactions of the children. 790 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this); 791 Linkset.Refresh(this);
657 792
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 793 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
659 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); 794 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 795 }
661 796
662 // "Making dynamic" means changing to and from static. 797 // "Making dynamic" means changing to and from static.
@@ -669,74 +804,80 @@ public sealed class BSPrim : BSPhysObject
669 if (makeStatic) 804 if (makeStatic)
670 { 805 {
671 // Become a Bullet 'static' object type 806 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 807 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 808 // Stop all movement
674 ZeroMotion(true); 809 ZeroMotion(true);
675 // Center of mass is at the center of the object 810
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 811 // Set various physical properties so other object interact properly
812 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
813 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
814 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
815
677 // Mass is zero which disables a bunch of physics stuff in Bullet 816 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 817 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 818 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 819 if (BSParam.CcdMotionThreshold > 0f)
681 { 820 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 821 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 822 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 823 }
685 // There can be special things needed for implementing linksets 824
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 825 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 826 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 827 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 828 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
829
830 // This collides like a static object
831 PhysBody.collisionType = CollisionType.Static;
691 832
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 833 // There can be special things needed for implementing linksets
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 834 Linkset.MakeStatic(this);
694 } 835 }
695 else 836 else
696 { 837 {
697 // Not a Bullet static object 838 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 839 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 840
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 841 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 842 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 843 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
844 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
703 845
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 846 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
705 // Since this can be called multiple times, only zero forces when becoming physical 847 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 848 // PhysicsScene.PE.ClearAllForces(BSBody);
707 849
708 // For good measure, make sure the transform is set through to the motion state 850 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 851 PhysicsScene.PE.SetTranslation(PhysBody, _position + PositionDisplacement, _orientation);
710 852
711 // Center of mass is at the center of the object 853 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 854 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
713 855
714 // A dynamic object has mass 856 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 857 UpdatePhysicalMassProperties(RawMass, false);
716 858
717 // Set collision detection parameters 859 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 860 if (BSParam.CcdMotionThreshold > 0f)
719 { 861 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 862 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 863 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 864 }
723 865
724 // Various values for simulation limits 866 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 867 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 868 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 869 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 870 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 871
730 // There might be special things needed for implementing linksets. 872 // This collides like an object.
731 Linkset.MakeDynamic(this); 873 PhysBody.collisionType = CollisionType.Dynamic;
732 874
733 // Force activation of the object so Bullet will act on it. 875 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 876 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 877 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737 878
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 879 // There might be special things needed for implementing linksets.
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 880 Linkset.MakeDynamic(this);
740 } 881 }
741 } 882 }
742 883
@@ -746,7 +887,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 887 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 888 private void MakeSolid(bool makeSolid)
748 { 889 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 890 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 891 if (makeSolid)
751 { 892 {
752 // Verify the previous code created the correct shape for this type of thing. 893 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +895,7 @@ public sealed class BSPrim : BSPhysObject
754 { 895 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 896 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 897 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 898 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 899 }
759 else 900 else
760 { 901 {
@@ -762,9 +903,10 @@ public sealed class BSPrim : BSPhysObject
762 { 903 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 904 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 905 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 906 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 907
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 908 // Change collision info from a static object to a ghosty collision object
909 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 910 }
769 } 911 }
770 912
@@ -773,8 +915,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 915 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 916 private void ActivateIfPhysical(bool forceIt)
775 { 917 {
776 if (IsPhysical) 918 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 919 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 920 }
779 921
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 922 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +924,27 @@ public sealed class BSPrim : BSPhysObject
782 { 924 {
783 if (wantsCollisionEvents) 925 if (wantsCollisionEvents)
784 { 926 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 927 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
786 } 928 }
787 else 929 else
788 { 930 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 931 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
932 }
933 }
934
935 // Add me to the physical world.
936 // Object MUST NOT already be in the world.
937 // This routine exists because some assorted properties get mangled by adding to the world.
938 internal void AddObjectToPhysicalWorld()
939 {
940 if (PhysBody.HasPhysicalBody)
941 {
942 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
943 }
944 else
945 {
946 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
947 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 948 }
791 } 949 }
792 950
@@ -805,18 +963,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 963 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 964 set { _throttleUpdates = value; }
807 } 965 }
808 public override bool IsColliding {
809 get { return (CollidingStep == PhysicsScene.SimulationStep); }
810 set { _isColliding = value; }
811 }
812 public override bool CollidingGround {
813 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
814 set { _collidingGround = value; }
815 }
816 public override bool CollidingObj {
817 get { return _collidingObj; }
818 set { _collidingObj = value; }
819 }
820 public bool IsPhantom { 966 public bool IsPhantom {
821 get { 967 get {
822 // SceneObjectPart removes phantom objects from the physics scene 968 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,32 +977,23 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 977 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 978 {
833 if (_floatOnWater) 979 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 980 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 981 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 982 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 983 });
838 } 984 }
839 } 985 }
840 public override OMV.Vector3 RotationalVelocity { 986 public override OMV.Vector3 RotationalVelocity {
841 get { 987 get {
842 /*
843 OMV.Vector3 pv = OMV.Vector3.Zero;
844 // if close to zero, report zero
845 // This is copied from ODE but I'm not sure why it returns zero but doesn't
846 // zero the property in the physics engine.
847 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
848 return pv;
849 */
850
851 return _rotationalVelocity; 988 return _rotationalVelocity;
852 } 989 }
853 set { 990 set {
854 _rotationalVelocity = value; 991 _rotationalVelocity = value;
992 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 993 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 994 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 995 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 996 ForceRotationalVelocity = _rotationalVelocity;
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
860 }); 997 });
861 } 998 }
862 } 999 }
@@ -866,7 +1003,13 @@ public sealed class BSPrim : BSPhysObject
866 } 1003 }
867 set { 1004 set {
868 _rotationalVelocity = value; 1005 _rotationalVelocity = value;
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 1006 if (PhysBody.HasPhysicalBody)
1007 {
1008 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1009 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1010 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1011 ActivateIfPhysical(false);
1012 }
870 } 1013 }
871 } 1014 }
872 public override bool Kinematic { 1015 public override bool Kinematic {
@@ -890,9 +1033,10 @@ public sealed class BSPrim : BSPhysObject
890 set { 1033 set {
891 _buoyancy = value; 1034 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1035 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 1036 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 1037 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 1038 UpdatePhysicalMassProperties(_mass, true);
1039 ActivateIfPhysical(false);
896 } 1040 }
897 } 1041 }
898 1042
@@ -900,17 +1044,112 @@ public sealed class BSPrim : BSPhysObject
900 public override OMV.Vector3 PIDTarget { 1044 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1045 set { _PIDTarget = value; }
902 } 1046 }
903 public override bool PIDActive {
904 set { _usePID = value; }
905 }
906 public override float PIDTau { 1047 public override float PIDTau {
907 set { _PIDTau = value; } 1048 set { _PIDTau = value; }
908 } 1049 }
1050 public override bool PIDActive {
1051 set {
1052 if (value)
1053 {
1054 // We're taking over after this.
1055 ZeroMotion(true);
1056
1057 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1058 _PIDTau, // timeScale
1059 BSMotor.Infinite, // decay time scale
1060 BSMotor.InfiniteVector, // friction timescale
1061 1f // efficiency
1062 );
1063 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1064 _targetMotor.SetTarget(_PIDTarget);
1065 _targetMotor.SetCurrent(RawPosition);
1066 /*
1067 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1068 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1069
1070 _targetMotor.SetTarget(_PIDTarget);
1071 _targetMotor.SetCurrent(RawPosition);
1072 _targetMotor.TimeScale = _PIDTau;
1073 _targetMotor.Efficiency = 1f;
1074 */
1075
1076 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1077 {
1078 if (!IsPhysicallyActive)
1079 {
1080 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1081 return;
1082 }
1083
1084 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1085
1086 // 'movePosition' is where we'd like the prim to be at this moment.
1087 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1088
1089 // If we are very close to our target, turn off the movement motor.
1090 if (_targetMotor.ErrorIsZero())
1091 {
1092 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1093 LocalID, movePosition, RawPosition, Mass);
1094 ForcePosition = _targetMotor.TargetValue;
1095 _targetMotor.Enabled = false;
1096 }
1097 else
1098 {
1099 ForcePosition = movePosition;
1100 }
1101 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1102 });
1103 }
1104 else
1105 {
1106 // Stop any targetting
1107 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1108 }
1109 }
1110 }
909 1111
910 // Used for llSetHoverHeight and maybe vehicle height 1112 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1113 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1114 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1115 set {
1116 if (value)
1117 {
1118 // Turning the target on
1119 _hoverMotor = new BSFMotor("BSPrim.Hover",
1120 _PIDHoverTau, // timeScale
1121 BSMotor.Infinite, // decay time scale
1122 BSMotor.Infinite, // friction timescale
1123 1f // efficiency
1124 );
1125 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1126 _hoverMotor.SetCurrent(RawPosition.Z);
1127 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1128
1129 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1130 {
1131 if (!IsPhysicallyActive)
1132 return;
1133
1134 _hoverMotor.SetCurrent(RawPosition.Z);
1135 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1136 float targetHeight = _hoverMotor.Step(timeStep);
1137
1138 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1139 // Compute the amount of force to push us there.
1140 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1141 // Undo anything the object thinks it's doing at the moment
1142 moveForce = -RawVelocity.Z * Mass;
1143
1144 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1145 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1146 });
1147 }
1148 else
1149 {
1150 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1151 }
1152 }
914 } 1153 }
915 public override float PIDHoverHeight { 1154 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1155 set { _PIDHoverHeight = value; }
@@ -919,8 +1158,35 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1158 set { _PIDHoverType = value; }
920 } 1159 }
921 public override float PIDHoverTau { 1160 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1161 set { _PIDHoverTau = value; }
923 } 1162 }
1163 // Based on current position, determine what we should be hovering at now.
1164 // Must recompute often. What if we walked offa cliff>
1165 private float ComputeCurrentPIDHoverHeight()
1166 {
1167 float ret = _PIDHoverHeight;
1168 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1169
1170 switch (_PIDHoverType)
1171 {
1172 case PIDHoverType.Ground:
1173 ret = groundHeight + _PIDHoverHeight;
1174 break;
1175 case PIDHoverType.GroundAndWater:
1176 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1177 if (groundHeight > waterHeight)
1178 {
1179 ret = groundHeight + _PIDHoverHeight;
1180 }
1181 else
1182 {
1183 ret = waterHeight + _PIDHoverHeight;
1184 }
1185 break;
1186 }
1187 return ret;
1188 }
1189
924 1190
925 // For RotLookAt 1191 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1192 public override OMV.Quaternion APIDTarget { set { return; } }
@@ -928,54 +1194,73 @@ public sealed class BSPrim : BSPhysObject
928 public override float APIDStrength { set { return; } } 1194 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1195 public override float APIDDamping { set { return; } }
930 1196
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1197 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1198 // Per documentation, max force is limited.
1199 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1200
1201 // Since this force is being applied in only one step, make this a force per second.
1202 addForce /= PhysicsScene.LastTimeStep;
1203 AddForce(addForce, pushforce, false /* inTaintTime */);
934 } 1204 }
1205
935 // Applying a force just adds this to the total force on the object. 1206 // Applying a force just adds this to the total force on the object.
1207 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1208 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1209 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1210 if (IsPhysicallyActive)
939 {
940 // _force += force;
941 lock (m_accumulatedForces)
942 m_accumulatedForces.Add(new OMV.Vector3(force));
943 }
944 else
945 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
947 return;
948 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 { 1211 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero; 1212 if (force.IsFinite())
952 lock (m_accumulatedForces)
953 { 1213 {
954 // Sum the accumulated additional forces for one big force to apply once. 1214 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
955 foreach (OMV.Vector3 v in m_accumulatedForces) 1215
1216 OMV.Vector3 addForce = force;
1217 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
956 { 1218 {
957 fSum += v; 1219 // Bullet adds this central force to the total force for this tick
958 } 1220 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
959 m_accumulatedForces.Clear(); 1221 if (PhysBody.HasPhysicalBody)
1222 {
1223 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1224 ActivateIfPhysical(false);
1225 }
1226 });
960 } 1227 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); 1228 else
962 if (fSum != OMV.Vector3.Zero) 1229 {
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); 1230 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
964 }); 1231 return;
1232 }
1233 }
965 } 1234 }
966 1235
967 // An impulse force is scaled by the mass of the object. 1236 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) 1237 // for an object, doesn't matter if force is a pushforce or not
969 { 1238 if (!IsPhysicallyActive)
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 { 1239 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); 1240 if (impulse.IsFinite())
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); 1241 {
975 }); 1242 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1243 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1244
1245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1246 {
1247 // Bullet adds this impulse immediately to the velocity
1248 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1249 if (PhysBody.HasPhysicalBody)
1250 {
1251 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1252 ActivateIfPhysical(false);
1253 }
1254 });
1255 }
1256 else
1257 {
1258 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1259 return;
1260 }
1261 }
976 } 1262 }
977 1263
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1264 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1265 AddAngularForce(force, pushforce, false);
981 } 1266 }
@@ -983,42 +1268,37 @@ public sealed class BSPrim : BSPhysObject
983 { 1268 {
984 if (force.IsFinite()) 1269 if (force.IsFinite())
985 { 1270 {
986 // _force += force; 1271 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1272 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1273 {
1274 if (PhysBody.HasPhysicalBody)
1275 {
1276 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1277 ActivateIfPhysical(false);
1278 }
1279 });
989 } 1280 }
990 else 1281 else
991 { 1282 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1283 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1284 return;
994 } 1285 }
995 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
996 {
997 OMV.Vector3 fSum = OMV.Vector3.Zero;
998 lock (m_accumulatedAngularForces)
999 {
1000 // Sum the accumulated additional forces for one big force to apply once.
1001 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
1002 {
1003 fSum += v;
1004 }
1005 m_accumulatedAngularForces.Clear();
1006 }
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero)
1009 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum;
1012 }
1013 });
1014 } 1286 }
1287
1015 // A torque impulse. 1288 // A torque impulse.
1289 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1290 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1291 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1292 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1293 {
1018 OMV.Vector3 applyImpulse = impulse; 1294 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1295 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1296 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1297 if (PhysBody.HasPhysicalBody)
1298 {
1299 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1300 ActivateIfPhysical(false);
1301 }
1022 }); 1302 });
1023 } 1303 }
1024 1304
@@ -1313,11 +1593,7 @@ public sealed class BSPrim : BSPhysObject
1313 } 1593 }
1314 */ 1594 */
1315 1595
1316 if (returnMass <= 0) 1596 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1317 returnMass = 0.0001f;
1318
1319 if (returnMass > PhysicsScene.MaximumObjectMass)
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1597
1322 return returnMass; 1598 return returnMass;
1323 }// end CalculateMass 1599 }// end CalculateMass
@@ -1326,37 +1602,20 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1602 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1603 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1604 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1605 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1606 {
1331 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt.
1333 bool needToRestoreLinkset = false;
1334 bool needToRestoreVehicle = false;
1335
1336 // Create the correct physical representation for this type of object. 1607 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1608 // Updates base.PhysBody and base.PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1609 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed. 1610 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1611 {
1342 // Called if the current prim body is about to be destroyed. 1612 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1613 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1614 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1615 Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1616 VehicleController.RemoveBodyDependencies(this);
1347 }); 1617 });
1348 1618
1349 if (needToRestoreLinkset)
1350 {
1351 // If physical body dependencies were removed, restore them
1352 Linkset.RestoreBodyDependencies(this);
1353 }
1354 if (needToRestoreVehicle)
1355 {
1356 // If physical body dependencies were removed, restore them
1357 _vehicle.RestoreBodyDependencies(this);
1358 }
1359
1360 // Make sure the properties are set on the new object 1619 // Make sure the properties are set on the new object
1361 UpdatePhysicalParameters(); 1620 UpdatePhysicalParameters();
1362 return; 1621 return;
@@ -1364,95 +1623,53 @@ public sealed class BSPrim : BSPhysObject
1364 1623
1365 // The physics engine says that properties have updated. Update same and inform 1624 // The physics engine says that properties have updated. Update same and inform
1366 // the world that things have changed. 1625 // the world that things have changed.
1367 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1368 enum UpdatedProperties {
1369 Position = 1 << 0,
1370 Rotation = 1 << 1,
1371 Velocity = 1 << 2,
1372 Acceleration = 1 << 3,
1373 RotationalVel = 1 << 4
1374 }
1375
1376 const float ROTATION_TOLERANCE = 0.01f;
1377 const float VELOCITY_TOLERANCE = 0.001f;
1378 const float POSITION_TOLERANCE = 0.05f;
1379 const float ACCELERATION_TOLERANCE = 0.01f;
1380 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1381
1382 public override void UpdateProperties(EntityProperties entprop) 1626 public override void UpdateProperties(EntityProperties entprop)
1383 { 1627 {
1384 /* 1628 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1629 if (Linkset.IsRoot(this))
1386 // assign to the local variables so the normal set action does not happen
1387 // if (_position != entprop.Position)
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1389 {
1390 _position = entprop.Position;
1391 changed |= UpdatedProperties.Position;
1392 }
1393 // if (_orientation != entprop.Rotation)
1394 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1395 {
1396 _orientation = entprop.Rotation;
1397 changed |= UpdatedProperties.Rotation;
1398 }
1399 // if (_velocity != entprop.Velocity)
1400 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1401 {
1402 _velocity = entprop.Velocity;
1403 changed |= UpdatedProperties.Velocity;
1404 }
1405 // if (_acceleration != entprop.Acceleration)
1406 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1407 {
1408 _acceleration = entprop.Acceleration;
1409 changed |= UpdatedProperties.Acceleration;
1410 }
1411 // if (_rotationalVelocity != entprop.RotationalVelocity)
1412 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1413 {
1414 _rotationalVelocity = entprop.RotationalVelocity;
1415 changed |= UpdatedProperties.RotationalVel;
1416 }
1417 if (changed != 0)
1418 { 1630 {
1419 // Only update the position of single objects and linkset roots 1631 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1632 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1633 if (VehicleController.IsActive)
1421 { 1634 {
1422 base.RequestPhysicsterseUpdate(); 1635 entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1636 }
1424 }
1425 */
1426 1637
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1638 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1428 1639
1429 // Updates only for individual prims and for the root object of a linkset. 1640 // Undo any center-of-mass displacement that might have been done.
1430 if (Linkset.IsRoot(this)) 1641 if (PositionDisplacement != OMV.Vector3.Zero)
1431 { 1642 {
1432 // Assign directly to the local variables so the normal set action does not happen 1643 // Correct for any rotation around the center-of-mass
1644 // TODO!!!
1645 entprop.Position -= PositionDisplacement;
1646 }
1647
1648 // Assign directly to the local variables so the normal set actions do not happen
1433 _position = entprop.Position; 1649 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1650 _orientation = entprop.Rotation;
1435 _velocity = entprop.Velocity; 1651 _velocity = entprop.Velocity;
1436 _acceleration = entprop.Acceleration; 1652 _acceleration = entprop.Acceleration;
1437 _rotationalVelocity = entprop.RotationalVelocity; 1653 _rotationalVelocity = entprop.RotationalVelocity;
1438 1654
1655 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1656
1439 // The sanity check can change the velocity and/or position. 1657 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true)) 1658 if (PositionSanityCheck(true /* inTaintTime */ ))
1441 { 1659 {
1442 entprop.Position = _position; 1660 entprop.Position = _position;
1443 entprop.Velocity = _velocity; 1661 entprop.Velocity = _velocity;
1662 entprop.RotationalVelocity = _rotationalVelocity;
1663 entprop.Acceleration = _acceleration;
1444 } 1664 }
1445 1665
1666 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1667 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1668
1446 // remember the current and last set values 1669 // remember the current and last set values
1447 LastEntityProperties = CurrentEntityProperties; 1670 LastEntityProperties = CurrentEntityProperties;
1448 CurrentEntityProperties = entprop; 1671 CurrentEntityProperties = entprop;
1449 1672
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1455
1456 base.RequestPhysicsterseUpdate(); 1673 base.RequestPhysicsterseUpdate();
1457 } 1674 }
1458 /* 1675 /*
@@ -1466,7 +1683,7 @@ public sealed class BSPrim : BSPhysObject
1466 */ 1683 */
1467 1684
1468 // The linkset implimentation might want to know about this. 1685 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this); 1686 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
1470 } 1687 }
1471} 1688}
1472} 1689}