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