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