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