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