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.cs889
1 files changed, 446 insertions, 443 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 826261c..f5b0361 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -39,7 +39,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
39{ 39{
40 40
41 [Serializable] 41 [Serializable]
42public sealed class BSPrim : BSPhysObject 42public class BSPrim : BSPhysObject
43{ 43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
@@ -50,39 +50,38 @@ public sealed class BSPrim : BSPhysObject
50 private bool _grabbed; 50 private bool _grabbed;
51 private bool _isSelected; 51 private bool _isSelected;
52 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53
54 // _position is what the simulator thinks the positions of the prim is.
53 private OMV.Vector3 _position; 55 private OMV.Vector3 _position;
56
54 private float _mass; // the mass of this object 57 private float _mass; // the mass of this object
55 private float _density;
56 private OMV.Vector3 _force;
57 private OMV.Vector3 _velocity;
58 private OMV.Vector3 _torque;
59 private float _collisionScore;
60 private OMV.Vector3 _acceleration; 58 private OMV.Vector3 _acceleration;
61 private OMV.Quaternion _orientation; 59 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 60 private int _physicsActorType;
63 private bool _isPhysical; 61 private bool _isPhysical;
64 private bool _flying; 62 private bool _flying;
65 private float _friction;
66 private float _restitution;
67 private bool _setAlwaysRun; 63 private bool _setAlwaysRun;
68 private bool _throttleUpdates; 64 private bool _throttleUpdates;
69 private bool _isColliding;
70 private bool _collidingGround;
71 private bool _collidingObj;
72 private bool _floatOnWater; 65 private bool _floatOnWater;
73 private OMV.Vector3 _rotationalVelocity; 66 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 67 private bool _kinematic;
75 private float _buoyancy; 68 private float _buoyancy;
76 69
77 private BSDynamics _vehicle; 70 private int CrossingFailures { get; set; }
78 71
79 private OMV.Vector3 _PIDTarget; 72 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
80 private bool _usePID; 73 public BSDynamics VehicleActor;
81 private float _PIDTau; 74 public const string VehicleActorName = "BasicVehicle";
82 private bool _useHoverPID; 75
83 private float _PIDHoverHeight; 76 // Parameters for the hover actor
84 private PIDHoverType _PIDHoverType; 77 public const string HoverActorName = "HoverActor";
85 private float _PIDHoverTao; 78 // Parameters for the axis lock actor
79 public const String LockedAxisActorName = "BSPrim.LockedAxis";
80 // Parameters for the move to target actor
81 public const string MoveToTargetActorName = "MoveToTargetActor";
82 // Parameters for the setForce and setTorque actors
83 public const string SetForceActorName = "SetForceActor";
84 public const string SetTorqueActorName = "SetTorqueActor";
86 85
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 86 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 87 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -95,32 +94,28 @@ public sealed class BSPrim : BSPhysObject
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes). 94 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation; 95 _orientation = rotation;
97 _buoyancy = 0f; 96 _buoyancy = 0f;
98 _velocity = OMV.Vector3.Zero; 97 RawVelocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero; 98 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs; 99 BaseShape = pbs;
101 _isPhysical = pisPhysical; 100 _isPhysical = pisPhysical;
102 _isVolumeDetect = false; 101 _isVolumeDetect = false;
103 102
104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet. 103 // We keep a handle to the vehicle actor so we can set vehicle parameters later.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); 104 VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName);
106 _density = PhysicsScene.Params.defaultDensity; 105 PhysicalActors.Add(VehicleActorName, VehicleActor);
107 _friction = PhysicsScene.Params.defaultFriction;
108 _restitution = PhysicsScene.Params.defaultRestitution;
109
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
111 106
112 _mass = CalculateMass(); 107 _mass = CalculateMass();
113 108
114 // Cause linkset variables to be initialized (like mass) 109 // DetailLog("{0},BSPrim.constructor,call", LocalID);
115 Linkset.Refresh(this);
116
117 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time 110 // do the actual object creation at taint time
119 PhysicsScene.TaintedObject("BSPrim.create", delegate() 111 PhysScene.TaintedObject("BSPrim.create", delegate()
120 { 112 {
113 // Make sure the object is being created with some sanity.
114 ExtremeSanityCheck(true /* inTaintTime */);
115
121 CreateGeomAndObject(true); 116 CreateGeomAndObject(true);
122 117
123 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); 118 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
124 }); 119 });
125 } 120 }
126 121
@@ -130,26 +125,17 @@ public sealed class BSPrim : BSPhysObject
130 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 125 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
131 base.Destroy(); 126 base.Destroy();
132 127
133 // Undo any links between me and any other object
134 BSPhysObject parentBefore = Linkset.LinksetRoot;
135 int childrenBefore = Linkset.NumberOfChildren;
136
137 Linkset = Linkset.RemoveMeFromLinkset(this);
138
139 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
140 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
141
142 // Undo any vehicle properties 128 // Undo any vehicle properties
143 this.VehicleType = (int)Vehicle.TYPE_NONE; 129 this.VehicleType = (int)Vehicle.TYPE_NONE;
144 130
145 PhysicsScene.TaintedObject("BSPrim.destroy", delegate() 131 PhysScene.TaintedObject("BSPrim.Destroy", delegate()
146 { 132 {
147 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 133 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
148 // If there are physical body and shape, release my use of same. 134 // If there are physical body and shape, release my use of same.
149 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 135 PhysScene.Shapes.DereferenceBody(PhysBody, null);
150 PhysBody.Clear(); 136 PhysBody.Clear();
151 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 137 PhysShape.Dereference(PhysScene);
152 PhysShape.Clear(); 138 PhysShape = new BSShapeNull();
153 }); 139 });
154 } 140 }
155 141
@@ -171,17 +157,13 @@ public sealed class BSPrim : BSPhysObject
171 public override PrimitiveBaseShape Shape { 157 public override PrimitiveBaseShape Shape {
172 set { 158 set {
173 BaseShape = value; 159 BaseShape = value;
160 PrimAssetState = PrimAssetCondition.Unknown;
174 ForceBodyShapeRebuild(false); 161 ForceBodyShapeRebuild(false);
175 } 162 }
176 } 163 }
177 // Whatever the linkset wants is what I want.
178 public override BSPhysicsShapeType PreferredPhysicalShape
179 { get { return Linkset.PreferredPhysicalShape(this); } }
180
181 public override bool ForceBodyShapeRebuild(bool inTaintTime) 164 public override bool ForceBodyShapeRebuild(bool inTaintTime)
182 { 165 {
183 LastAssetBuildFailed = false; 166 PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
184 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
185 { 167 {
186 _mass = CalculateMass(); // changing the shape changes the mass 168 _mass = CalculateMass(); // changing the shape changes the mass
187 CreateGeomAndObject(true); 169 CreateGeomAndObject(true);
@@ -198,7 +180,7 @@ public sealed class BSPrim : BSPhysObject
198 if (value != _isSelected) 180 if (value != _isSelected)
199 { 181 {
200 _isSelected = value; 182 _isSelected = value;
201 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 183 PhysScene.TaintedObject("BSPrim.setSelected", delegate()
202 { 184 {
203 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 185 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
204 SetObjectDynamic(false); 186 SetObjectDynamic(false);
@@ -206,37 +188,31 @@ public sealed class BSPrim : BSPhysObject
206 } 188 }
207 } 189 }
208 } 190 }
209 public override void CrossingFailure() { return; } 191 public override bool IsSelected
192 {
193 get { return _isSelected; }
194 }
210 195
211 // link me to the specified parent 196 public override void CrossingFailure()
212 public override void link(PhysicsActor obj) { 197 {
213 BSPrim parent = obj as BSPrim; 198 CrossingFailures++;
214 if (parent != null) 199 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
215 { 200 {
216 BSPhysObject parentBefore = Linkset.LinksetRoot; 201 base.RaiseOutOfBounds(RawPosition);
217 int childrenBefore = Linkset.NumberOfChildren; 202 }
218 203 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
219 Linkset = parent.Linkset.AddMeToLinkset(this); 204 {
220 205 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
221 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
222 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
223 } 206 }
224 return; 207 return;
225 } 208 }
226 209
210 // link me to the specified parent
211 public override void link(PhysicsActor obj) {
212 }
213
227 // delink me from my linkset 214 // delink me from my linkset
228 public override void delink() { 215 public override void delink() {
229 // TODO: decide if this parent checking needs to happen at taint time
230 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
231
232 BSPhysObject parentBefore = Linkset.LinksetRoot;
233 int childrenBefore = Linkset.NumberOfChildren;
234
235 Linkset = Linkset.RemoveMeFromLinkset(this);
236
237 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
238 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
239 return;
240 } 216 }
241 217
242 // Set motion values to zero. 218 // Set motion values to zero.
@@ -245,28 +221,28 @@ public sealed class BSPrim : BSPhysObject
245 // Called at taint time! 221 // Called at taint time!
246 public override void ZeroMotion(bool inTaintTime) 222 public override void ZeroMotion(bool inTaintTime)
247 { 223 {
248 _velocity = OMV.Vector3.Zero; 224 RawVelocity = OMV.Vector3.Zero;
249 _acceleration = OMV.Vector3.Zero; 225 _acceleration = OMV.Vector3.Zero;
250 _rotationalVelocity = OMV.Vector3.Zero; 226 _rotationalVelocity = OMV.Vector3.Zero;
251 227
252 // Zero some other properties in the physics engine 228 // Zero some other properties in the physics engine
253 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 229 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
254 { 230 {
255 if (PhysBody.HasPhysicalBody) 231 if (PhysBody.HasPhysicalBody)
256 PhysicsScene.PE.ClearAllForces(PhysBody); 232 PhysScene.PE.ClearAllForces(PhysBody);
257 }); 233 });
258 } 234 }
259 public override void ZeroAngularMotion(bool inTaintTime) 235 public override void ZeroAngularMotion(bool inTaintTime)
260 { 236 {
261 _rotationalVelocity = OMV.Vector3.Zero; 237 _rotationalVelocity = OMV.Vector3.Zero;
262 // Zero some other properties in the physics engine 238 // Zero some other properties in the physics engine
263 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 239 PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
264 { 240 {
265 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 241 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
266 if (PhysBody.HasPhysicalBody) 242 if (PhysBody.HasPhysicalBody)
267 { 243 {
268 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 244 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
269 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 245 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
270 } 246 }
271 }); 247 });
272 } 248 }
@@ -274,6 +250,25 @@ public sealed class BSPrim : BSPhysObject
274 public override void LockAngularMotion(OMV.Vector3 axis) 250 public override void LockAngularMotion(OMV.Vector3 axis)
275 { 251 {
276 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 252 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
253
254 // "1" means free, "0" means locked
255 OMV.Vector3 locking = LockedAxisFree;
256 if (axis.X != 1) locking.X = 0f;
257 if (axis.Y != 1) locking.Y = 0f;
258 if (axis.Z != 1) locking.Z = 0f;
259 LockedAngularAxis = locking;
260
261 EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate()
262 {
263 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
264 });
265
266 // Update parameters so the new actor's Refresh() action is called at the right time.
267 PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
268 {
269 UpdatePhysicalParameters();
270 });
271
277 return; 272 return;
278 } 273 }
279 274
@@ -284,15 +279,8 @@ public sealed class BSPrim : BSPhysObject
284 } 279 }
285 public override OMV.Vector3 Position { 280 public override OMV.Vector3 Position {
286 get { 281 get {
287 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
288 * and does not fetch this position info for children. Thus this is commented out.
289 // child prims move around based on their parent. Need to get the latest location
290 if (!Linkset.IsRoot(this))
291 _position = Linkset.PositionGet(this);
292 */
293
294 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 282 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
295 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody); 283 // _position = ForcePosition;
296 return _position; 284 return _position;
297 } 285 }
298 set { 286 set {
@@ -306,26 +294,24 @@ public sealed class BSPrim : BSPhysObject
306 _position = value; 294 _position = value;
307 PositionSanityCheck(false); 295 PositionSanityCheck(false);
308 296
309 // A linkset might need to know if a component information changed. 297 PhysScene.TaintedObject("BSPrim.setPosition", delegate()
310 Linkset.UpdateProperties(this, false);
311
312 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
313 { 298 {
314 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 299 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
315 ForcePosition = _position; 300 ForcePosition = _position;
316 }); 301 });
317 } 302 }
318 } 303 }
304
319 public override OMV.Vector3 ForcePosition { 305 public override OMV.Vector3 ForcePosition {
320 get { 306 get {
321 _position = PhysicsScene.PE.GetPosition(PhysBody); 307 _position = PhysScene.PE.GetPosition(PhysBody);
322 return _position; 308 return _position;
323 } 309 }
324 set { 310 set {
325 _position = value; 311 _position = value;
326 if (PhysBody.HasPhysicalBody) 312 if (PhysBody.HasPhysicalBody)
327 { 313 {
328 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 314 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
329 ActivateIfPhysical(false); 315 ActivateIfPhysical(false);
330 } 316 }
331 } 317 }
@@ -338,7 +324,11 @@ public sealed class BSPrim : BSPhysObject
338 { 324 {
339 bool ret = false; 325 bool ret = false;
340 326
341 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) 327 // We don't care where non-physical items are placed
328 if (!IsPhysicallyActive)
329 return ret;
330
331 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
342 { 332 {
343 // The physical object is out of the known/simulated area. 333 // The physical object is out of the known/simulated area.
344 // Upper levels of code will handle the transition to other areas so, for 334 // Upper levels of code will handle the transition to other areas so, for
@@ -346,39 +336,74 @@ public sealed class BSPrim : BSPhysObject
346 return ret; 336 return ret;
347 } 337 }
348 338
349 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 339 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
350 OMV.Vector3 upForce = OMV.Vector3.Zero; 340 OMV.Vector3 upForce = OMV.Vector3.Zero;
351 if (RawPosition.Z < terrainHeight) 341 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
342 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
352 { 343 {
353 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 344 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
354 float targetHeight = terrainHeight + (Size.Z / 2f); 345 float targetHeight = terrainHeight + (Size.Z / 2f);
355 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 346 // If the object is below ground it just has to be moved up because pushing will
356 upForce.Z = (terrainHeight - RawPosition.Z) * 1f; 347 // not get it through the terrain
348 _position.Z = targetHeight;
349 if (inTaintTime)
350 {
351 ForcePosition = _position;
352 }
353 // If we are throwing the object around, zero its other forces
354 ZeroMotion(inTaintTime);
357 ret = true; 355 ret = true;
358 } 356 }
359 357
360 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 358 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
361 { 359 {
362 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 360 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position);
363 // TODO: a floating motor so object will bob in the water 361 // TODO: a floating motor so object will bob in the water
364 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) 362 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
365 { 363 {
366 // 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.
367 upForce.Z = (waterHeight - RawPosition.Z) * 1f; 365 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
366
367 // Apply upforce and overcome gravity.
368 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
369 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
370 AddForce(correctionForce, false, inTaintTime);
368 ret = true; 371 ret = true;
369 } 372 }
370 } 373 }
371 374
372 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 375 return ret;
373 // TODO: This should be intergrated with a geneal physics action mechanism. 376 }
374 // TODO: This should be moderated with PID'ness. 377
375 if (ret) 378 // Occasionally things will fly off and really get lost.
379 // Find the wanderers and bring them back.
380 // Return 'true' if some parameter need some sanity.
381 private bool ExtremeSanityCheck(bool inTaintTime)
382 {
383 bool ret = false;
384
385 uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
386 // There have been instances of objects getting thrown way out of bounds and crashing
387 // the border crossing code.
388 if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere
389 || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere
390 || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere)
391 {
392 _position = new OMV.Vector3(10, 10, 50);
393 ZeroMotion(inTaintTime);
394 ret = true;
395 }
396 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
376 { 397 {
377 // Apply upforce and overcome gravity. 398 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
378 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; 399 ret = true;
379 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
380 AddForce(correctionForce, false, inTaintTime);
381 } 400 }
401 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
402 {
403 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
404 ret = true;
405 }
406
382 return ret; 407 return ret;
383 } 408 }
384 409
@@ -387,72 +412,69 @@ public sealed class BSPrim : BSPhysObject
387 // If the simulator cares about the mass of the linkset, it will sum it itself. 412 // If the simulator cares about the mass of the linkset, it will sum it itself.
388 public override float Mass 413 public override float Mass
389 { 414 {
390 get 415 get { return _mass; }
391 { 416 }
392 return _mass; 417 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
393 } 418 public virtual float TotalMass
419 {
420 get { return _mass; }
394 } 421 }
395
396 // used when we only want this prim's mass and not the linkset thing 422 // used when we only want this prim's mass and not the linkset thing
397 public override float RawMass { 423 public override float RawMass {
398 get { return _mass; } 424 get { return _mass; }
399 } 425 }
400 // Set the physical mass to the passed mass. 426 // Set the physical mass to the passed mass.
401 // Note that this does not change _mass! 427 // Note that this does not change _mass!
402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 428 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
403 { 429 {
404 if (PhysBody.HasPhysicalBody) 430 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
405 { 431 {
406 if (IsStatic) 432 if (IsStatic)
407 { 433 {
408 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); 434 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
409 Inertia = OMV.Vector3.Zero; 435 Inertia = OMV.Vector3.Zero;
410 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); 436 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
411 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 437 PhysScene.PE.UpdateInertiaTensor(PhysBody);
412 } 438 }
413 else 439 else
414 { 440 {
415 OMV.Vector3 grav = ComputeGravity();
416
417 if (inWorld) 441 if (inWorld)
418 { 442 {
419 // Changing interesting properties doesn't change proxy and collision cache 443 // Changing interesting properties doesn't change proxy and collision cache
420 // information. The Bullet solution is to re-add the object to the world 444 // information. The Bullet solution is to re-add the object to the world
421 // after parameters are changed. 445 // after parameters are changed.
422 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 446 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
423 } 447 }
424 448
425 // The computation of mass props requires gravity to be set on the object. 449 // The computation of mass props requires gravity to be set on the object.
426 PhysicsScene.PE.SetGravity(PhysBody, grav); 450 Gravity = ComputeGravity(Buoyancy);
451 PhysScene.PE.SetGravity(PhysBody, Gravity);
427 452
428 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 453 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
429 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 454 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
430 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 455 PhysScene.PE.UpdateInertiaTensor(PhysBody);
431 456
432 // center of mass is at the zero of the object 457 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
433 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation); 458 LocalID, physMass, Inertia, Gravity, inWorld);
434 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
435 459
436 if (inWorld) 460 if (inWorld)
437 { 461 {
438 AddObjectToPhysicalWorld(); 462 AddObjectToPhysicalWorld();
439 } 463 }
440
441 // Must set gravity after it has been added to the world because, for unknown reasons,
442 // adding the object resets the object's gravity to world gravity
443 PhysicsScene.PE.SetGravity(PhysBody, grav);
444
445 } 464 }
446 } 465 }
447 } 466 }
448 467
449 // Return what gravity should be set to this very moment 468 // Return what gravity should be set to this very moment
450 private OMV.Vector3 ComputeGravity() 469 public OMV.Vector3 ComputeGravity(float buoyancy)
451 { 470 {
452 OMV.Vector3 ret = PhysicsScene.DefaultGravity; 471 OMV.Vector3 ret = PhysScene.DefaultGravity;
453 472
454 if (!IsStatic) 473 if (!IsStatic)
455 ret *= (1f - Buoyancy); 474 {
475 ret *= (1f - buoyancy);
476 ret *= GravModifier;
477 }
456 478
457 return ret; 479 return ret;
458 } 480 }
@@ -460,93 +482,70 @@ public sealed class BSPrim : BSPhysObject
460 // Is this used? 482 // Is this used?
461 public override OMV.Vector3 CenterOfMass 483 public override OMV.Vector3 CenterOfMass
462 { 484 {
463 get { return Linkset.CenterOfMass; } 485 get { return RawPosition; }
464 } 486 }
465 487
466 // Is this used? 488 // Is this used?
467 public override OMV.Vector3 GeometricCenter 489 public override OMV.Vector3 GeometricCenter
468 { 490 {
469 get { return Linkset.GeometricCenter; } 491 get { return RawPosition; }
470 } 492 }
471 493
472 public override OMV.Vector3 Force { 494 public override OMV.Vector3 Force {
473 get { return _force; } 495 get { return RawForce; }
474 set { 496 set {
475 _force = value; 497 RawForce = value;
476 if (_force != OMV.Vector3.Zero) 498 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
477 { 499 {
478 // If the force is non-zero, it must be reapplied each tick because 500 return new BSActorSetForce(PhysScene, this, SetForceActorName);
479 // Bullet clears the forces applied last frame. 501 });
480 RegisterPreStepAction("BSPrim.setForce", LocalID,
481 delegate(float timeStep)
482 {
483 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
484 if (PhysBody.HasPhysicalBody)
485 {
486 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
487 ActivateIfPhysical(false);
488 }
489 }
490 );
491 }
492 else
493 {
494 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
495 }
496 } 502 }
497 } 503 }
498 504
499 public override int VehicleType { 505 public override int VehicleType {
500 get { 506 get {
501 return (int)_vehicle.Type; // if we are a vehicle, return that type 507 return (int)VehicleActor.Type;
502 } 508 }
503 set { 509 set {
504 Vehicle type = (Vehicle)value; 510 Vehicle type = (Vehicle)value;
505 511
506 PhysicsScene.TaintedObject("setVehicleType", delegate() 512 PhysScene.TaintedObject("setVehicleType", delegate()
507 { 513 {
508 // Done at taint time so we're sure the physics engine is not using the variables 514 ZeroMotion(true /* inTaintTime */);
509 // Vehicle code changes the parameters for this vehicle type. 515 VehicleActor.ProcessTypeChange(type);
510 _vehicle.ProcessTypeChange(type);
511 ActivateIfPhysical(false); 516 ActivateIfPhysical(false);
512
513 // If an active vehicle, register the vehicle code to be called before each step
514 if (_vehicle.Type == Vehicle.TYPE_NONE)
515 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
516 else
517 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
518 }); 517 });
519 } 518 }
520 } 519 }
521 public override void VehicleFloatParam(int param, float value) 520 public override void VehicleFloatParam(int param, float value)
522 { 521 {
523 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 522 PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
524 { 523 {
525 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 524 VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
526 ActivateIfPhysical(false); 525 ActivateIfPhysical(false);
527 }); 526 });
528 } 527 }
529 public override void VehicleVectorParam(int param, OMV.Vector3 value) 528 public override void VehicleVectorParam(int param, OMV.Vector3 value)
530 { 529 {
531 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 530 PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
532 { 531 {
533 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 532 VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
534 ActivateIfPhysical(false); 533 ActivateIfPhysical(false);
535 }); 534 });
536 } 535 }
537 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 536 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
538 { 537 {
539 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 538 PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
540 { 539 {
541 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 540 VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
542 ActivateIfPhysical(false); 541 ActivateIfPhysical(false);
543 }); 542 });
544 } 543 }
545 public override void VehicleFlags(int param, bool remove) 544 public override void VehicleFlags(int param, bool remove)
546 { 545 {
547 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 546 PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate()
548 { 547 {
549 _vehicle.ProcessVehicleFlags(param, remove); 548 VehicleActor.ProcessVehicleFlags(param, remove);
550 }); 549 });
551 } 550 }
552 551
@@ -556,7 +555,7 @@ public sealed class BSPrim : BSPhysObject
556 if (_isVolumeDetect != newValue) 555 if (_isVolumeDetect != newValue)
557 { 556 {
558 _isVolumeDetect = newValue; 557 _isVolumeDetect = newValue;
559 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 558 PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
560 { 559 {
561 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); 560 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
562 SetObjectDynamic(true); 561 SetObjectDynamic(true);
@@ -564,56 +563,110 @@ public sealed class BSPrim : BSPhysObject
564 } 563 }
565 return; 564 return;
566 } 565 }
566 public override void SetMaterial(int material)
567 {
568 base.SetMaterial(material);
569 PhysScene.TaintedObject("BSPrim.SetMaterial", delegate()
570 {
571 UpdatePhysicalParameters();
572 });
573 }
574 public override float Friction
575 {
576 get { return base.Friction; }
577 set
578 {
579 if (base.Friction != value)
580 {
581 base.Friction = value;
582 PhysScene.TaintedObject("BSPrim.setFriction", delegate()
583 {
584 UpdatePhysicalParameters();
585 });
586 }
587 }
588 }
589 public override float Restitution
590 {
591 get { return base.Restitution; }
592 set
593 {
594 if (base.Restitution != value)
595 {
596 base.Restitution = value;
597 PhysScene.TaintedObject("BSPrim.setRestitution", delegate()
598 {
599 UpdatePhysicalParameters();
600 });
601 }
602 }
603 }
604 // The simulator/viewer keep density as 100kg/m3.
605 // Remember to use BSParam.DensityScaleFactor to create the physical density.
606 public override float Density
607 {
608 get { return base.Density; }
609 set
610 {
611 if (base.Density != value)
612 {
613 base.Density = value;
614 PhysScene.TaintedObject("BSPrim.setDensity", delegate()
615 {
616 UpdatePhysicalParameters();
617 });
618 }
619 }
620 }
621 public override float GravModifier
622 {
623 get { return base.GravModifier; }
624 set
625 {
626 if (base.GravModifier != value)
627 {
628 base.GravModifier = value;
629 PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate()
630 {
631 UpdatePhysicalParameters();
632 });
633 }
634 }
635 }
567 public override OMV.Vector3 Velocity { 636 public override OMV.Vector3 Velocity {
568 get { return _velocity; } 637 get { return RawVelocity; }
569 set { 638 set {
570 _velocity = value; 639 RawVelocity = value;
571 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 640 PhysScene.TaintedObject("BSPrim.setVelocity", delegate()
572 { 641 {
573 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 642 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
574 ForceVelocity = _velocity; 643 ForceVelocity = RawVelocity;
575 }); 644 });
576 } 645 }
577 } 646 }
578 public override OMV.Vector3 ForceVelocity { 647 public override OMV.Vector3 ForceVelocity {
579 get { return _velocity; } 648 get { return RawVelocity; }
580 set { 649 set {
581 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); 650 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
582 651
583 _velocity = value; 652 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
584 if (PhysBody.HasPhysicalBody) 653 if (PhysBody.HasPhysicalBody)
585 { 654 {
586 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 655 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
656 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
587 ActivateIfPhysical(false); 657 ActivateIfPhysical(false);
588 } 658 }
589 } 659 }
590 } 660 }
591 public override OMV.Vector3 Torque { 661 public override OMV.Vector3 Torque {
592 get { return _torque; } 662 get { return RawTorque; }
593 set { 663 set {
594 _torque = value; 664 RawTorque = value;
595 if (_torque != OMV.Vector3.Zero) 665 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
596 { 666 {
597 // If the torque is non-zero, it must be reapplied each tick because 667 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
598 // Bullet clears the forces applied last frame. 668 });
599 RegisterPreStepAction("BSPrim.setTorque", LocalID, 669 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
600 delegate(float timeStep)
601 {
602 if (PhysBody.HasPhysicalBody)
603 AddAngularForce(_torque, false, true);
604 }
605 );
606 }
607 else
608 {
609 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
610 }
611 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
612 }
613 }
614 public override float CollisionScore {
615 get { return _collisionScore; }
616 set { _collisionScore = value;
617 } 670 }
618 } 671 }
619 public override OMV.Vector3 Acceleration { 672 public override OMV.Vector3 Acceleration {
@@ -627,14 +680,6 @@ public sealed class BSPrim : BSPhysObject
627 } 680 }
628 public override OMV.Quaternion Orientation { 681 public override OMV.Quaternion Orientation {
629 get { 682 get {
630 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
631 * and does not fetch this position info for children. Thus this is commented out.
632 // Children move around because tied to parent. Get a fresh value.
633 if (!Linkset.IsRoot(this))
634 {
635 _orientation = Linkset.OrientationGet(this);
636 }
637 */
638 return _orientation; 683 return _orientation;
639 } 684 }
640 set { 685 set {
@@ -642,17 +687,9 @@ public sealed class BSPrim : BSPhysObject
642 return; 687 return;
643 _orientation = value; 688 _orientation = value;
644 689
645 // A linkset might need to know if a component information changed. 690 PhysScene.TaintedObject("BSPrim.setOrientation", delegate()
646 Linkset.UpdateProperties(this, false);
647
648 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
649 { 691 {
650 if (PhysBody.HasPhysicalBody) 692 ForceOrientation = _orientation;
651 {
652 // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody);
653 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
654 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
655 }
656 }); 693 });
657 } 694 }
658 } 695 }
@@ -661,13 +698,14 @@ public sealed class BSPrim : BSPhysObject
661 { 698 {
662 get 699 get
663 { 700 {
664 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 701 _orientation = PhysScene.PE.GetOrientation(PhysBody);
665 return _orientation; 702 return _orientation;
666 } 703 }
667 set 704 set
668 { 705 {
669 _orientation = value; 706 _orientation = value;
670 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 707 if (PhysBody.HasPhysicalBody)
708 PhysScene.PE.SetTranslation(PhysBody, _position, _orientation);
671 } 709 }
672 } 710 }
673 public override int PhysicsActorType { 711 public override int PhysicsActorType {
@@ -680,12 +718,13 @@ public sealed class BSPrim : BSPhysObject
680 if (_isPhysical != value) 718 if (_isPhysical != value)
681 { 719 {
682 _isPhysical = value; 720 _isPhysical = value;
683 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 721 PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate()
684 { 722 {
685 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 723 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
686 SetObjectDynamic(true); 724 SetObjectDynamic(true);
687 // whether phys-to-static or static-to-phys, the object is not moving. 725 // whether phys-to-static or static-to-phys, the object is not moving.
688 ZeroMotion(true); 726 ZeroMotion(true);
727
689 }); 728 });
690 } 729 }
691 } 730 }
@@ -703,6 +742,12 @@ public sealed class BSPrim : BSPhysObject
703 get { return !IsPhantom && !_isVolumeDetect; } 742 get { return !IsPhantom && !_isVolumeDetect; }
704 } 743 }
705 744
745 // The object is moving and is actively being dynamic in the physical world
746 public override bool IsPhysicallyActive
747 {
748 get { return !_isSelected && IsPhysical; }
749 }
750
706 // Make gravity work if the object is physical and not selected 751 // Make gravity work if the object is physical and not selected
707 // Called at taint-time!! 752 // Called at taint-time!!
708 private void SetObjectDynamic(bool forceRebuild) 753 private void SetObjectDynamic(bool forceRebuild)
@@ -717,19 +762,24 @@ public sealed class BSPrim : BSPhysObject
717 // isSolid: other objects bounce off of this object 762 // isSolid: other objects bounce off of this object
718 // isVolumeDetect: other objects pass through but can generate collisions 763 // isVolumeDetect: other objects pass through but can generate collisions
719 // collisionEvents: whether this object returns collision events 764 // collisionEvents: whether this object returns collision events
720 private void UpdatePhysicalParameters() 765 public virtual void UpdatePhysicalParameters()
721 { 766 {
722 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); 767 if (!PhysBody.HasPhysicalBody)
768 {
769 // This would only happen if updates are called for during initialization when the body is not set up yet.
770 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
771 return;
772 }
723 773
724 // Mangling all the physical properties requires the object not be in the physical world. 774 // Mangling all the physical properties requires the object not be in the physical world.
725 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 775 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
726 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 776 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
727 777
728 // Set up the object physicalness (does gravity and collisions move this object) 778 // Set up the object physicalness (does gravity and collisions move this object)
729 MakeDynamic(IsStatic); 779 MakeDynamic(IsStatic);
730 780
731 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 781 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
732 _vehicle.Refresh(); 782 PhysicalActors.Refresh();
733 783
734 // Arrange for collision events if the simulator wants them 784 // Arrange for collision events if the simulator wants them
735 EnableCollisions(SubscribedEvents()); 785 EnableCollisions(SubscribedEvents());
@@ -740,16 +790,11 @@ public sealed class BSPrim : BSPhysObject
740 AddObjectToPhysicalWorld(); 790 AddObjectToPhysicalWorld();
741 791
742 // Rebuild its shape 792 // Rebuild its shape
743 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 793 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
744
745 // Recompute any linkset parameters.
746 // When going from non-physical to physical, this re-enables the constraints that
747 // had been automatically disabled when the mass was set to zero.
748 // For compound based linksets, this enables and disables interactions of the children.
749 Linkset.Refresh(this);
750 794
751 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 795 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
752 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 796 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
797 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
753 } 798 }
754 799
755 // "Making dynamic" means changing to and from static. 800 // "Making dynamic" means changing to and from static.
@@ -757,59 +802,55 @@ public sealed class BSPrim : BSPhysObject
757 // When dynamic, the object can fall and be pushed by others. 802 // When dynamic, the object can fall and be pushed by others.
758 // This is independent of its 'solidness' which controls what passes through 803 // This is independent of its 'solidness' which controls what passes through
759 // this object and what interacts with it. 804 // this object and what interacts with it.
760 private void MakeDynamic(bool makeStatic) 805 protected virtual void MakeDynamic(bool makeStatic)
761 { 806 {
762 if (makeStatic) 807 if (makeStatic)
763 { 808 {
764 // Become a Bullet 'static' object type 809 // Become a Bullet 'static' object type
765 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 810 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
766 // Stop all movement 811 // Stop all movement
767 ZeroMotion(true); 812 ZeroMotion(true);
768 813
769 // Set various physical properties so other object interact properly 814 // Set various physical properties so other object interact properly
770 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); 815 PhysScene.PE.SetFriction(PhysBody, Friction);
771 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); 816 PhysScene.PE.SetRestitution(PhysBody, Restitution);
772 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); 817 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
773 818
774 // Mass is zero which disables a bunch of physics stuff in Bullet 819 // Mass is zero which disables a bunch of physics stuff in Bullet
775 UpdatePhysicalMassProperties(0f, false); 820 UpdatePhysicalMassProperties(0f, false);
776 // Set collision detection parameters 821 // Set collision detection parameters
777 if (BSParam.CcdMotionThreshold > 0f) 822 if (BSParam.CcdMotionThreshold > 0f)
778 { 823 {
779 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 824 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
780 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 825 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
781 } 826 }
782 827
783 // The activation state is 'disabled' so Bullet will not try to act on it. 828 // The activation state is 'disabled' so Bullet will not try to act on it.
784 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); 829 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
785 // Start it out sleeping and physical actions could wake it up. 830 // Start it out sleeping and physical actions could wake it up.
786 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); 831 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
787 832
788 // This collides like a static object 833 // This collides like a static object
789 PhysBody.collisionType = CollisionType.Static; 834 PhysBody.collisionType = CollisionType.Static;
790
791 // There can be special things needed for implementing linksets
792 Linkset.MakeStatic(this);
793 } 835 }
794 else 836 else
795 { 837 {
796 // Not a Bullet static object 838 // Not a Bullet static object
797 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 839 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
798 840
799 // Set various physical properties so other object interact properly 841 // Set various physical properties so other object interact properly
800 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); 842 PhysScene.PE.SetFriction(PhysBody, Friction);
801 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); 843 PhysScene.PE.SetRestitution(PhysBody, Restitution);
802 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); 844 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
803 845
804 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 846 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
805 // Since this can be called multiple times, only zero forces when becoming physical 847 // Since this can be called multiple times, only zero forces when becoming physical
806 // PhysicsScene.PE.ClearAllForces(BSBody); 848 // PhysicsScene.PE.ClearAllForces(BSBody);
807 849
808 // For good measure, make sure the transform is set through to the motion state 850 // For good measure, make sure the transform is set through to the motion state
809 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 851 ForcePosition = _position;
810 852 ForceVelocity = RawVelocity;
811 // Center of mass is at the center of the object 853 ForceRotationalVelocity = _rotationalVelocity;
812 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
813 854
814 // A dynamic object has mass 855 // A dynamic object has mass
815 UpdatePhysicalMassProperties(RawMass, false); 856 UpdatePhysicalMassProperties(RawMass, false);
@@ -817,25 +858,22 @@ public sealed class BSPrim : BSPhysObject
817 // Set collision detection parameters 858 // Set collision detection parameters
818 if (BSParam.CcdMotionThreshold > 0f) 859 if (BSParam.CcdMotionThreshold > 0f)
819 { 860 {
820 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 861 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
821 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 862 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
822 } 863 }
823 864
824 // Various values for simulation limits 865 // Various values for simulation limits
825 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); 866 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
826 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); 867 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
827 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); 868 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
828 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 869 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
829 870
830 // This collides like an object. 871 // This collides like an object.
831 PhysBody.collisionType = CollisionType.Dynamic; 872 PhysBody.collisionType = CollisionType.Dynamic;
832 873
833 // Force activation of the object so Bullet will act on it. 874 // Force activation of the object so Bullet will act on it.
834 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 875 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
835 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 876 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
836
837 // There might be special things needed for implementing linksets.
838 Linkset.MakeDynamic(this);
839 } 877 }
840 } 878 }
841 879
@@ -845,7 +883,7 @@ public sealed class BSPrim : BSPhysObject
845 // the functions after this one set up the state of a possibly newly created collision body. 883 // the functions after this one set up the state of a possibly newly created collision body.
846 private void MakeSolid(bool makeSolid) 884 private void MakeSolid(bool makeSolid)
847 { 885 {
848 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); 886 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
849 if (makeSolid) 887 if (makeSolid)
850 { 888 {
851 // Verify the previous code created the correct shape for this type of thing. 889 // Verify the previous code created the correct shape for this type of thing.
@@ -853,7 +891,7 @@ public sealed class BSPrim : BSPhysObject
853 { 891 {
854 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 892 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
855 } 893 }
856 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 894 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
857 } 895 }
858 else 896 else
859 { 897 {
@@ -861,32 +899,23 @@ public sealed class BSPrim : BSPhysObject
861 { 899 {
862 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 900 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
863 } 901 }
864 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 902 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
865 903
866 // Change collision info from a static object to a ghosty collision object 904 // Change collision info from a static object to a ghosty collision object
867 PhysBody.collisionType = CollisionType.VolumeDetect; 905 PhysBody.collisionType = CollisionType.VolumeDetect;
868 } 906 }
869 } 907 }
870 908
871 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
872 // they need waking up when parameters are changed.
873 // Called in taint-time!!
874 private void ActivateIfPhysical(bool forceIt)
875 {
876 if (IsPhysical && PhysBody.HasPhysicalBody)
877 PhysicsScene.PE.Activate(PhysBody, forceIt);
878 }
879
880 // Turn on or off the flag controlling whether collision events are returned to the simulator. 909 // Turn on or off the flag controlling whether collision events are returned to the simulator.
881 private void EnableCollisions(bool wantsCollisionEvents) 910 private void EnableCollisions(bool wantsCollisionEvents)
882 { 911 {
883 if (wantsCollisionEvents) 912 if (wantsCollisionEvents)
884 { 913 {
885 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 914 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
886 } 915 }
887 else 916 else
888 { 917 {
889 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 918 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
890 } 919 }
891 } 920 }
892 921
@@ -897,12 +926,12 @@ public sealed class BSPrim : BSPhysObject
897 { 926 {
898 if (PhysBody.HasPhysicalBody) 927 if (PhysBody.HasPhysicalBody)
899 { 928 {
900 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 929 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
901 } 930 }
902 else 931 else
903 { 932 {
904 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); 933 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
905 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); 934 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
906 } 935 }
907 } 936 }
908 937
@@ -932,12 +961,12 @@ public sealed class BSPrim : BSPhysObject
932 public override bool FloatOnWater { 961 public override bool FloatOnWater {
933 set { 962 set {
934 _floatOnWater = value; 963 _floatOnWater = value;
935 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 964 PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
936 { 965 {
937 if (_floatOnWater) 966 if (_floatOnWater)
938 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 967 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
939 else 968 else
940 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 969 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
941 }); 970 });
942 } 971 }
943 } 972 }
@@ -947,10 +976,10 @@ public sealed class BSPrim : BSPhysObject
947 } 976 }
948 set { 977 set {
949 _rotationalVelocity = value; 978 _rotationalVelocity = value;
979 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
950 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 980 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
951 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 981 PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
952 { 982 {
953 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
954 ForceRotationalVelocity = _rotationalVelocity; 983 ForceRotationalVelocity = _rotationalVelocity;
955 }); 984 });
956 } 985 }
@@ -960,10 +989,12 @@ public sealed class BSPrim : BSPhysObject
960 return _rotationalVelocity; 989 return _rotationalVelocity;
961 } 990 }
962 set { 991 set {
963 _rotationalVelocity = value; 992 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
964 if (PhysBody.HasPhysicalBody) 993 if (PhysBody.HasPhysicalBody)
965 { 994 {
966 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 995 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
996 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
997 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
967 ActivateIfPhysical(false); 998 ActivateIfPhysical(false);
968 } 999 }
969 } 1000 }
@@ -978,7 +1009,7 @@ public sealed class BSPrim : BSPhysObject
978 get { return _buoyancy; } 1009 get { return _buoyancy; }
979 set { 1010 set {
980 _buoyancy = value; 1011 _buoyancy = value;
981 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 1012 PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate()
982 { 1013 {
983 ForceBuoyancy = _buoyancy; 1014 ForceBuoyancy = _buoyancy;
984 }); 1015 });
@@ -990,96 +1021,113 @@ public sealed class BSPrim : BSPhysObject
990 _buoyancy = value; 1021 _buoyancy = value;
991 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 1022 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
992 // Force the recalculation of the various inertia,etc variables in the object 1023 // Force the recalculation of the various inertia,etc variables in the object
993 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass); 1024 UpdatePhysicalMassProperties(RawMass, true);
994 UpdatePhysicalMassProperties(_mass, true); 1025 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
995 ActivateIfPhysical(false); 1026 ActivateIfPhysical(false);
996 } 1027 }
997 } 1028 }
998 1029
999 // Used for MoveTo
1000 public override OMV.Vector3 PIDTarget {
1001 set { _PIDTarget = value; }
1002 }
1003 public override float PIDTau {
1004 set { _PIDTau = value; }
1005 }
1006 public override bool PIDActive { 1030 public override bool PIDActive {
1007 set { _usePID = value; } 1031 set {
1032 base.MoveToTargetActive = value;
1033 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1034 {
1035 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1036 });
1037 }
1008 } 1038 }
1009 1039
1010 // Used for llSetHoverHeight and maybe vehicle height 1040 // Used for llSetHoverHeight and maybe vehicle height
1011 // Hover Height will override MoveTo target's Z 1041 // Hover Height will override MoveTo target's Z
1012 public override bool PIDHoverActive { 1042 public override bool PIDHoverActive {
1013 set { _useHoverPID = value; } 1043 set {
1014 } 1044 base.HoverActive = value;
1015 public override float PIDHoverHeight { 1045 EnableActor(HoverActive, HoverActorName, delegate()
1016 set { _PIDHoverHeight = value; } 1046 {
1017 } 1047 return new BSActorHover(PhysScene, this, HoverActorName);
1018 public override PIDHoverType PIDHoverType { 1048 });
1019 set { _PIDHoverType = value; } 1049 }
1020 }
1021 public override float PIDHoverTau {
1022 set { _PIDHoverTao = value; }
1023 } 1050 }
1024 1051
1025 // For RotLookAt
1026 public override OMV.Quaternion APIDTarget { set { return; } }
1027 public override bool APIDActive { set { return; } }
1028 public override float APIDStrength { set { return; } }
1029 public override float APIDDamping { set { return; } }
1030
1031 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1052 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1053 // Per documentation, max force is limited.
1054 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1055
1032 // Since this force is being applied in only one step, make this a force per second. 1056 // Since this force is being applied in only one step, make this a force per second.
1033 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 1057 addForce /= PhysScene.LastTimeStep;
1034 AddForce(addForce, pushforce, false); 1058 AddForce(addForce, pushforce, false /* inTaintTime */);
1035 } 1059 }
1060
1036 // Applying a force just adds this to the total force on the object. 1061 // Applying a force just adds this to the total force on the object.
1037 // This added force will only last the next simulation tick. 1062 // This added force will only last the next simulation tick.
1038 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1063 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1039 // for an object, doesn't matter if force is a pushforce or not 1064 // for an object, doesn't matter if force is a pushforce or not
1040 if (force.IsFinite()) 1065 if (IsPhysicallyActive)
1041 { 1066 {
1042 float magnitude = force.Length(); 1067 if (force.IsFinite())
1043 if (magnitude > BSParam.MaxAddForceMagnitude)
1044 { 1068 {
1045 // Force has a limit 1069 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1046 force = force / magnitude * BSParam.MaxAddForceMagnitude;
1047 }
1048
1049 OMV.Vector3 addForce = force;
1050 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1051 1070
1052 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1071 OMV.Vector3 addForce = force;
1053 { 1072 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1054 // Bullet adds this central force to the total force for this tick
1055 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1056 if (PhysBody.HasPhysicalBody)
1057 { 1073 {
1058 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 1074 // Bullet adds this central force to the total force for this tick
1059 ActivateIfPhysical(false); 1075 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1060 } 1076 if (PhysBody.HasPhysicalBody)
1061 }); 1077 {
1078 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1079 ActivateIfPhysical(false);
1080 }
1081 });
1082 }
1083 else
1084 {
1085 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1086 return;
1087 }
1062 } 1088 }
1063 else 1089 }
1090
1091 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1092 // for an object, doesn't matter if force is a pushforce or not
1093 if (!IsPhysicallyActive)
1064 { 1094 {
1065 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1095 if (impulse.IsFinite())
1066 return; 1096 {
1097 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1098 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1099
1100 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate()
1101 {
1102 // Bullet adds this impulse immediately to the velocity
1103 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1104 if (PhysBody.HasPhysicalBody)
1105 {
1106 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1107 ActivateIfPhysical(false);
1108 }
1109 });
1110 }
1111 else
1112 {
1113 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1114 return;
1115 }
1067 } 1116 }
1068 } 1117 }
1069 1118
1070 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1119 // BSPhysObject.AddAngularForce()
1071 AddAngularForce(force, pushforce, false); 1120 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1072 }
1073 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1074 { 1121 {
1075 if (force.IsFinite()) 1122 if (force.IsFinite())
1076 { 1123 {
1077 OMV.Vector3 angForce = force; 1124 OMV.Vector3 angForce = force;
1078 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() 1125 PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1079 { 1126 {
1080 if (PhysBody.HasPhysicalBody) 1127 if (PhysBody.HasPhysicalBody)
1081 { 1128 {
1082 PhysicsScene.PE.ApplyTorque(PhysBody, angForce); 1129 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1130 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1083 ActivateIfPhysical(false); 1131 ActivateIfPhysical(false);
1084 } 1132 }
1085 }); 1133 });
@@ -1098,11 +1146,11 @@ public sealed class BSPrim : BSPhysObject
1098 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1146 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1099 { 1147 {
1100 OMV.Vector3 applyImpulse = impulse; 1148 OMV.Vector3 applyImpulse = impulse;
1101 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1149 PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1102 { 1150 {
1103 if (PhysBody.HasPhysicalBody) 1151 if (PhysBody.HasPhysicalBody)
1104 { 1152 {
1105 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); 1153 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1106 ActivateIfPhysical(false); 1154 ActivateIfPhysical(false);
1107 } 1155 }
1108 }); 1156 });
@@ -1387,19 +1435,10 @@ public sealed class BSPrim : BSPhysObject
1387 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; 1435 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1388 volume *= (profileEnd - profileBegin); 1436 volume *= (profileEnd - profileBegin);
1389 1437
1390 returnMass = _density * volume; 1438 returnMass = Density * BSParam.DensityScaleFactor * volume;
1391
1392 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1393 if (IsRootOfLinkset)
1394 {
1395 foreach (BSPrim prim in _childrenPrims)
1396 {
1397 returnMass += prim.CalculateMass();
1398 }
1399 }
1400 */
1401 1439
1402 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); 1440 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1441 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1403 1442
1404 return returnMass; 1443 return returnMass;
1405 }// end CalculateMass 1444 }// end CalculateMass
@@ -1410,104 +1449,68 @@ public sealed class BSPrim : BSPhysObject
1410 // Called at taint-time!!! 1449 // Called at taint-time!!!
1411 public void CreateGeomAndObject(bool forceRebuild) 1450 public void CreateGeomAndObject(bool forceRebuild)
1412 { 1451 {
1413 // If this prim is part of a linkset, we must remove and restore the physical
1414 // links if the body is rebuilt.
1415 bool needToRestoreLinkset = false;
1416 bool needToRestoreVehicle = false;
1417
1418 // Create the correct physical representation for this type of object. 1452 // Create the correct physical representation for this type of object.
1419 // Updates PhysBody and PhysShape with the new information. 1453 // Updates base.PhysBody and base.PhysShape with the new information.
1420 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1454 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1421 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1455 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1422 { 1456 {
1423 // Called if the current prim body is about to be destroyed. 1457 // Called if the current prim body is about to be destroyed.
1424 // Remove all the physical dependencies on the old body. 1458 // Remove all the physical dependencies on the old body.
1425 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1459 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1426 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1460 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1427 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1461 RemoveDependencies();
1428 }); 1462 });
1429 1463
1430 if (needToRestoreLinkset)
1431 {
1432 // If physical body dependencies were removed, restore them
1433 Linkset.RestoreBodyDependencies(this);
1434 }
1435 if (needToRestoreVehicle)
1436 {
1437 // If physical body dependencies were removed, restore them
1438 _vehicle.RestoreBodyDependencies(this);
1439 }
1440
1441 // Make sure the properties are set on the new object 1464 // Make sure the properties are set on the new object
1442 UpdatePhysicalParameters(); 1465 UpdatePhysicalParameters();
1443 return; 1466 return;
1444 } 1467 }
1445 1468
1446 // The physics engine says that properties have updated. Update same and inform 1469 // Called at taint-time
1447 // the world that things have changed. 1470 protected virtual void RemoveDependencies()
1448 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() 1471 {
1449 enum UpdatedProperties { 1472 PhysicalActors.RemoveDependencies();
1450 Position = 1 << 0,
1451 Rotation = 1 << 1,
1452 Velocity = 1 << 2,
1453 Acceleration = 1 << 3,
1454 RotationalVel = 1 << 4
1455 } 1473 }
1456 1474
1457 const float ROTATION_TOLERANCE = 0.01f; 1475 // The physics engine says that properties have updated. Update same and inform
1458 const float VELOCITY_TOLERANCE = 0.001f; 1476 // the world that things have changed.
1459 const float POSITION_TOLERANCE = 0.05f;
1460 const float ACCELERATION_TOLERANCE = 0.01f;
1461 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1462
1463 public override void UpdateProperties(EntityProperties entprop) 1477 public override void UpdateProperties(EntityProperties entprop)
1464 { 1478 {
1465 // Updates only for individual prims and for the root object of a linkset. 1479 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1466 if (Linkset.IsRoot(this)) 1480 TriggerPreUpdatePropertyAction(ref entprop);
1467 {
1468 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1469 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1470 if (_vehicle.IsActive)
1471 {
1472 entprop.RotationalVelocity = OMV.Vector3.Zero;
1473 }
1474 1481
1475 // Assign directly to the local variables so the normal set action does not happen 1482 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1476 _position = entprop.Position;
1477 _orientation = entprop.Rotation;
1478 _velocity = entprop.Velocity;
1479 _acceleration = entprop.Acceleration;
1480 _rotationalVelocity = entprop.RotationalVelocity;
1481 1483
1482 // The sanity check can change the velocity and/or position. 1484 // Assign directly to the local variables so the normal set actions do not happen
1483 if (IsPhysical && PositionSanityCheck(true)) 1485 _position = entprop.Position;
1484 { 1486 _orientation = entprop.Rotation;
1485 entprop.Position = _position; 1487 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1486 entprop.Velocity = _velocity; 1488 // very sensitive to velocity changes.
1487 } 1489 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1490 RawVelocity = entprop.Velocity;
1491 _acceleration = entprop.Acceleration;
1492 _rotationalVelocity = entprop.RotationalVelocity;
1488 1493
1489 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG 1494 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1490 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1491 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1492 1495
1493 // remember the current and last set values 1496 // The sanity check can change the velocity and/or position.
1494 LastEntityProperties = CurrentEntityProperties; 1497 if (PositionSanityCheck(true /* inTaintTime */ ))
1495 CurrentEntityProperties = entprop;
1496
1497 base.RequestPhysicsterseUpdate();
1498 }
1499 /*
1500 else
1501 { 1498 {
1502 // For debugging, report the movement of children 1499 entprop.Position = _position;
1503 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1500 entprop.Velocity = RawVelocity;
1504 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1501 entprop.RotationalVelocity = _rotationalVelocity;
1505 entprop.Acceleration, entprop.RotationalVelocity); 1502 entprop.Acceleration = _acceleration;
1506 } 1503 }
1507 */
1508 1504
1509 // The linkset implimentation might want to know about this. 1505 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1510 Linkset.UpdateProperties(this, true); 1506 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1507
1508 // remember the current and last set values
1509 LastEntityProperties = CurrentEntityProperties;
1510 CurrentEntityProperties = entprop;
1511
1512 // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims.
1513 base.RequestPhysicsterseUpdate();
1511 } 1514 }
1512} 1515}
1513} 1516}