diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 767 |
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 | } |