Merge branch 'master' into careminster
						commit
						a126097d6b
					
				|  | @ -299,6 +299,13 @@ namespace OpenSim.Framework | ||||||
|                 x; |                 x; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         // Inclusive, within range test (true if equal to the endpoints) | ||||||
|  |         public static bool InRange<T>(T x, T min, T max) | ||||||
|  |             where T : IComparable<T> | ||||||
|  |         { | ||||||
|  |             return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public static uint GetNextXferID() |         public static uint GetNextXferID() | ||||||
|         { |         { | ||||||
|             uint id = 0; |             uint id = 0; | ||||||
|  |  | ||||||
|  | @ -88,8 +88,8 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |         // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||||||
|         //     replace with the default values. |         //     replace with the default values. | ||||||
|         _size = size; |         _size = size; | ||||||
|         if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; |         if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||||||
|         if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; |         if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||||||
| 
 | 
 | ||||||
|         // A motor to control the acceleration and deceleration of the avatar movement. |         // A motor to control the acceleration and deceleration of the avatar movement. | ||||||
|         // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); |         // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||||||
|  | @ -108,8 +108,8 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         _velocity = OMV.Vector3.Zero; |         _velocity = OMV.Vector3.Zero; | ||||||
|         _appliedVelocity = OMV.Vector3.Zero; |         _appliedVelocity = OMV.Vector3.Zero; | ||||||
|         _buoyancy = ComputeBuoyancyFromFlying(isFlying); |         _buoyancy = ComputeBuoyancyFromFlying(isFlying); | ||||||
|         _currentFriction = PhysicsScene.Params.avatarStandingFriction; |         _currentFriction = BSParam.AvatarStandingFriction; | ||||||
|         _avatarDensity = PhysicsScene.Params.avatarDensity; |         _avatarDensity = BSParam.AvatarDensity; | ||||||
| 
 | 
 | ||||||
|         // The dimensions of the avatar capsule are kept in the scale. |         // The dimensions of the avatar capsule are kept in the scale. | ||||||
|         // Physics creates a unit capsule which is scaled by the physics engine. |         // Physics creates a unit capsule which is scaled by the physics engine. | ||||||
|  | @ -134,6 +134,8 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|     // called when this character is being destroyed and the resources should be released |     // called when this character is being destroyed and the resources should be released | ||||||
|     public override void Destroy() |     public override void Destroy() | ||||||
|     { |     { | ||||||
|  |         base.Destroy(); | ||||||
|  | 
 | ||||||
|         DetailLog("{0},BSCharacter.Destroy", LocalID); |         DetailLog("{0},BSCharacter.Destroy", LocalID); | ||||||
|         PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |         PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | ||||||
|         { |         { | ||||||
|  | @ -156,19 +158,20 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         _velocityMotor.Reset(); |         _velocityMotor.Reset(); | ||||||
|         _velocityMotor.SetCurrent(_velocity); |         _velocityMotor.SetCurrent(_velocity); | ||||||
|         _velocityMotor.SetTarget(_velocity); |         _velocityMotor.SetTarget(_velocity); | ||||||
|  |         _velocityMotor.Enabled = false; | ||||||
| 
 | 
 | ||||||
|         // This will enable or disable the flying buoyancy of the avatar. |         // This will enable or disable the flying buoyancy of the avatar. | ||||||
|         // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |         // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | ||||||
|         Flying = _flying; |         Flying = _flying; | ||||||
| 
 | 
 | ||||||
|         BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); |         BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution); | ||||||
|         BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); |         BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | ||||||
|         BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); |         BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||||||
|         BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |         BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); | ||||||
|         if (PhysicsScene.Params.ccdMotionThreshold > 0f) |         if (BSParam.CcdMotionThreshold > 0f) | ||||||
|         { |         { | ||||||
|             BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |             BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||||||
|             BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |             BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         UpdatePhysicalMassProperties(RawMass); |         UpdatePhysicalMassProperties(RawMass); | ||||||
|  | @ -208,8 +211,8 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|             _size = value; |             _size = value; | ||||||
|             // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |             // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||||||
|             //     replace with the default values. |             //     replace with the default values. | ||||||
|             if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; |             if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||||||
|             if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; |             if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||||||
| 
 | 
 | ||||||
|             ComputeAvatarScale(_size); |             ComputeAvatarScale(_size); | ||||||
|             ComputeAvatarVolumeAndMass(); |             ComputeAvatarVolumeAndMass(); | ||||||
|  | @ -433,13 +436,13 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|             OMV.Vector3 targetVel = value; |             OMV.Vector3 targetVel = value; | ||||||
|             PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() |             PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||||||
|             { |             { | ||||||
|                 float timeStep = 0.089f;    // DEBUG DEBUG FIX FIX FIX |  | ||||||
|                 _velocityMotor.Reset(); |                 _velocityMotor.Reset(); | ||||||
|                 _velocityMotor.SetTarget(targetVel); |                 _velocityMotor.SetTarget(targetVel); | ||||||
|                 _velocityMotor.SetCurrent(_velocity); |                 _velocityMotor.SetCurrent(_velocity); | ||||||
|                 // Compute a velocity value and make sure it gets pushed into the avatar. |                 _velocityMotor.Enabled = true; | ||||||
|                 // This makes sure the avatar will start from a stop. | 
 | ||||||
|                 ForceVelocity = _velocityMotor.Step(timeStep); |                 // Make sure a property update happens next step so the motor gets incorporated. | ||||||
|  |                 BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -448,12 +451,15 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         get { return _velocity; } |         get { return _velocity; } | ||||||
|         set { |         set { | ||||||
|             _velocity = value; |             _velocity = value; | ||||||
|             _velocityMotor.Reset(); |  | ||||||
|             _velocityMotor.SetCurrent(_velocity); |  | ||||||
|             _velocityMotor.SetTarget(_velocity); |  | ||||||
|             // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); |             // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | ||||||
|             PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() |             PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | ||||||
|             { |             { | ||||||
|  |                 _velocityMotor.Reset(); | ||||||
|  |                 _velocityMotor.SetCurrent(_velocity); | ||||||
|  |                 _velocityMotor.SetTarget(_velocity); | ||||||
|  |                 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | ||||||
|  |                 _velocityMotor.Enabled = false; | ||||||
|  | 
 | ||||||
|                 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); |                 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||||||
|                 ForceVelocity = _velocity; |                 ForceVelocity = _velocity; | ||||||
|             }); |             }); | ||||||
|  | @ -464,27 +470,27 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         set { |         set { | ||||||
|             PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |             PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||||||
| 
 | 
 | ||||||
|  |             _velocity = value; | ||||||
|             // Depending on whether the avatar is moving or not, change the friction |             // Depending on whether the avatar is moving or not, change the friction | ||||||
|             //    to keep the avatar from slipping around |             //    to keep the avatar from slipping around | ||||||
|             if (_velocity.Length() == 0) |             if (_velocity.Length() == 0) | ||||||
|             { |             { | ||||||
|                 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) |                 if (_currentFriction != BSParam.AvatarStandingFriction) | ||||||
|                 { |                 { | ||||||
|                     _currentFriction = PhysicsScene.Params.avatarStandingFriction; |                     _currentFriction = BSParam.AvatarStandingFriction; | ||||||
|                     if (PhysBody.HasPhysicalBody) |                     if (PhysBody.HasPhysicalBody) | ||||||
|                         BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); |                         BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 if (_currentFriction != PhysicsScene.Params.avatarFriction) |                 if (_currentFriction != BSParam.AvatarFriction) | ||||||
|                 { |                 { | ||||||
|                     _currentFriction = PhysicsScene.Params.avatarFriction; |                     _currentFriction = BSParam.AvatarFriction; | ||||||
|                     if (PhysBody.HasPhysicalBody) |                     if (PhysBody.HasPhysicalBody) | ||||||
|                         BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); |                         BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             _velocity = value; |  | ||||||
|             // Remember the set velocity so we can suppress the reduction by friction, ... |             // Remember the set velocity so we can suppress the reduction by friction, ... | ||||||
|             _appliedVelocity = value; |             _appliedVelocity = value; | ||||||
| 
 | 
 | ||||||
|  | @ -561,12 +567,6 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         set { |         set { | ||||||
|             _flying = value; |             _flying = value; | ||||||
| 
 | 
 | ||||||
|             // Velocity movement is different when flying: flying velocity degrades over time. |  | ||||||
|             if (_flying) |  | ||||||
|                 _velocityMotor.TargetValueDecayTimeScale = 1f; |  | ||||||
|             else |  | ||||||
|                 _velocityMotor.TargetValueDecayTimeScale = BSMotor.Infinite; |  | ||||||
| 
 |  | ||||||
|             // simulate flying by changing the effect of gravity |             // simulate flying by changing the effect of gravity | ||||||
|             Buoyancy = ComputeBuoyancyFromFlying(_flying); |             Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||||||
|         } |         } | ||||||
|  | @ -750,39 +750,42 @@ public sealed class BSCharacter : BSPhysObject | ||||||
|         _velocity = entprop.Velocity; |         _velocity = entprop.Velocity; | ||||||
|         _acceleration = entprop.Acceleration; |         _acceleration = entprop.Acceleration; | ||||||
|         _rotationalVelocity = entprop.RotationalVelocity; |         _rotationalVelocity = entprop.RotationalVelocity; | ||||||
|  | 
 | ||||||
|         // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |         // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | ||||||
|         PositionSanityCheck(true); |         PositionSanityCheck(true); | ||||||
| 
 | 
 | ||||||
|  |         if (_velocityMotor.Enabled) | ||||||
|  |         { | ||||||
|  |             // TODO: Decide if the step parameters should be changed depending on the avatar's | ||||||
|  |             //     state (flying, colliding, ...). | ||||||
|  | 
 | ||||||
|  |             OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep); | ||||||
|  | 
 | ||||||
|  |             // If falling, we keep the world's downward vector no matter what the other axis specify. | ||||||
|  |             if (!Flying && !IsColliding) | ||||||
|  |             { | ||||||
|  |                 stepVelocity.Z = entprop.Velocity.Z; | ||||||
|  |                 DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // If the user has said stop and we've stopped applying velocity correction, | ||||||
|  |             //     the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer. | ||||||
|  |             if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero) | ||||||
|  |             { | ||||||
|  |                 stepVelocity = OMV.Vector3.Zero; | ||||||
|  |                 _velocityMotor.Enabled = false; | ||||||
|  |                 DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             _velocity = stepVelocity; | ||||||
|  |             entprop.Velocity = _velocity; | ||||||
|  |             BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // remember the current and last set values |         // remember the current and last set values | ||||||
|         LastEntityProperties = CurrentEntityProperties; |         LastEntityProperties = CurrentEntityProperties; | ||||||
|         CurrentEntityProperties = entprop; |         CurrentEntityProperties = entprop; | ||||||
| 
 | 
 | ||||||
|         // Avatars don't respond to world friction, etc. They only go the speed I tell them too. |  | ||||||
|         // Special kludge here for falling. Even though the target velocity might not have a |  | ||||||
|         //     Z component, the avatar could be falling (walked off a ledge, stopped flying, ...) |  | ||||||
|         //     and that velocity component must be retained. |  | ||||||
|         float timeStep = 0.089f;        // DEBUG DEBUG FIX FIX FIX |  | ||||||
|         OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); |  | ||||||
|         // Remove next line so avatars don't fly up forever. DEBUG DEBUG this is only temporary. |  | ||||||
|         // stepVelocity.Z += entprop.Velocity.Z; |  | ||||||
|         _velocity = stepVelocity; |  | ||||||
|         BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |  | ||||||
|         /* |  | ||||||
|         OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); |  | ||||||
|         OMV.Vector3 avVel = new OMV.Vector3(stepVelocity.X, stepVelocity.Y, entprop.Velocity.Z); |  | ||||||
|         _velocity = avVel; |  | ||||||
|         BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); |  | ||||||
|          |  | ||||||
|         if (entprop.Velocity != LastEntityProperties.Velocity) |  | ||||||
|         { |  | ||||||
|             // Changes in the velocity are suppressed in avatars. |  | ||||||
|             // That's just the way they are defined. |  | ||||||
|             OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); |  | ||||||
|             _velocity = avVel; |  | ||||||
|             BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); |  | ||||||
|         } |  | ||||||
|          */ |  | ||||||
| 
 |  | ||||||
|         // Tell the linkset about value changes |         // Tell the linkset about value changes | ||||||
|         Linkset.UpdateProperties(this, true); |         Linkset.UpdateProperties(this, true); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -122,7 +122,7 @@ public abstract class BSConstraint : IDisposable | ||||||
|                 // Setting an object's mass to zero (making it static like when it's selected) |                 // Setting an object's mass to zero (making it static like when it's selected) | ||||||
|                 //     automatically disables the constraints. |                 //     automatically disables the constraints. | ||||||
|                 // If the link is enabled, be sure to set the constraint itself to enabled. |                 // If the link is enabled, be sure to set the constraint itself to enabled. | ||||||
|                 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); |                 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true)); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  |  | ||||||
|  | @ -563,7 +563,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|                 // Moderate angular movement introduced by Bullet. |                 // Moderate angular movement introduced by Bullet. | ||||||
|                 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. |                 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||||||
|                 //     Maybe compute linear and angular factor and damping from params. |                 //     Maybe compute linear and angular factor and damping from params. | ||||||
|                 float angularDamping = PhysicsScene.Params.vehicleAngularDamping; |                 float angularDamping = BSParam.VehicleAngularDamping; | ||||||
|                 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); |                 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||||||
| 
 | 
 | ||||||
|                 // Vehicles report collision events so we know when it's on the ground |                 // Vehicles report collision events so we know when it's on the ground | ||||||
|  | @ -634,28 +634,33 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|             m_knownHas = 0; |             m_knownHas = 0; | ||||||
|             m_knownChanged = 0; |             m_knownChanged = 0; | ||||||
|         } |         } | ||||||
|  |         // Push all the changed values back into the physics engine | ||||||
|         private void PushKnownChanged() |         private void PushKnownChanged() | ||||||
|         { |         { | ||||||
|             if (m_knownChanged != 0) |             if (m_knownChanged != 0) | ||||||
|             { |             { | ||||||
|                 if ((m_knownChanged & m_knownChangedPosition) != 0) |                 if ((m_knownChanged & m_knownChangedPosition) != 0) | ||||||
|                     Prim.ForcePosition = VehiclePosition; |                     Prim.ForcePosition = m_knownPosition; | ||||||
|  | 
 | ||||||
|                 if ((m_knownChanged & m_knownChangedOrientation) != 0) |                 if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||||||
|                     Prim.ForceOrientation = VehicleOrientation; |                     Prim.ForceOrientation = m_knownOrientation; | ||||||
|  | 
 | ||||||
|                 if ((m_knownChanged & m_knownChangedVelocity) != 0) |                 if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||||||
|                 { |                 { | ||||||
|                     Prim.ForceVelocity = VehicleVelocity; |                     Prim.ForceVelocity = m_knownVelocity; | ||||||
|                     BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); |                     BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 if ((m_knownChanged & m_knownChangedForce) != 0) |                 if ((m_knownChanged & m_knownChangedForce) != 0) | ||||||
|                     Prim.AddForce((Vector3)m_knownForce, false, true); |                     Prim.AddForce((Vector3)m_knownForce, false, true); | ||||||
| 
 | 
 | ||||||
|                 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) |                 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||||||
|                 { |                 { | ||||||
|                     Prim.ForceRotationalVelocity = VehicleRotationalVelocity; |                     Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | ||||||
|                     // Fake out Bullet by making it think the velocity is the same as last time. |                     // Fake out Bullet by making it think the velocity is the same as last time. | ||||||
|                     BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity); |                     BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|                 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) |                 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||||||
|                     Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); |                     Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | ||||||
| 
 | 
 | ||||||
|  | @ -667,7 +672,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Since the computation of terrain height can be a little involved, this routine |         // Since the computation of terrain height can be a little involved, this routine | ||||||
|         //    is used ot fetch the height only once for each vehicle simulation step. |         //    is used to fetch the height only once for each vehicle simulation step. | ||||||
|         private float GetTerrainHeight(Vector3 pos) |         private float GetTerrainHeight(Vector3 pos) | ||||||
|         { |         { | ||||||
|             if ((m_knownHas & m_knownChangedTerrainHeight) == 0) |             if ((m_knownHas & m_knownChangedTerrainHeight) == 0) | ||||||
|  | @ -699,12 +704,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|                     m_knownPosition = Prim.ForcePosition; |                     m_knownPosition = Prim.ForcePosition; | ||||||
|                     m_knownHas |= m_knownChangedPosition; |                     m_knownHas |= m_knownChangedPosition; | ||||||
|                 } |                 } | ||||||
|                 return (Vector3)m_knownPosition; |                 return m_knownPosition; | ||||||
|             } |             } | ||||||
|             set |             set | ||||||
|             { |             { | ||||||
|                 m_knownPosition = value; |                 m_knownPosition = value; | ||||||
|                 m_knownChanged |= m_knownChangedPosition; |                 m_knownChanged |= m_knownChangedPosition; | ||||||
|  |                 m_knownHas |= m_knownChangedPosition; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -717,12 +723,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|                     m_knownOrientation = Prim.ForceOrientation; |                     m_knownOrientation = Prim.ForceOrientation; | ||||||
|                     m_knownHas |= m_knownChangedOrientation; |                     m_knownHas |= m_knownChangedOrientation; | ||||||
|                 } |                 } | ||||||
|                 return (Quaternion)m_knownOrientation; |                 return m_knownOrientation; | ||||||
|             } |             } | ||||||
|             set |             set | ||||||
|             { |             { | ||||||
|                 m_knownOrientation = value; |                 m_knownOrientation = value; | ||||||
|                 m_knownChanged |= m_knownChangedOrientation; |                 m_knownChanged |= m_knownChangedOrientation; | ||||||
|  |                 m_knownHas |= m_knownChangedOrientation; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -741,13 +748,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|             { |             { | ||||||
|                 m_knownVelocity = value; |                 m_knownVelocity = value; | ||||||
|                 m_knownChanged |= m_knownChangedVelocity; |                 m_knownChanged |= m_knownChangedVelocity; | ||||||
|  |                 m_knownHas |= m_knownChangedVelocity; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private void VehicleAddForce(Vector3 aForce) |         private void VehicleAddForce(Vector3 aForce) | ||||||
|         { |         { | ||||||
|  |             if ((m_knownHas & m_knownChangedForce) == 0) | ||||||
|  |             { | ||||||
|  |                 m_knownForce = Vector3.Zero; | ||||||
|  |             } | ||||||
|             m_knownForce += aForce; |             m_knownForce += aForce; | ||||||
|             m_knownChanged |= m_knownChangedForce; |             m_knownChanged |= m_knownChangedForce; | ||||||
|  |             m_knownHas |= m_knownChangedForce; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private Vector3 VehicleRotationalVelocity |         private Vector3 VehicleRotationalVelocity | ||||||
|  | @ -765,12 +778,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|             { |             { | ||||||
|                 m_knownRotationalVelocity = value; |                 m_knownRotationalVelocity = value; | ||||||
|                 m_knownChanged |= m_knownChangedRotationalVelocity; |                 m_knownChanged |= m_knownChangedRotationalVelocity; | ||||||
|  |                 m_knownHas |= m_knownChangedRotationalVelocity; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         private void VehicleAddAngularForce(Vector3 aForce) |         private void VehicleAddAngularForce(Vector3 aForce) | ||||||
|         { |         { | ||||||
|  |             if ((m_knownHas & m_knownChangedRotationalForce) == 0) | ||||||
|  |             { | ||||||
|  |                 m_knownRotationalForce = Vector3.Zero; | ||||||
|  |             } | ||||||
|             m_knownRotationalForce += aForce; |             m_knownRotationalForce += aForce; | ||||||
|             m_knownChanged |= m_knownChangedRotationalForce; |             m_knownChanged |= m_knownChangedRotationalForce; | ||||||
|  |             m_knownHas |= m_knownChangedRotationalForce; | ||||||
|         } |         } | ||||||
|         // Vehicle relative forward velocity |         // Vehicle relative forward velocity | ||||||
|         private Vector3 VehicleForwardVelocity |         private Vector3 VehicleForwardVelocity | ||||||
|  | @ -782,7 +801,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|                     m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); |                     m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||||||
|                     m_knownHas |= m_knownChangedForwardVelocity; |                     m_knownHas |= m_knownChangedForwardVelocity; | ||||||
|                 } |                 } | ||||||
|                 return (Vector3)m_knownForwardVelocity; |                 return m_knownForwardVelocity; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         private float VehicleForwardSpeed |         private float VehicleForwardSpeed | ||||||
|  |  | ||||||
|  | @ -56,7 +56,7 @@ public abstract class BSLinkset | ||||||
|     { |     { | ||||||
|         BSLinkset ret = null; |         BSLinkset ret = null; | ||||||
| 
 | 
 | ||||||
|         switch ((int)physScene.Params.linksetImplementation) |         switch ((int)BSParam.LinksetImplementation) | ||||||
|         { |         { | ||||||
|             case (int)LinksetImplementation.Constraint: |             case (int)LinksetImplementation.Constraint: | ||||||
|                 ret = new BSLinksetConstraints(physScene, parent); |                 ret = new BSLinksetConstraints(physScene, parent); | ||||||
|  |  | ||||||
|  | @ -226,14 +226,14 @@ public sealed class BSLinksetConstraints : BSLinkset | ||||||
|         constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |         constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||||||
| 
 | 
 | ||||||
|         // tweek the constraint to increase stability |         // tweek the constraint to increase stability | ||||||
|         constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); |         constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); | ||||||
|         constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), |         constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), | ||||||
|                         PhysicsScene.Params.linkConstraintTransMotorMaxVel, |                         BSParam.LinkConstraintTransMotorMaxVel, | ||||||
|                         PhysicsScene.Params.linkConstraintTransMotorMaxForce); |                         BSParam.LinkConstraintTransMotorMaxForce); | ||||||
|         constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); |         constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); | ||||||
|         if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) |         if (BSParam.LinkConstraintSolverIterations != 0f) | ||||||
|         { |         { | ||||||
|             constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); |             constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); | ||||||
|         } |         } | ||||||
|         return constrain; |         return constrain; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -43,7 +43,9 @@ public abstract class BSMotor | ||||||
|     { |     { | ||||||
|         UseName = useName; |         UseName = useName; | ||||||
|         PhysicsScene = null; |         PhysicsScene = null; | ||||||
|  |         Enabled = true; | ||||||
|     } |     } | ||||||
|  |     public virtual bool Enabled { get; set; } | ||||||
|     public virtual void Reset() { } |     public virtual void Reset() { } | ||||||
|     public virtual void Zero() { } |     public virtual void Zero() { } | ||||||
|     public virtual void GenerateTestOutput(float timeStep) { } |     public virtual void GenerateTestOutput(float timeStep) { } | ||||||
|  | @ -98,6 +100,12 @@ public class BSVMotor : BSMotor | ||||||
|     public virtual Vector3 CurrentValue { get; protected set; } |     public virtual Vector3 CurrentValue { get; protected set; } | ||||||
|     public virtual Vector3 LastError { get; protected set; } |     public virtual Vector3 LastError { get; protected set; } | ||||||
| 
 | 
 | ||||||
|  |     public virtual bool ErrorIsZero | ||||||
|  |     { get { | ||||||
|  |         return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public BSVMotor(string useName) |     public BSVMotor(string useName) | ||||||
|         : base(useName) |         : base(useName) | ||||||
|     { |     { | ||||||
|  | @ -105,7 +113,7 @@ public class BSVMotor : BSMotor | ||||||
|         Efficiency = 1f; |         Efficiency = 1f; | ||||||
|         FrictionTimescale = BSMotor.InfiniteVector; |         FrictionTimescale = BSMotor.InfiniteVector; | ||||||
|         CurrentValue = TargetValue = Vector3.Zero; |         CurrentValue = TargetValue = Vector3.Zero; | ||||||
|         ErrorZeroThreshold = 0.01f; |         ErrorZeroThreshold = 0.001f; | ||||||
|     } |     } | ||||||
|     public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)  |     public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)  | ||||||
|         : this(useName) |         : this(useName) | ||||||
|  | @ -133,6 +141,8 @@ public class BSVMotor : BSMotor | ||||||
|     // Compute the next step and return the new current value |     // Compute the next step and return the new current value | ||||||
|     public virtual Vector3 Step(float timeStep) |     public virtual Vector3 Step(float timeStep) | ||||||
|     { |     { | ||||||
|  |         if (!Enabled) return TargetValue; | ||||||
|  | 
 | ||||||
|         Vector3 origTarget = TargetValue;       // DEBUG |         Vector3 origTarget = TargetValue;       // DEBUG | ||||||
|         Vector3 origCurrVal = CurrentValue;     // DEBUG |         Vector3 origCurrVal = CurrentValue;     // DEBUG | ||||||
| 
 | 
 | ||||||
|  | @ -178,7 +188,7 @@ public class BSVMotor : BSMotor | ||||||
|         { |         { | ||||||
|             // Difference between what we have and target is small. Motor is done. |             // Difference between what we have and target is small. Motor is done. | ||||||
|             CurrentValue = TargetValue; |             CurrentValue = TargetValue; | ||||||
|             MDetailLog("{0},  BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={2}", |             MDetailLog("{0},  BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||||||
|                         BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); |                         BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -186,6 +196,8 @@ public class BSVMotor : BSMotor | ||||||
|     } |     } | ||||||
|     public virtual Vector3 Step(float timeStep, Vector3 error) |     public virtual Vector3 Step(float timeStep, Vector3 error) | ||||||
|     { |     { | ||||||
|  |         if (!Enabled) return Vector3.Zero; | ||||||
|  | 
 | ||||||
|         LastError = error; |         LastError = error; | ||||||
|         Vector3 returnCorrection = Vector3.Zero; |         Vector3 returnCorrection = Vector3.Zero; | ||||||
|         if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) |         if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||||||
|  | @ -268,12 +280,14 @@ public class BSPIDVMotor : BSVMotor | ||||||
|     public Vector3 proportionFactor { get; set; } |     public Vector3 proportionFactor { get; set; } | ||||||
|     public Vector3 integralFactor { get; set; } |     public Vector3 integralFactor { get; set; } | ||||||
|     public Vector3 derivFactor { get; set; } |     public Vector3 derivFactor { get; set; } | ||||||
|  | 
 | ||||||
|     // Arbritrary factor range. |     // Arbritrary factor range. | ||||||
|     // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. |     // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | ||||||
|     public float EfficiencyHigh = 0.4f; |     public float EfficiencyHigh = 0.4f; | ||||||
|     public float EfficiencyLow = 4.0f; |     public float EfficiencyLow = 4.0f; | ||||||
| 
 | 
 | ||||||
|     Vector3 IntegralFactor { get; set; } |     // Running integration of the error | ||||||
|  |     Vector3 RunningIntegration { get; set; } | ||||||
| 
 | 
 | ||||||
|     public BSPIDVMotor(string useName) |     public BSPIDVMotor(string useName) | ||||||
|         : base(useName) |         : base(useName) | ||||||
|  | @ -281,7 +295,7 @@ public class BSPIDVMotor : BSVMotor | ||||||
|         proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); |         proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||||||
|         integralFactor = new Vector3(1.00f, 1.00f, 1.00f); |         integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||||||
|         derivFactor = new Vector3(1.00f, 1.00f, 1.00f); |         derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | ||||||
|         IntegralFactor = Vector3.Zero; |         RunningIntegration = Vector3.Zero; | ||||||
|         LastError = Vector3.Zero; |         LastError = Vector3.Zero; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -311,15 +325,21 @@ public class BSPIDVMotor : BSVMotor | ||||||
|     // Ignore Current and Target Values and just advance the PID computation on this error. |     // Ignore Current and Target Values and just advance the PID computation on this error. | ||||||
|     public override Vector3 Step(float timeStep, Vector3 error) |     public override Vector3 Step(float timeStep, Vector3 error) | ||||||
|     { |     { | ||||||
|  |         if (!Enabled) return Vector3.Zero; | ||||||
|  | 
 | ||||||
|         // Add up the error so we can integrate over the accumulated errors |         // Add up the error so we can integrate over the accumulated errors | ||||||
|         IntegralFactor += error * timeStep; |         RunningIntegration += error * timeStep; | ||||||
| 
 | 
 | ||||||
|         // A simple derivitive is the rate of change from the last error. |         // A simple derivitive is the rate of change from the last error. | ||||||
|         Vector3 derivFactor = (error - LastError) * timeStep; |         Vector3 derivFactor = (error - LastError) * timeStep; | ||||||
|         LastError = error; |         LastError = error; | ||||||
| 
 | 
 | ||||||
|         // Correction = -(proportionOfPresentError +      accumulationOfPastError    +     rateOfChangeOfError) |         // Correction = -(proportionOfPresentError +      accumulationOfPastError    +     rateOfChangeOfError) | ||||||
|         Vector3 ret   = -(error * proportionFactor + IntegralFactor * integralFactor + derivFactor * derivFactor); |         Vector3 ret   = -( | ||||||
|  |                           error * proportionFactor | ||||||
|  |                         + RunningIntegration * integralFactor  | ||||||
|  |                         + derivFactor * derivFactor | ||||||
|  |                         ); | ||||||
| 
 | 
 | ||||||
|         return ret; |         return ret; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,559 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) Contributors, http://opensimulator.org/ | ||||||
|  |  * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are met: | ||||||
|  |  *     * Redistributions of source code must retain the above copyright | ||||||
|  |  *       notice, this list of conditions and the following disclaimer. | ||||||
|  |  *     * Redistributions in binary form must reproduce the above copyrightD | ||||||
|  |  *       notice, this list of conditions and the following disclaimer in the | ||||||
|  |  *       documentation and/or other materials provided with the distribution. | ||||||
|  |  *     * Neither the name of the OpenSimulator Project nor the | ||||||
|  |  *       names of its contributors may be used to endorse or promote products | ||||||
|  |  *       derived from this software without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||||||
|  |  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||||||
|  |  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||||
|  |  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||||||
|  |  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||||||
|  |  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||||
|  |  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||||||
|  |  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  |  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Text; | ||||||
|  | 
 | ||||||
|  | using OpenSim.Region.Physics.Manager; | ||||||
|  | 
 | ||||||
|  | using OpenMetaverse; | ||||||
|  | using Nini.Config; | ||||||
|  | 
 | ||||||
|  | namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|  | { | ||||||
|  | public static class BSParam | ||||||
|  | { | ||||||
|  |     // Level of Detail values kept as float because that's what the Meshmerizer wants | ||||||
|  |     public static float MeshLOD { get; private set; } | ||||||
|  |     public static float MeshMegaPrimLOD { get; private set; } | ||||||
|  |     public static float MeshMegaPrimThreshold { get; private set; } | ||||||
|  |     public static float SculptLOD { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static float MinimumObjectMass { get; private set; } | ||||||
|  |     public static float MaximumObjectMass { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static float LinearDamping { get; private set; } | ||||||
|  |     public static float AngularDamping { get; private set; } | ||||||
|  |     public static float DeactivationTime { get; private set; } | ||||||
|  |     public static float LinearSleepingThreshold { get; private set; } | ||||||
|  |     public static float AngularSleepingThreshold { get; private set; } | ||||||
|  | 	public static float CcdMotionThreshold { get; private set; } | ||||||
|  | 	public static float CcdSweptSphereRadius { get; private set; } | ||||||
|  |     public static float ContactProcessingThreshold { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static bool ShouldMeshSculptedPrim { get; private set; }   // cause scuplted prims to get meshed | ||||||
|  |     public static bool ShouldForceSimplePrimMeshing { get; private set; }   // if a cube or sphere, let Bullet do internal shapes | ||||||
|  |     public static bool ShouldUseHullsForPhysicalObjects { get; private set; }   // 'true' if should create hulls for physical objects | ||||||
|  | 
 | ||||||
|  |     public static float TerrainImplementation { get; private set; } | ||||||
|  |     public static float TerrainFriction { get; private set; } | ||||||
|  |     public static float TerrainHitFraction { get; private set; } | ||||||
|  |     public static float TerrainRestitution { get; private set; } | ||||||
|  |     public static float TerrainCollisionMargin { get; private set; } | ||||||
|  | 
 | ||||||
|  |     // Avatar parameters | ||||||
|  |     public static float AvatarFriction { get; private set; } | ||||||
|  |     public static float AvatarStandingFriction { get; private set; } | ||||||
|  |     public static float AvatarDensity { get; private set; } | ||||||
|  |     public static float AvatarRestitution { get; private set; } | ||||||
|  |     public static float AvatarCapsuleWidth { get; private set; } | ||||||
|  |     public static float AvatarCapsuleDepth { get; private set; } | ||||||
|  |     public static float AvatarCapsuleHeight { get; private set; } | ||||||
|  | 	public static float AvatarContactProcessingThreshold { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static float VehicleAngularDamping { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static float LinksetImplementation { get; private set; } | ||||||
|  |     public static float LinkConstraintUseFrameOffset { get; private set; } | ||||||
|  |     public static float LinkConstraintEnableTransMotor { get; private set; } | ||||||
|  |     public static float LinkConstraintTransMotorMaxVel { get; private set; } | ||||||
|  |     public static float LinkConstraintTransMotorMaxForce { get; private set; } | ||||||
|  |     public static float LinkConstraintERP { get; private set; } | ||||||
|  |     public static float LinkConstraintCFM { get; private set; } | ||||||
|  |     public static float LinkConstraintSolverIterations { get; private set; } | ||||||
|  | 
 | ||||||
|  |     public static float PID_D { get; private set; }    // derivative | ||||||
|  |     public static float PID_P { get; private set; }    // proportional | ||||||
|  | 
 | ||||||
|  |     public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | ||||||
|  |     public delegate float ParamGet(BSScene scene); | ||||||
|  |     public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||||||
|  |     public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||||||
|  | 
 | ||||||
|  |     public struct ParameterDefn | ||||||
|  |     { | ||||||
|  |         public string name;         // string name of the parameter | ||||||
|  |         public string desc;         // a short description of what the parameter means | ||||||
|  |         public float defaultValue;  // default value if not specified anywhere else | ||||||
|  |         public ParamUser userParam; // get the value from the configuration file | ||||||
|  |         public ParamGet getter;     // return the current value stored for this parameter | ||||||
|  |         public ParamSet setter;     // set the current value for this parameter | ||||||
|  |         public SetOnObject onObject;    // set the value on an object in the physical domain | ||||||
|  |         public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | ||||||
|  |         { | ||||||
|  |             name = n; | ||||||
|  |             desc = d; | ||||||
|  |             defaultValue = v; | ||||||
|  |             userParam = u; | ||||||
|  |             getter = g; | ||||||
|  |             setter = s; | ||||||
|  |             onObject = null; | ||||||
|  |         } | ||||||
|  |         public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||||||
|  |         { | ||||||
|  |             name = n; | ||||||
|  |             desc = d; | ||||||
|  |             defaultValue = v; | ||||||
|  |             userParam = u; | ||||||
|  |             getter = g; | ||||||
|  |             setter = s; | ||||||
|  |             onObject = o; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // List of all of the externally visible parameters. | ||||||
|  |     // For each parameter, this table maps a text name to getter and setters. | ||||||
|  |     // To add a new externally referencable/settable parameter, add the paramter storage | ||||||
|  |     //    location somewhere in the program and make an entry in this table with the | ||||||
|  |     //    getters and setters. | ||||||
|  |     // It is easiest to find an existing definition and copy it. | ||||||
|  |     // Parameter values are floats. Booleans are converted to a floating value. | ||||||
|  |     // | ||||||
|  |     // A ParameterDefn() takes the following parameters: | ||||||
|  |     //    -- the text name of the parameter. This is used for console input and ini file. | ||||||
|  |     //    -- a short text description of the parameter. This shows up in the console listing. | ||||||
|  |     //    -- a default value (float) | ||||||
|  |     //    -- a delegate for fetching the parameter from the ini file. | ||||||
|  |     //          Should handle fetching the right type from the ini file and converting it. | ||||||
|  |     //    -- a delegate for getting the value as a float | ||||||
|  |     //    -- a delegate for setting the value from a float | ||||||
|  |     //    -- an optional delegate to update the value in the world. Most often used to | ||||||
|  |     //          push the new value to an in-world object. | ||||||
|  |     // | ||||||
|  |     // The single letter parameters for the delegates are: | ||||||
|  |     //    s = BSScene | ||||||
|  |     //    o = BSPhysObject | ||||||
|  |     //    p = string parameter name | ||||||
|  |     //    l = localID of referenced object | ||||||
|  |     //    v = value (float) | ||||||
|  |     //    cf = parameter configuration class (for fetching values from ini file) | ||||||
|  |     private static ParameterDefn[] ParameterDefinitions = | ||||||
|  |     { | ||||||
|  |         new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | ||||||
|  |             ConfigurationParameters.numericTrue, | ||||||
|  |             (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||||||
|  |             (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, | ||||||
|  |             (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), | ||||||
|  |         new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | ||||||
|  |             ConfigurationParameters.numericFalse, | ||||||
|  |             (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||||||
|  |             (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, | ||||||
|  |             (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), | ||||||
|  |         new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||||||
|  |             ConfigurationParameters.numericTrue, | ||||||
|  |             (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | ||||||
|  |             (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, | ||||||
|  |             (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||||||
|  |             8f, | ||||||
|  |             (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return MeshLOD; }, | ||||||
|  |             (s,p,l,v) => { MeshLOD = v; } ), | ||||||
|  |         new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | ||||||
|  |             16f, | ||||||
|  |             (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return MeshMegaPrimLOD; }, | ||||||
|  |             (s,p,l,v) => { MeshMegaPrimLOD = v; } ), | ||||||
|  |         new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||||||
|  |             10f, | ||||||
|  |             (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return MeshMegaPrimThreshold; }, | ||||||
|  |             (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), | ||||||
|  |         new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||||||
|  |             32f, | ||||||
|  |             (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return SculptLOD; }, | ||||||
|  |             (s,p,l,v) => { SculptLOD = v; } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | ||||||
|  |             10f, | ||||||
|  |             (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return (float)s.m_maxSubSteps; }, | ||||||
|  |             (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | ||||||
|  |         new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||||||
|  |             1f / 60f, | ||||||
|  |             (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return (float)s.m_fixedTimeStep; }, | ||||||
|  |             (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | ||||||
|  |         new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | ||||||
|  |             2048f, | ||||||
|  |             (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return (float)s.m_maxCollisionsPerFrame; }, | ||||||
|  |             (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | ||||||
|  |         new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | ||||||
|  |             8000f, | ||||||
|  |             (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return (float)s.m_maxUpdatesPerFrame; }, | ||||||
|  |             (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||||||
|  |         new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||||||
|  |             500f, | ||||||
|  |             (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||||||
|  |             (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||||||
|  |         new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", | ||||||
|  |             0.0001f, | ||||||
|  |             (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return (float)MinimumObjectMass; }, | ||||||
|  |             (s,p,l,v) => { MinimumObjectMass = v; } ), | ||||||
|  |         new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||||||
|  |             10000.01f, | ||||||
|  |             (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return (float)MaximumObjectMass; }, | ||||||
|  |             (s,p,l,v) => { MaximumObjectMass = v; } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | ||||||
|  |             2200f, | ||||||
|  |             (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return (float)PID_D; }, | ||||||
|  |             (s,p,l,v) => { PID_D = v; } ), | ||||||
|  |         new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | ||||||
|  |             900f, | ||||||
|  |             (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return (float)PID_P; }, | ||||||
|  |             (s,p,l,v) => { PID_P = v; } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | ||||||
|  |             0.2f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].defaultFriction; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), | ||||||
|  |         new ParameterDefn("DefaultDensity", "Density for new objects" , | ||||||
|  |             10.000006836f,  // Aluminum g/cm3 | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].defaultDensity; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), | ||||||
|  |         new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].defaultRestitution; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), | ||||||
|  |         new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||||||
|  |             0.04f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].collisionMargin; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), | ||||||
|  |         new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||||||
|  |             -9.80665f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].gravity; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinearDamping; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ), | ||||||
|  |         new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AngularDamping; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ), | ||||||
|  |         new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | ||||||
|  |             0.2f, | ||||||
|  |             (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return DeactivationTime; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), | ||||||
|  |         new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | ||||||
|  |             0.8f, | ||||||
|  |             (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinearSleepingThreshold; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||||||
|  |         new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | ||||||
|  |             1.0f, | ||||||
|  |             (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AngularSleepingThreshold; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), | ||||||
|  |         new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | ||||||
|  |             0f,     // set to zero to disable | ||||||
|  |             (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return CcdMotionThreshold; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), | ||||||
|  |         new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return CcdSweptSphereRadius; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), | ||||||
|  |         new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | ||||||
|  |             0.1f, | ||||||
|  |             (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return ContactProcessingThreshold; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, | ||||||
|  |             (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), | ||||||
|  | 
 | ||||||
|  | 	    new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | ||||||
|  |             (float)BSTerrainPhys.TerrainImplementation.Mesh, | ||||||
|  |             (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, | ||||||
|  |             (s) => { return TerrainImplementation; }, | ||||||
|  |             (s,p,l,v) => { TerrainImplementation = v; } ), | ||||||
|  |         new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | ||||||
|  |             0.3f, | ||||||
|  |             (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return TerrainFriction; }, | ||||||
|  |             (s,p,l,v) => { TerrainFriction = v;  /* TODO: set on real terrain */} ), | ||||||
|  |         new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | ||||||
|  |             0.8f, | ||||||
|  |             (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return TerrainHitFraction; }, | ||||||
|  |             (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||||||
|  |         new ParameterDefn("TerrainRestitution", "Bouncyness" , | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return TerrainRestitution; }, | ||||||
|  |             (s,p,l,v) => { TerrainRestitution = v;  /* TODO: set on real terrain */ } ), | ||||||
|  |         new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||||||
|  |             0.04f, | ||||||
|  |             (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return TerrainCollisionMargin; }, | ||||||
|  |             (s,p,l,v) => { TerrainCollisionMargin = v;  /* TODO: set on real terrain */ } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||||||
|  |             0.2f, | ||||||
|  |             (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarFriction; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), | ||||||
|  |         new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||||||
|  |             10.0f, | ||||||
|  |             (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarStandingFriction; }, | ||||||
|  |             (s,p,l,v) => { AvatarStandingFriction = v; } ), | ||||||
|  |         new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||||||
|  |             60f, | ||||||
|  |             (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarDensity; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), | ||||||
|  |         new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarRestitution; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), | ||||||
|  |         new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||||||
|  |             0.6f, | ||||||
|  |             (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarCapsuleWidth; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), | ||||||
|  |         new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||||||
|  |             0.45f, | ||||||
|  |             (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarCapsuleDepth; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), | ||||||
|  |         new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | ||||||
|  |             1.5f, | ||||||
|  |             (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarCapsuleHeight; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), | ||||||
|  | 	    new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||||||
|  |             0.1f, | ||||||
|  |             (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return AvatarContactProcessingThreshold; }, | ||||||
|  |             (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||||||
|  |             0.95f, | ||||||
|  |             (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return VehicleAngularDamping; }, | ||||||
|  |             (s,p,l,v) => { VehicleAngularDamping = v; } ), | ||||||
|  | 
 | ||||||
|  | 	    new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | ||||||
|  | 	    new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | ||||||
|  | 	    new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||||||
|  |             ConfigurationParameters.numericFalse, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||||||
|  | 	    new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||||||
|  |             ConfigurationParameters.numericFalse, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), | ||||||
|  | 	    new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||||||
|  |             ConfigurationParameters.numericTrue, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), | ||||||
|  | 	    new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||||||
|  |             ConfigurationParameters.numericTrue, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), | ||||||
|  | 	    new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||||||
|  |             ConfigurationParameters.numericFalse, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), | ||||||
|  | 	    new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||||||
|  |             0f,     // zero says use Bullet default | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||||||
|  | 
 | ||||||
|  | 	    new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||||||
|  |             (float)BSLinkset.LinksetImplementation.Compound, | ||||||
|  |             (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, | ||||||
|  |             (s) => { return LinksetImplementation; }, | ||||||
|  |             (s,p,l,v) => { LinksetImplementation = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||||||
|  |             ConfigurationParameters.numericFalse, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return LinkConstraintUseFrameOffset; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||||||
|  |             ConfigurationParameters.numericTrue, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||||||
|  |             (s) => { return LinkConstraintEnableTransMotor; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||||||
|  |             5.0f, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinkConstraintTransMotorMaxVel; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||||||
|  |             0.1f, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinkConstraintTransMotorMaxForce; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||||||
|  |             0.1f, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinkConstraintCFM; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintCFM = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||||||
|  |             0.1f, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinkConstraintERP; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintERP = v; } ), | ||||||
|  | 	    new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||||||
|  |             40, | ||||||
|  |             (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||||||
|  |             (s) => { return LinkConstraintSolverIterations; }, | ||||||
|  |             (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), | ||||||
|  | 
 | ||||||
|  |         new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", | ||||||
|  |             0f, | ||||||
|  |             (s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, | ||||||
|  |             (s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; }, | ||||||
|  |             (s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Convert a boolean to our numeric true and false values | ||||||
|  |     public static float NumericBool(bool b) | ||||||
|  |     { | ||||||
|  |         return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Convert numeric true and false values to a boolean | ||||||
|  |     public static bool BoolNumeric(float b) | ||||||
|  |     { | ||||||
|  |         return (b == ConfigurationParameters.numericTrue ? true : false); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Search through the parameter definitions and return the matching | ||||||
|  |     //    ParameterDefn structure. | ||||||
|  |     // Case does not matter as names are compared after converting to lower case. | ||||||
|  |     // Returns 'false' if the parameter is not found. | ||||||
|  |     internal static bool TryGetParameter(string paramName, out ParameterDefn defn) | ||||||
|  |     { | ||||||
|  |         bool ret = false; | ||||||
|  |         ParameterDefn foundDefn = new ParameterDefn(); | ||||||
|  |         string pName = paramName.ToLower(); | ||||||
|  | 
 | ||||||
|  |         foreach (ParameterDefn parm in ParameterDefinitions) | ||||||
|  |         { | ||||||
|  |             if (pName == parm.name.ToLower()) | ||||||
|  |             { | ||||||
|  |                 foundDefn = parm; | ||||||
|  |                 ret = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         defn = foundDefn; | ||||||
|  |         return ret; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Pass through the settable parameters and set the default values | ||||||
|  |     internal static void SetParameterDefaultValues(BSScene physicsScene) | ||||||
|  |     { | ||||||
|  |         foreach (ParameterDefn parm in ParameterDefinitions) | ||||||
|  |         { | ||||||
|  |             parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Get user set values out of the ini file. | ||||||
|  |     internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | ||||||
|  |     { | ||||||
|  |         foreach (ParameterDefn parm in ParameterDefinitions) | ||||||
|  |         { | ||||||
|  |             parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; | ||||||
|  | 
 | ||||||
|  |     // This creates an array in the correct format for returning the list of | ||||||
|  |     //    parameters. This is used by the 'list' option of the 'physics' command. | ||||||
|  |     internal static void BuildParameterTable() | ||||||
|  |     { | ||||||
|  |         if (SettableParameters.Length < ParameterDefinitions.Length) | ||||||
|  |         { | ||||||
|  |             List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | ||||||
|  |             for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | ||||||
|  |             { | ||||||
|  |                 ParameterDefn pd = ParameterDefinitions[ii]; | ||||||
|  |                 entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // make the list in alphabetical order for estetic reasons | ||||||
|  |             entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | ||||||
|  |             { | ||||||
|  |                 return ppe1.name.CompareTo(ppe2.name); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             SettableParameters = entries.ToArray(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | } | ||||||
|  | @ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | ||||||
|  *      ForceVariableName: direct reference (store and fetch) to the value in the physics engine. |  *      ForceVariableName: direct reference (store and fetch) to the value in the physics engine. | ||||||
|  *  The last two (and certainly the last one) should be referenced only in taint-time. |  *  The last two (and certainly the last one) should be referenced only in taint-time. | ||||||
|  */ |  */ | ||||||
|  | 
 | ||||||
|  | /* | ||||||
|  |  * As of 20121221, the following are the call sequences (going down) for different script physical functions: | ||||||
|  |  * llApplyImpulse       llApplyRotImpulse           llSetTorque             llSetForce | ||||||
|  |  * SOP.ApplyImpulse     SOP.ApplyAngularImpulse     SOP.SetAngularImpulse   SOP.SetForce | ||||||
|  |  * SOG.ApplyImpulse     SOG.ApplyAngularImpulse     SOG.SetAngularImpulse | ||||||
|  |  * PA.AddForce          PA.AddAngularForce          PA.Torque = v           PA.Force = v | ||||||
|  |  * BS.ApplyCentralForce BS.ApplyTorque               | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
| public abstract class BSPhysObject : PhysicsActor | public abstract class BSPhysObject : PhysicsActor | ||||||
| { | { | ||||||
|     protected BSPhysObject() |     protected BSPhysObject() | ||||||
|  | @ -69,6 +79,12 @@ public abstract class BSPhysObject : PhysicsActor | ||||||
|         CollidingGroundStep = 0; |         CollidingGroundStep = 0; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Tell the object to clean up. | ||||||
|  |     public virtual void Destroy() | ||||||
|  |     { | ||||||
|  |         UnRegisterAllPreStepActions(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public BSScene PhysicsScene { get; protected set; } |     public BSScene PhysicsScene { get; protected set; } | ||||||
|     // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor |     // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | ||||||
|     public string PhysObjectName { get; protected set; } |     public string PhysObjectName { get; protected set; } | ||||||
|  | @ -130,9 +146,6 @@ public abstract class BSPhysObject : PhysicsActor | ||||||
|     // Update the physical location and motion of the object. Called with data from Bullet. |     // Update the physical location and motion of the object. Called with data from Bullet. | ||||||
|     public abstract void UpdateProperties(EntityProperties entprop); |     public abstract void UpdateProperties(EntityProperties entprop); | ||||||
| 
 | 
 | ||||||
|     // Tell the object to clean up. |  | ||||||
|     public abstract void Destroy(); |  | ||||||
| 
 |  | ||||||
|     public abstract OMV.Vector3 RawPosition { get; set; } |     public abstract OMV.Vector3 RawPosition { get; set; } | ||||||
|     public abstract OMV.Vector3 ForcePosition { get; set; } |     public abstract OMV.Vector3 ForcePosition { get; set; } | ||||||
| 
 | 
 | ||||||
|  | @ -140,7 +153,7 @@ public abstract class BSPhysObject : PhysicsActor | ||||||
|     public abstract OMV.Quaternion ForceOrientation { get; set; } |     public abstract OMV.Quaternion ForceOrientation { get; set; } | ||||||
| 
 | 
 | ||||||
|     // The system is telling us the velocity it wants to move at. |     // The system is telling us the velocity it wants to move at. | ||||||
|     protected OMV.Vector3 m_targetVelocity; |     // protected OMV.Vector3 m_targetVelocity;  // use the definition in PhysicsActor | ||||||
|     public override OMV.Vector3 TargetVelocity |     public override OMV.Vector3 TargetVelocity | ||||||
|     { |     { | ||||||
|         get { return m_targetVelocity; } |         get { return m_targetVelocity; } | ||||||
|  | @ -280,11 +293,53 @@ public abstract class BSPhysObject : PhysicsActor | ||||||
| 
 | 
 | ||||||
|     #endregion // Collisions |     #endregion // Collisions | ||||||
| 
 | 
 | ||||||
|  |     #region Per Simulation Step actions | ||||||
|  |     // There are some actions that must be performed for a physical object before each simulation step. | ||||||
|  |     // These actions are optional so, rather than scanning all the physical objects and asking them | ||||||
|  |     //     if they have anything to do, a physical object registers for an event call before the step is performed. | ||||||
|  |     // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||||||
|  |     private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>(); | ||||||
|  |     protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||||||
|  |     { | ||||||
|  |         string identifier = op + "-" + id.ToString(); | ||||||
|  |         RegisteredActions[identifier] = actn; | ||||||
|  |         PhysicsScene.BeforeStep += actn; | ||||||
|  |         DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Unregister a pre step action. Safe to call if the action has not been registered. | ||||||
|  |     protected void UnRegisterPreStepAction(string op, uint id) | ||||||
|  |     { | ||||||
|  |         string identifier = op + "-" + id.ToString(); | ||||||
|  |         bool removed = false; | ||||||
|  |         if (RegisteredActions.ContainsKey(identifier)) | ||||||
|  |         { | ||||||
|  |             PhysicsScene.BeforeStep -= RegisteredActions[identifier]; | ||||||
|  |             RegisteredActions.Remove(identifier); | ||||||
|  |             removed = true; | ||||||
|  |         } | ||||||
|  |         DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     protected void UnRegisterAllPreStepActions() | ||||||
|  |     { | ||||||
|  |         foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions) | ||||||
|  |         { | ||||||
|  |             PhysicsScene.BeforeStep -= kvp.Value; | ||||||
|  |         } | ||||||
|  |         RegisteredActions.Clear(); | ||||||
|  |         DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |      | ||||||
|  |     #endregion // Per Simulation Step actions | ||||||
|  | 
 | ||||||
|     // High performance detailed logging routine used by the physical objects. |     // High performance detailed logging routine used by the physical objects. | ||||||
|     protected void DetailLog(string msg, params Object[] args) |     protected void DetailLog(string msg, params Object[] args) | ||||||
|     { |     { | ||||||
|         if (PhysicsScene.PhysicsLogging.Enabled) |         if (PhysicsScene.PhysicsLogging.Enabled) | ||||||
|             PhysicsScene.DetailLog(msg, args); |             PhysicsScene.DetailLog(msg, args); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -129,6 +129,7 @@ public sealed class BSPrim : BSPhysObject | ||||||
|     public override void Destroy() |     public override void Destroy() | ||||||
|     { |     { | ||||||
|         // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |         // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | ||||||
|  |         base.Destroy(); | ||||||
| 
 | 
 | ||||||
|         // Undo any links between me and any other object |         // Undo any links between me and any other object | ||||||
|         BSPhysObject parentBefore = Linkset.LinksetRoot; |         BSPhysObject parentBefore = Linkset.LinksetRoot; | ||||||
|  | @ -434,12 +435,26 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         get { return _force; } |         get { return _force; } | ||||||
|         set { |         set { | ||||||
|             _force = value; |             _force = value; | ||||||
|             PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |             if (_force != OMV.Vector3.Zero) | ||||||
|             { |             { | ||||||
|                 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |                 // If the force is non-zero, it must be reapplied each tick because | ||||||
|  |                 //    Bullet clears the forces applied last frame. | ||||||
|  |                 RegisterPreStepAction("BSPrim.setForce", LocalID, | ||||||
|  |                     delegate(float timeStep) | ||||||
|  |                     { | ||||||
|  |                         DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||||||
|                         if (PhysBody.HasPhysicalBody) |                         if (PhysBody.HasPhysicalBody) | ||||||
|                     BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); |                         { | ||||||
|             }); |                             BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force); | ||||||
|  |                             ActivateIfPhysical(false); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -450,15 +465,18 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         set { |         set { | ||||||
|             Vehicle type = (Vehicle)value; |             Vehicle type = (Vehicle)value; | ||||||
| 
 | 
 | ||||||
|             // Tell the scene about the vehicle so it will get processing each frame. |  | ||||||
|             PhysicsScene.VehicleInSceneTypeChanged(this, type); |  | ||||||
| 
 |  | ||||||
|             PhysicsScene.TaintedObject("setVehicleType", delegate() |             PhysicsScene.TaintedObject("setVehicleType", delegate() | ||||||
|             { |             { | ||||||
|                 // Done at taint time so we're sure the physics engine is not using the variables |                 // Done at taint time so we're sure the physics engine is not using the variables | ||||||
|                 // Vehicle code changes the parameters for this vehicle type. |                 // Vehicle code changes the parameters for this vehicle type. | ||||||
|                 _vehicle.ProcessTypeChange(type); |                 _vehicle.ProcessTypeChange(type); | ||||||
|                 ActivateIfPhysical(false); |                 ActivateIfPhysical(false); | ||||||
|  | 
 | ||||||
|  |                 // If an active vehicle, register the vehicle code to be called before each step | ||||||
|  |                 if (_vehicle.Type == Vehicle.TYPE_NONE) | ||||||
|  |                     UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||||||
|  |                 else | ||||||
|  |                     RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -494,23 +512,6 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Called each simulation step to advance vehicle characteristics. |  | ||||||
|     // Called from Scene when doing simulation step so we're in taint processing time. |  | ||||||
|     public override void StepVehicle(float timeStep) |  | ||||||
|     { |  | ||||||
|         if (IsPhysical && _vehicle.IsActive) |  | ||||||
|         { |  | ||||||
|             _vehicle.Step(timeStep); |  | ||||||
|             /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step |  | ||||||
|             PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate() |  | ||||||
|             { |  | ||||||
|                 // This resets the interpolation values and recomputes the tensor variables |  | ||||||
|                 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation); |  | ||||||
|             }); |  | ||||||
|              */ |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |     // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||||||
|     public override void SetVolumeDetect(int param) { |     public override void SetVolumeDetect(int param) { | ||||||
|         bool newValue = (param != 0); |         bool newValue = (param != 0); | ||||||
|  | @ -543,14 +544,32 @@ public sealed class BSPrim : BSPhysObject | ||||||
| 
 | 
 | ||||||
|             _velocity = value; |             _velocity = value; | ||||||
|             if (PhysBody.HasPhysicalBody) |             if (PhysBody.HasPhysicalBody) | ||||||
|  |             { | ||||||
|                 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |                 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||||||
|  |                 ActivateIfPhysical(false); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     public override OMV.Vector3 Torque { |     public override OMV.Vector3 Torque { | ||||||
|         get { return _torque; } |         get { return _torque; } | ||||||
|         set { |         set { | ||||||
|             _torque = value; |             _torque = value; | ||||||
|             AddAngularForce(_torque, false, false); |             if (_torque != OMV.Vector3.Zero) | ||||||
|  |             { | ||||||
|  |                 // If the torque is non-zero, it must be reapplied each tick because | ||||||
|  |                 //    Bullet clears the forces applied last frame. | ||||||
|  |                 RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||||||
|  |                     delegate(float timeStep) | ||||||
|  |                     { | ||||||
|  |                         if (PhysBody.HasPhysicalBody) | ||||||
|  |                             AddAngularForce(_torque, false, true); | ||||||
|  |                     } | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||||||
|  |             } | ||||||
|             // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |             // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -720,10 +739,10 @@ public sealed class BSPrim : BSPhysObject | ||||||
|             // Mass is zero which disables a bunch of physics stuff in Bullet |             // Mass is zero which disables a bunch of physics stuff in Bullet | ||||||
|             UpdatePhysicalMassProperties(0f); |             UpdatePhysicalMassProperties(0f); | ||||||
|             // Set collision detection parameters |             // Set collision detection parameters | ||||||
|             if (PhysicsScene.Params.ccdMotionThreshold > 0f) |             if (BSParam.CcdMotionThreshold > 0f) | ||||||
|             { |             { | ||||||
|                 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |                 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||||||
|                 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |                 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // The activation state is 'disabled' so Bullet will not try to act on it. |             // The activation state is 'disabled' so Bullet will not try to act on it. | ||||||
|  | @ -761,17 +780,17 @@ public sealed class BSPrim : BSPhysObject | ||||||
|             UpdatePhysicalMassProperties(RawMass); |             UpdatePhysicalMassProperties(RawMass); | ||||||
| 
 | 
 | ||||||
|             // Set collision detection parameters |             // Set collision detection parameters | ||||||
|             if (PhysicsScene.Params.ccdMotionThreshold > 0f) |             if (BSParam.CcdMotionThreshold > 0f) | ||||||
|             { |             { | ||||||
|                 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |                 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||||||
|                 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |                 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // Various values for simulation limits |             // Various values for simulation limits | ||||||
|             BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); |             BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping); | ||||||
|             BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); |             BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime); | ||||||
|             BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |             BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | ||||||
|             BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |             BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); | ||||||
| 
 | 
 | ||||||
|             // This collides like an object. |             // This collides like an object. | ||||||
|             PhysBody.collisionType = CollisionType.Dynamic; |             PhysBody.collisionType = CollisionType.Dynamic; | ||||||
|  | @ -819,7 +838,7 @@ public sealed class BSPrim : BSPhysObject | ||||||
|     // Called in taint-time!! |     // Called in taint-time!! | ||||||
|     private void ActivateIfPhysical(bool forceIt) |     private void ActivateIfPhysical(bool forceIt) | ||||||
|     { |     { | ||||||
|         if (IsPhysical) |         if (IsPhysical && PhysBody.HasPhysicalBody) | ||||||
|             BulletSimAPI.Activate2(PhysBody.ptr, forceIt); |             BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -893,8 +912,7 @@ public sealed class BSPrim : BSPhysObject | ||||||
|             PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |             PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | ||||||
|             { |             { | ||||||
|                 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |                 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||||||
|                 if (PhysBody.HasPhysicalBody) |                 ForceRotationalVelocity = _rotationalVelocity; | ||||||
|                     BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |  | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -904,7 +922,11 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         } |         } | ||||||
|         set { |         set { | ||||||
|             _rotationalVelocity = value; |             _rotationalVelocity = value; | ||||||
|  |             if (PhysBody.HasPhysicalBody) | ||||||
|  |             { | ||||||
|                 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |                 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||||||
|  |                 ActivateIfPhysical(false); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     public override bool Kinematic { |     public override bool Kinematic { | ||||||
|  | @ -933,6 +955,7 @@ public sealed class BSPrim : BSPhysObject | ||||||
|             { |             { | ||||||
|                 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |                 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||||||
|                 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); |                 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||||||
|  |                 ActivateIfPhysical(false); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -969,56 +992,35 @@ public sealed class BSPrim : BSPhysObject | ||||||
|     public override float APIDStrength { set { return; } } |     public override float APIDStrength { set { return; } } | ||||||
|     public override float APIDDamping { set { return; } } |     public override float APIDDamping { set { return; } } | ||||||
| 
 | 
 | ||||||
|     private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); |  | ||||||
|     public override void AddForce(OMV.Vector3 force, bool pushforce) { |     public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||||||
|         AddForce(force, pushforce, false); |         AddForce(force, pushforce, false); | ||||||
|     } |     } | ||||||
|     // Applying a force just adds this to the total force on the object. |     // Applying a force just adds this to the total force on the object. | ||||||
|  |     // This added force will only last the next simulation tick. | ||||||
|     public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |     public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||||||
|         // for an object, doesn't matter if force is a pushforce or not |         // for an object, doesn't matter if force is a pushforce or not | ||||||
|         if (force.IsFinite()) |         if (force.IsFinite()) | ||||||
|         { |         { | ||||||
|             // _force += force; |             OMV.Vector3 addForce = force; | ||||||
|             lock (m_accumulatedForces) |             DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | ||||||
|                 m_accumulatedForces.Add(new OMV.Vector3(force)); |             PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | ||||||
|  |             { | ||||||
|  |                 // Bullet adds this central force to the total force for this tick | ||||||
|  |                 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | ||||||
|  |                 if (PhysBody.HasPhysicalBody) | ||||||
|  |                 { | ||||||
|  |                     BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce); | ||||||
|  |                     ActivateIfPhysical(false); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |             m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |  | ||||||
|         { |  | ||||||
|             OMV.Vector3 fSum = OMV.Vector3.Zero; |  | ||||||
|             lock (m_accumulatedForces) |  | ||||||
|             { |  | ||||||
|                 // Sum the accumulated additional forces for one big force to apply once. |  | ||||||
|                 foreach (OMV.Vector3 v in m_accumulatedForces) |  | ||||||
|                 { |  | ||||||
|                     fSum += v; |  | ||||||
|                 } |  | ||||||
|                 m_accumulatedForces.Clear(); |  | ||||||
|             } |  | ||||||
|             DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); |  | ||||||
|             if (fSum != OMV.Vector3.Zero) |  | ||||||
|                 if (PhysBody.HasPhysicalBody) |  | ||||||
|                     BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // An impulse force is scaled by the mass of the object. |  | ||||||
|     public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime) |  | ||||||
|     { |  | ||||||
|         OMV.Vector3 applyImpulse = impulse; |  | ||||||
|         PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() |  | ||||||
|         { |  | ||||||
|             DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); |  | ||||||
|             if (PhysBody.HasPhysicalBody) |  | ||||||
|                 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); |  | ||||||
|     public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |     public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||||||
|         AddAngularForce(force, pushforce, false); |         AddAngularForce(force, pushforce, false); | ||||||
|     } |     } | ||||||
|  | @ -1026,36 +1028,23 @@ public sealed class BSPrim : BSPhysObject | ||||||
|     { |     { | ||||||
|         if (force.IsFinite()) |         if (force.IsFinite()) | ||||||
|         { |         { | ||||||
|             // _force += force; |             OMV.Vector3 angForce = force; | ||||||
|             lock (m_accumulatedAngularForces) |             PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||||||
|                 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); |             { | ||||||
|  |                 if (PhysBody.HasPhysicalBody) | ||||||
|  |                 { | ||||||
|  |                     BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce); | ||||||
|  |                     ActivateIfPhysical(false); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |             m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |  | ||||||
|         { |  | ||||||
|             OMV.Vector3 fSum = OMV.Vector3.Zero; |  | ||||||
|             lock (m_accumulatedAngularForces) |  | ||||||
|             { |  | ||||||
|                 // Sum the accumulated additional forces for one big force to apply once. |  | ||||||
|                 foreach (OMV.Vector3 v in m_accumulatedAngularForces) |  | ||||||
|                 { |  | ||||||
|                     fSum += v; |  | ||||||
|                 } |  | ||||||
|                 m_accumulatedAngularForces.Clear(); |  | ||||||
|             } |  | ||||||
|             DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); |  | ||||||
|             if (fSum != OMV.Vector3.Zero) |  | ||||||
|             { |  | ||||||
|                 if (PhysBody.HasPhysicalBody) |  | ||||||
|                     BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); |  | ||||||
|                 _torque = fSum; |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     // A torque impulse. |     // A torque impulse. | ||||||
|     // ApplyTorqueImpulse adds torque directly to the angularVelocity. |     // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||||||
|     // AddAngularForce accumulates the force and applied it to the angular velocity all at once. |     // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||||||
|  | @ -1066,7 +1055,10 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |         PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | ||||||
|         { |         { | ||||||
|             if (PhysBody.HasPhysicalBody) |             if (PhysBody.HasPhysicalBody) | ||||||
|  |             { | ||||||
|                 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); |                 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||||||
|  |                 ActivateIfPhysical(false); | ||||||
|  |             } | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -1361,11 +1353,7 @@ public sealed class BSPrim : BSPhysObject | ||||||
|         } |         } | ||||||
|          */ |          */ | ||||||
| 
 | 
 | ||||||
|         if (returnMass <= 0) |         returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | ||||||
|             returnMass = 0.0001f; |  | ||||||
| 
 |  | ||||||
|         if (returnMass > PhysicsScene.MaximumObjectMass) |  | ||||||
|             returnMass = PhysicsScene.MaximumObjectMass; |  | ||||||
| 
 | 
 | ||||||
|         return returnMass; |         return returnMass; | ||||||
|     }// end CalculateMass |     }// end CalculateMass | ||||||
|  |  | ||||||
|  | @ -69,20 +69,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     //    every tick so OpenSim will update its animation. |     //    every tick so OpenSim will update its animation. | ||||||
|     private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); |     private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); | ||||||
| 
 | 
 | ||||||
|     // List of all the objects that have vehicle properties and should be called |  | ||||||
|     //    to update each physics step. |  | ||||||
|     private List<BSPhysObject> m_vehicles = new List<BSPhysObject>(); |  | ||||||
| 
 |  | ||||||
|     // let my minuions use my logger |     // let my minuions use my logger | ||||||
|     public ILog Logger { get { return m_log; } } |     public ILog Logger { get { return m_log; } } | ||||||
| 
 | 
 | ||||||
|     public IMesher mesher; |     public IMesher mesher; | ||||||
|     // Level of Detail values kept as float because that's what the Meshmerizer wants |  | ||||||
|     public float MeshLOD { get; private set; } |  | ||||||
|     public float MeshMegaPrimLOD { get; private set; } |  | ||||||
|     public float MeshMegaPrimThreshold { get; private set; } |  | ||||||
|     public float SculptLOD { get; private set; } |  | ||||||
| 
 |  | ||||||
|     public uint WorldID { get; private set; } |     public uint WorldID { get; private set; } | ||||||
|     public BulletSim World { get; private set; } |     public BulletSim World { get; private set; } | ||||||
| 
 | 
 | ||||||
|  | @ -90,24 +80,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     public BSConstraintCollection Constraints { get; private set; } |     public BSConstraintCollection Constraints { get; private set; } | ||||||
| 
 | 
 | ||||||
|     // Simulation parameters |     // Simulation parameters | ||||||
|     private int m_maxSubSteps; |     internal int m_maxSubSteps; | ||||||
|     private float m_fixedTimeStep; |     internal float m_fixedTimeStep; | ||||||
|     private long m_simulationStep = 0; |     internal long m_simulationStep = 0; | ||||||
|     public long SimulationStep { get { return m_simulationStep; } } |     public long SimulationStep { get { return m_simulationStep; } } | ||||||
|     private int m_taintsToProcessPerStep; |     internal int m_taintsToProcessPerStep; | ||||||
| 
 |     internal float LastTimeStep { get; private set; } | ||||||
|     // Avatar parameters |  | ||||||
|     public float ParamAvatarFriction { get; private set; } |  | ||||||
|     public float ParamAvatarStandingFriction { get; private set; } |  | ||||||
|     public float ParamAvatarDensity { get; private set; } |  | ||||||
|     public float ParamAvatarRestitution { get; private set; } |  | ||||||
|     public float ParamAvatarCapsuleWidth { get; private set; } |  | ||||||
|     public float ParamAvatarCapsuleDepth { get; private set; } |  | ||||||
|     public float ParamAvatarCapsuleHeight { get; private set; } |  | ||||||
| 	public float ParamAvatarContactProcessingThreshold { get; private set; } |  | ||||||
| 
 | 
 | ||||||
|  |     // Physical objects can register for prestep or poststep events | ||||||
|     public delegate void PreStepAction(float timeStep); |     public delegate void PreStepAction(float timeStep); | ||||||
|  |     public delegate void PostStepAction(float timeStep); | ||||||
|     public event PreStepAction BeforeStep; |     public event PreStepAction BeforeStep; | ||||||
|  |     public event PreStepAction AfterStep; | ||||||
| 
 | 
 | ||||||
|     // A value of the time now so all the collision and update routines do not have to get their own |     // A value of the time now so all the collision and update routines do not have to get their own | ||||||
|     // Set to 'now' just before all the prims and actors are called for collisions and updates |     // Set to 'now' just before all the prims and actors are called for collisions and updates | ||||||
|  | @ -121,20 +105,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     public bool InTaintTime { get; private set; } |     public bool InTaintTime { get; private set; } | ||||||
| 
 | 
 | ||||||
|     // Pinned memory used to pass step information between managed and unmanaged |     // Pinned memory used to pass step information between managed and unmanaged | ||||||
|     private int m_maxCollisionsPerFrame; |     internal int m_maxCollisionsPerFrame; | ||||||
|     private CollisionDesc[] m_collisionArray; |     internal CollisionDesc[] m_collisionArray; | ||||||
|     private GCHandle m_collisionArrayPinnedHandle; |     internal GCHandle m_collisionArrayPinnedHandle; | ||||||
| 
 | 
 | ||||||
|     private int m_maxUpdatesPerFrame; |     internal int m_maxUpdatesPerFrame; | ||||||
|     private EntityProperties[] m_updateArray; |     internal EntityProperties[] m_updateArray; | ||||||
|     private GCHandle m_updateArrayPinnedHandle; |     internal GCHandle m_updateArrayPinnedHandle; | ||||||
| 
 |  | ||||||
|     public bool ShouldMeshSculptedPrim { get; private set; }   // cause scuplted prims to get meshed |  | ||||||
|     public bool ShouldForceSimplePrimMeshing { get; private set; }   // if a cube or sphere, let Bullet do internal shapes |  | ||||||
|     public bool ShouldUseHullsForPhysicalObjects { get; private set; }   // 'true' if should create hulls for physical objects |  | ||||||
| 
 |  | ||||||
|     public float PID_D { get; private set; }    // derivative |  | ||||||
|     public float PID_P { get; private set; }    // proportional |  | ||||||
| 
 | 
 | ||||||
|     public const uint TERRAIN_ID = 0;       // OpenSim senses terrain with a localID of zero |     public const uint TERRAIN_ID = 0;       // OpenSim senses terrain with a localID of zero | ||||||
|     public const uint GROUNDPLANE_ID = 1; |     public const uint GROUNDPLANE_ID = 1; | ||||||
|  | @ -145,7 +122,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
| 
 | 
 | ||||||
|     public ConfigurationParameters Params |     public ConfigurationParameters Params | ||||||
|     { |     { | ||||||
|         get { return m_params[0]; } |         get { return UnmanagedParams[0]; } | ||||||
|     } |     } | ||||||
|     public Vector3 DefaultGravity |     public Vector3 DefaultGravity | ||||||
|     { |     { | ||||||
|  | @ -157,8 +134,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         get { return Params.gravity; } |         get { return Params.gravity; } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public float MaximumObjectMass { get; private set; } |  | ||||||
| 
 |  | ||||||
|     // When functions in the unmanaged code must be called, it is only |     // When functions in the unmanaged code must be called, it is only | ||||||
|     //   done at a known time just before the simulation step. The taint |     //   done at a known time just before the simulation step. The taint | ||||||
|     //   system saves all these function calls and executes them in |     //   system saves all these function calls and executes them in | ||||||
|  | @ -181,7 +156,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
| 
 | 
 | ||||||
|     // A pointer to an instance if this structure is passed to the C++ code |     // A pointer to an instance if this structure is passed to the C++ code | ||||||
|     // Used to pass basic configuration values to the unmanaged code. |     // Used to pass basic configuration values to the unmanaged code. | ||||||
|     ConfigurationParameters[] m_params; |     internal ConfigurationParameters[] UnmanagedParams; | ||||||
|     GCHandle m_paramsHandle; |     GCHandle m_paramsHandle; | ||||||
| 
 | 
 | ||||||
|     // Handle to the callback used by the unmanaged code to call into the managed code. |     // Handle to the callback used by the unmanaged code to call into the managed code. | ||||||
|  | @ -218,8 +193,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         Shapes = new BSShapeCollection(this); |         Shapes = new BSShapeCollection(this); | ||||||
| 
 | 
 | ||||||
|         // Allocate pinned memory to pass parameters. |         // Allocate pinned memory to pass parameters. | ||||||
|         m_params = new ConfigurationParameters[1]; |         UnmanagedParams = new ConfigurationParameters[1]; | ||||||
|         m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); |         m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); | ||||||
| 
 | 
 | ||||||
|         // Set default values for physics parameters plus any overrides from the ini file |         // Set default values for physics parameters plus any overrides from the ini file | ||||||
|         GetInitialParameterValues(config); |         GetInitialParameterValues(config); | ||||||
|  | @ -277,7 +252,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         TerrainManager = new BSTerrainManager(this); |         TerrainManager = new BSTerrainManager(this); | ||||||
|         TerrainManager.CreateInitialGroundPlaneAndTerrain(); |         TerrainManager.CreateInitialGroundPlaneAndTerrain(); | ||||||
| 
 | 
 | ||||||
|         m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); |         m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||||||
| 
 | 
 | ||||||
|         InTaintTime = false; |         InTaintTime = false; | ||||||
|         m_initialized = true; |         m_initialized = true; | ||||||
|  | @ -288,9 +263,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     private void GetInitialParameterValues(IConfigSource config) |     private void GetInitialParameterValues(IConfigSource config) | ||||||
|     { |     { | ||||||
|         ConfigurationParameters parms = new ConfigurationParameters(); |         ConfigurationParameters parms = new ConfigurationParameters(); | ||||||
|         m_params[0] = parms; |         UnmanagedParams[0] = parms; | ||||||
| 
 | 
 | ||||||
|         SetParameterDefaultValues(); |         BSParam.SetParameterDefaultValues(this); | ||||||
| 
 | 
 | ||||||
|         if (config != null) |         if (config != null) | ||||||
|         { |         { | ||||||
|  | @ -298,7 +273,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|             IConfig pConfig = config.Configs["BulletSim"]; |             IConfig pConfig = config.Configs["BulletSim"]; | ||||||
|             if (pConfig != null) |             if (pConfig != null) | ||||||
|             { |             { | ||||||
|                 SetParameterConfigurationValues(pConfig); |                 BSParam.SetParameterConfigurationValues(this, pConfig); | ||||||
| 
 | 
 | ||||||
|                 // Very detailed logging for physics debugging |                 // Very detailed logging for physics debugging | ||||||
|                 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); |                 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | ||||||
|  | @ -492,6 +467,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     // Simulate one timestep |     // Simulate one timestep | ||||||
|     public override float Simulate(float timeStep) |     public override float Simulate(float timeStep) | ||||||
|     { |     { | ||||||
|  |         // prevent simulation until we've been initialized | ||||||
|  |         if (!m_initialized) return 5.0f; | ||||||
|  | 
 | ||||||
|  |         LastTimeStep = timeStep; | ||||||
|  | 
 | ||||||
|         int updatedEntityCount = 0; |         int updatedEntityCount = 0; | ||||||
|         IntPtr updatedEntitiesPtr; |         IntPtr updatedEntitiesPtr; | ||||||
|         int collidersCount = 0; |         int collidersCount = 0; | ||||||
|  | @ -500,26 +480,27 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         int beforeTime = 0; |         int beforeTime = 0; | ||||||
|         int simTime = 0; |         int simTime = 0; | ||||||
| 
 | 
 | ||||||
|         // prevent simulation until we've been initialized |  | ||||||
|         if (!m_initialized) return 5.0f; |  | ||||||
| 
 |  | ||||||
|         // update the prim states while we know the physics engine is not busy |         // update the prim states while we know the physics engine is not busy | ||||||
|         int numTaints = _taintOperations.Count; |         int numTaints = _taintOperations.Count; | ||||||
|  | 
 | ||||||
|  |         InTaintTime = true; // Only used for debugging so locking is not necessary. | ||||||
|  | 
 | ||||||
|         ProcessTaints(); |         ProcessTaints(); | ||||||
| 
 | 
 | ||||||
|         // Some of the prims operate with special vehicle properties |         // Some of the physical objects requre individual, pre-step calls | ||||||
|         DoPreStepActions(timeStep); |         TriggerPreStepEvent(timeStep); | ||||||
| 
 | 
 | ||||||
|         // the prestep actions might have added taints |         // the prestep actions might have added taints | ||||||
|         ProcessTaints(); |         ProcessTaints(); | ||||||
| 
 | 
 | ||||||
|  |         InTaintTime = false; // Only used for debugging so locking is not necessary. | ||||||
|  | 
 | ||||||
|         // step the physical world one interval |         // step the physical world one interval | ||||||
|         m_simulationStep++; |         m_simulationStep++; | ||||||
|         int numSubSteps = 0; |         int numSubSteps = 0; | ||||||
| 
 | 
 | ||||||
|         try |         try | ||||||
|         { |         { | ||||||
|             if (VehiclePhysicalLoggingEnabled) DumpVehicles();  // DEBUG |  | ||||||
|             if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |             if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | ||||||
| 
 | 
 | ||||||
|             numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |             numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | ||||||
|  | @ -529,7 +510,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|             DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |             DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||||||
|                                     DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,  |                                     DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,  | ||||||
|                                     updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); |                                     updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||||||
|             if (VehiclePhysicalLoggingEnabled) DumpVehicles();  // DEBUG |  | ||||||
|         } |         } | ||||||
|         catch (Exception e) |         catch (Exception e) | ||||||
|         { |         { | ||||||
|  | @ -608,7 +588,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         ProcessPostStepTaints(); |         TriggerPostStepEvent(timeStep); | ||||||
| 
 | 
 | ||||||
|         // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |         // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | ||||||
|         // Only enable this in a limited test world with few objects. |         // Only enable this in a limited test world with few objects. | ||||||
|  | @ -700,6 +680,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     public override bool IsThreaded { get { return false;  } } |     public override bool IsThreaded { get { return false;  } } | ||||||
| 
 | 
 | ||||||
|     #region Taints |     #region Taints | ||||||
|  |     // The simulation execution order is: | ||||||
|  |     // Simulate() | ||||||
|  |     //    DoOneTimeTaints | ||||||
|  |     //    TriggerPreStepEvent | ||||||
|  |     //    DoOneTimeTaints | ||||||
|  |     //    Step() | ||||||
|  |     //       ProcessAndForwardCollisions | ||||||
|  |     //       ProcessAndForwardPropertyUpdates | ||||||
|  |     //    TriggerPostStepEvent | ||||||
| 
 | 
 | ||||||
|     // Calls to the PhysicsActors can't directly call into the physics engine |     // Calls to the PhysicsActors can't directly call into the physics engine | ||||||
|     //       because it might be busy. We delay changes to a known time. |     //       because it might be busy. We delay changes to a known time. | ||||||
|  | @ -726,58 +715,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|             TaintedObject(ident, callback); |             TaintedObject(ident, callback); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void TriggerPreStepEvent(float timeStep) | ||||||
|  |     { | ||||||
|  |         PreStepAction actions = BeforeStep; | ||||||
|  |         if (actions != null) | ||||||
|  |             actions(timeStep); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void TriggerPostStepEvent(float timeStep) | ||||||
|  |     { | ||||||
|  |         PreStepAction actions = AfterStep; | ||||||
|  |         if (actions != null) | ||||||
|  |             actions(timeStep); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     // When someone tries to change a property on a BSPrim or BSCharacter, the object queues |     // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | ||||||
|     // a callback into itself to do the actual property change. That callback is called |     // a callback into itself to do the actual property change. That callback is called | ||||||
|     // here just before the physics engine is called to step the simulation. |     // here just before the physics engine is called to step the simulation. | ||||||
|     public void ProcessTaints() |     public void ProcessTaints() | ||||||
|     { |     { | ||||||
|         InTaintTime = true; // Only used for debugging so locking is not necessary. |  | ||||||
|         ProcessRegularTaints(); |         ProcessRegularTaints(); | ||||||
|         ProcessPostTaintTaints(); |         ProcessPostTaintTaints(); | ||||||
|         InTaintTime = false; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void ProcessRegularTaints() |     private void ProcessRegularTaints() | ||||||
|     { |     { | ||||||
|         if (_taintOperations.Count > 0)  // save allocating new list if there is nothing to process |         if (_taintOperations.Count > 0)  // save allocating new list if there is nothing to process | ||||||
|         { |         { | ||||||
|             /* |  | ||||||
|             // Code to limit the number of taints processed per step. Meant to limit step time. |  | ||||||
|             // Unsure if a good idea as code assumes that taints are done before the step. |  | ||||||
|             int taintCount = m_taintsToProcessPerStep; |  | ||||||
|             TaintCallbackEntry oneCallback = new TaintCallbackEntry(); |  | ||||||
|             while (_taintOperations.Count > 0 && taintCount-- > 0) |  | ||||||
|             { |  | ||||||
|                 bool gotOne = false; |  | ||||||
|                 lock (_taintLock) |  | ||||||
|                 { |  | ||||||
|                     if (_taintOperations.Count > 0) |  | ||||||
|                     { |  | ||||||
|                         oneCallback = _taintOperations[0]; |  | ||||||
|                         _taintOperations.RemoveAt(0); |  | ||||||
|                         gotOne = true; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 if (gotOne) |  | ||||||
|                 { |  | ||||||
|                     try |  | ||||||
|                     { |  | ||||||
|                         DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); |  | ||||||
|                         oneCallback.callback(); |  | ||||||
|                     } |  | ||||||
|                     catch (Exception e) |  | ||||||
|                     { |  | ||||||
|                         DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG |  | ||||||
|                         m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             if (_taintOperations.Count > 0) |  | ||||||
|             { |  | ||||||
|                 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count); |  | ||||||
|             } |  | ||||||
|              */ |  | ||||||
| 
 |  | ||||||
|             // swizzle a new list into the list location so we can process what's there |             // swizzle a new list into the list location so we can process what's there | ||||||
|             List<TaintCallbackEntry> oldList; |             List<TaintCallbackEntry> oldList; | ||||||
|             lock (_taintLock) |             lock (_taintLock) | ||||||
|  | @ -816,6 +782,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Taints that happen after the normal taint processing but before the simulation step. | ||||||
|     private void ProcessPostTaintTaints() |     private void ProcessPostTaintTaints() | ||||||
|     { |     { | ||||||
|         if (_postTaintOperations.Count > 0) |         if (_postTaintOperations.Count > 0) | ||||||
|  | @ -843,45 +810,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void PostStepTaintObject(String ident, TaintCallback callback) |  | ||||||
|     { |  | ||||||
|         if (!m_initialized) return; |  | ||||||
| 
 |  | ||||||
|         lock (_taintLock) |  | ||||||
|         { |  | ||||||
|             _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private void ProcessPostStepTaints() |  | ||||||
|     { |  | ||||||
|         if (_postStepOperations.Count > 0) |  | ||||||
|         { |  | ||||||
|             List<TaintCallbackEntry> oldList; |  | ||||||
|             lock (_taintLock) |  | ||||||
|             { |  | ||||||
|                 oldList = _postStepOperations; |  | ||||||
|                 _postStepOperations = new List<TaintCallbackEntry>(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             foreach (TaintCallbackEntry tcbe in oldList) |  | ||||||
|             { |  | ||||||
|                 try |  | ||||||
|                 { |  | ||||||
|                     DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG |  | ||||||
|                     tcbe.callback(); |  | ||||||
|                 } |  | ||||||
|                 catch (Exception e) |  | ||||||
|                 { |  | ||||||
|                     m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             oldList.Clear(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Only used for debugging. Does not change state of anything so locking is not necessary. |     // Only used for debugging. Does not change state of anything so locking is not necessary. | ||||||
|     public bool AssertInTaintTime(string whereFrom) |     public bool AssertInTaintTime(string whereFrom) | ||||||
|     { |     { | ||||||
|  | @ -889,540 +817,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         { |         { | ||||||
|             DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |             DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||||||
|             m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |             m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||||||
|             Util.PrintCallStack();  // Prints the stack into the DEBUG log file. |             Util.PrintCallStack(DetailLog); | ||||||
|         } |         } | ||||||
|         return InTaintTime; |         return InTaintTime; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     #endregion // Taints |     #endregion // Taints | ||||||
| 
 | 
 | ||||||
|     #region Vehicles |  | ||||||
| 
 |  | ||||||
|     public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) |  | ||||||
|     { |  | ||||||
|         RemoveVehiclePrim(vehic); |  | ||||||
|         if (newType != Vehicle.TYPE_NONE) |  | ||||||
|         { |  | ||||||
|            // make it so the scene will call us each tick to do vehicle things |  | ||||||
|            AddVehiclePrim(vehic); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Make so the scene will call this prim for vehicle actions each tick. |  | ||||||
|     // Safe to call if prim is already in the vehicle list. |  | ||||||
|     public void AddVehiclePrim(BSPrim vehicle) |  | ||||||
|     { |  | ||||||
|         lock (m_vehicles) |  | ||||||
|         { |  | ||||||
|             if (!m_vehicles.Contains(vehicle)) |  | ||||||
|             { |  | ||||||
|                 m_vehicles.Add(vehicle); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Remove a prim from our list of vehicles. |  | ||||||
|     // Safe to call if the prim is not in the vehicle list. |  | ||||||
|     public void RemoveVehiclePrim(BSPrim vehicle) |  | ||||||
|     { |  | ||||||
|         lock (m_vehicles) |  | ||||||
|         { |  | ||||||
|             if (m_vehicles.Contains(vehicle)) |  | ||||||
|             { |  | ||||||
|                 m_vehicles.Remove(vehicle); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private void DoPreStepActions(float timeStep) |  | ||||||
|     { |  | ||||||
|         ProcessVehicles(timeStep); |  | ||||||
| 
 |  | ||||||
|         PreStepAction actions = BeforeStep; |  | ||||||
|         if (actions != null) |  | ||||||
|             actions(timeStep); |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Some prims have extra vehicle actions |  | ||||||
|     // Called at taint time! |  | ||||||
|     private void ProcessVehicles(float timeStep) |  | ||||||
|     { |  | ||||||
|         foreach (BSPhysObject pobj in m_vehicles) |  | ||||||
|         { |  | ||||||
|             pobj.StepVehicle(timeStep); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     #endregion Vehicles |  | ||||||
| 
 |  | ||||||
|     #region INI and command line parameter processing |     #region INI and command line parameter processing | ||||||
| 
 | 
 | ||||||
|     delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); |  | ||||||
|     delegate float ParamGet(BSScene scene); |  | ||||||
|     delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); |  | ||||||
|     delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); |  | ||||||
| 
 |  | ||||||
|     private struct ParameterDefn |  | ||||||
|     { |  | ||||||
|         public string name;         // string name of the parameter |  | ||||||
|         public string desc;         // a short description of what the parameter means |  | ||||||
|         public float defaultValue;  // default value if not specified anywhere else |  | ||||||
|         public ParamUser userParam; // get the value from the configuration file |  | ||||||
|         public ParamGet getter;     // return the current value stored for this parameter |  | ||||||
|         public ParamSet setter;     // set the current value for this parameter |  | ||||||
|         public SetOnObject onObject;    // set the value on an object in the physical domain |  | ||||||
|         public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) |  | ||||||
|         { |  | ||||||
|             name = n; |  | ||||||
|             desc = d; |  | ||||||
|             defaultValue = v; |  | ||||||
|             userParam = u; |  | ||||||
|             getter = g; |  | ||||||
|             setter = s; |  | ||||||
|             onObject = null; |  | ||||||
|         } |  | ||||||
|         public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) |  | ||||||
|         { |  | ||||||
|             name = n; |  | ||||||
|             desc = d; |  | ||||||
|             defaultValue = v; |  | ||||||
|             userParam = u; |  | ||||||
|             getter = g; |  | ||||||
|             setter = s; |  | ||||||
|             onObject = o; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // List of all of the externally visible parameters. |  | ||||||
|     // For each parameter, this table maps a text name to getter and setters. |  | ||||||
|     // To add a new externally referencable/settable parameter, add the paramter storage |  | ||||||
|     //    location somewhere in the program and make an entry in this table with the |  | ||||||
|     //    getters and setters. |  | ||||||
|     // It is easiest to find an existing definition and copy it. |  | ||||||
|     // Parameter values are floats. Booleans are converted to a floating value. |  | ||||||
|     // |  | ||||||
|     // A ParameterDefn() takes the following parameters: |  | ||||||
|     //    -- the text name of the parameter. This is used for console input and ini file. |  | ||||||
|     //    -- a short text description of the parameter. This shows up in the console listing. |  | ||||||
|     //    -- a delegate for fetching the parameter from the ini file. |  | ||||||
|     //          Should handle fetching the right type from the ini file and converting it. |  | ||||||
|     //    -- a delegate for getting the value as a float |  | ||||||
|     //    -- a delegate for setting the value from a float |  | ||||||
|     //    -- an optional delegate to update the value in the world. Most often used to |  | ||||||
|     //          push the new value to an in-world object. |  | ||||||
|     // |  | ||||||
|     // The single letter parameters for the delegates are: |  | ||||||
|     //    s = BSScene |  | ||||||
|     //    o = BSPhysObject |  | ||||||
|     //    p = string parameter name |  | ||||||
|     //    l = localID of referenced object |  | ||||||
|     //    v = float value |  | ||||||
|     //    cf = parameter configuration class (for fetching values from ini file) |  | ||||||
|     private ParameterDefn[] ParameterDefinitions = |  | ||||||
|     { |  | ||||||
|         new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", |  | ||||||
|             ConfigurationParameters.numericTrue, |  | ||||||
|             (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, |  | ||||||
|             (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); }, |  | ||||||
|             (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ), |  | ||||||
|         new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", |  | ||||||
|             ConfigurationParameters.numericFalse, |  | ||||||
|             (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, |  | ||||||
|             (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, |  | ||||||
|             (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), |  | ||||||
|         new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", |  | ||||||
|             ConfigurationParameters.numericTrue, |  | ||||||
|             (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, |  | ||||||
|             (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, |  | ||||||
|             (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |  | ||||||
|             8f, |  | ||||||
|             (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return s.MeshLOD; }, |  | ||||||
|             (s,p,l,v) => { s.MeshLOD = v; } ), |  | ||||||
|         new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", |  | ||||||
|             16f, |  | ||||||
|             (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return s.MeshMegaPrimLOD; }, |  | ||||||
|             (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ), |  | ||||||
|         new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", |  | ||||||
|             10f, |  | ||||||
|             (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return s.MeshMegaPrimThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ), |  | ||||||
|         new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", |  | ||||||
|             32f, |  | ||||||
|             (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return s.SculptLOD; }, |  | ||||||
|             (s,p,l,v) => { s.SculptLOD = v; } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", |  | ||||||
|             10f, |  | ||||||
|             (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return (float)s.m_maxSubSteps; }, |  | ||||||
|             (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), |  | ||||||
|         new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", |  | ||||||
|             1f / 60f, |  | ||||||
|             (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return (float)s.m_fixedTimeStep; }, |  | ||||||
|             (s,p,l,v) => { s.m_fixedTimeStep = v; } ), |  | ||||||
|         new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", |  | ||||||
|             2048f, |  | ||||||
|             (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return (float)s.m_maxCollisionsPerFrame; }, |  | ||||||
|             (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), |  | ||||||
|         new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", |  | ||||||
|             8000f, |  | ||||||
|             (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return (float)s.m_maxUpdatesPerFrame; }, |  | ||||||
|             (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |  | ||||||
|         new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", |  | ||||||
|             500f, |  | ||||||
|             (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return (float)s.m_taintsToProcessPerStep; }, |  | ||||||
|             (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), |  | ||||||
|         new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", |  | ||||||
|             10000.01f, |  | ||||||
|             (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return (float)s.MaximumObjectMass; }, |  | ||||||
|             (s,p,l,v) => { s.MaximumObjectMass = v; } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", |  | ||||||
|             2200f, |  | ||||||
|             (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return (float)s.PID_D; }, |  | ||||||
|             (s,p,l,v) => { s.PID_D = v; } ), |  | ||||||
|         new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", |  | ||||||
|             900f, |  | ||||||
|             (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return (float)s.PID_P; }, |  | ||||||
|             (s,p,l,v) => { s.PID_P = v; } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("DefaultFriction", "Friction factor used on new objects", |  | ||||||
|             0.2f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].defaultFriction; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), |  | ||||||
|         new ParameterDefn("DefaultDensity", "Density for new objects" , |  | ||||||
|             10.000006836f,  // Aluminum g/cm3 |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].defaultDensity; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ), |  | ||||||
|         new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].defaultRestitution; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), |  | ||||||
|         new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", |  | ||||||
|             0.04f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].collisionMargin; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), |  | ||||||
|         new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", |  | ||||||
|             -9.80665f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].gravity; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linearDamping; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ), |  | ||||||
|         new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].angularDamping; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ), |  | ||||||
|         new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |  | ||||||
|             0.2f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].deactivationTime; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), |  | ||||||
|         new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |  | ||||||
|             0.8f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linearSleepingThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), |  | ||||||
|         new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |  | ||||||
|             1.0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].angularSleepingThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), |  | ||||||
|         new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |  | ||||||
|             0f,     // set to zero to disable |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].ccdMotionThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), |  | ||||||
|         new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), |  | ||||||
|         new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |  | ||||||
|             0.1f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].contactProcessingThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, |  | ||||||
|             (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), |  | ||||||
| 
 |  | ||||||
| 	    new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", |  | ||||||
|             (float)BSTerrainPhys.TerrainImplementation.Mesh, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); }, |  | ||||||
|             (s) => { return s.m_params[0].terrainImplementation; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), |  | ||||||
|         new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |  | ||||||
|             0.3f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].terrainFriction; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].terrainFriction = v;  /* TODO: set on real terrain */} ), |  | ||||||
|         new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , |  | ||||||
|             0.8f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].terrainHitFraction; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), |  | ||||||
|         new ParameterDefn("TerrainRestitution", "Bouncyness" , |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].terrainRestitution; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].terrainRestitution = v;  /* TODO: set on real terrain */ } ), |  | ||||||
|         new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , |  | ||||||
|             0.04f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].terrainCollisionMargin; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v;  /* TODO: set on real terrain */ } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |  | ||||||
|             0.2f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarFriction; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |  | ||||||
|         new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |  | ||||||
|             10.0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarStandingFriction; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), |  | ||||||
|         new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |  | ||||||
|             60f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarDensity; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ), |  | ||||||
|         new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarRestitution; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), |  | ||||||
|         new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", |  | ||||||
|             0.6f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarCapsuleWidth; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ), |  | ||||||
|         new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", |  | ||||||
|             0.45f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarCapsuleDepth; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ), |  | ||||||
|         new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", |  | ||||||
|             1.5f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarCapsuleHeight; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), |  | ||||||
| 	    new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |  | ||||||
|             0.1f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |  | ||||||
|             (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", |  | ||||||
|             0.95f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].vehicleAngularDamping; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), |  | ||||||
| 
 |  | ||||||
| 	    new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), |  | ||||||
| 	    new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), |  | ||||||
| 	    new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", |  | ||||||
|             ConfigurationParameters.numericFalse, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ), |  | ||||||
| 	    new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", |  | ||||||
|             ConfigurationParameters.numericFalse, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), |  | ||||||
| 	    new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", |  | ||||||
|             ConfigurationParameters.numericTrue, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), |  | ||||||
| 	    new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", |  | ||||||
|             ConfigurationParameters.numericTrue, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), |  | ||||||
| 	    new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", |  | ||||||
|             ConfigurationParameters.numericFalse, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].shouldEnableFrictionCaching; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ), |  | ||||||
| 	    new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", |  | ||||||
|             0f,     // zero says use Bullet default |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].numberOfSolverIterations; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), |  | ||||||
| 
 |  | ||||||
| 	    new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", |  | ||||||
|             (float)BSLinkset.LinksetImplementation.Compound, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, |  | ||||||
|             (s) => { return s.m_params[0].linksetImplementation; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |  | ||||||
|             ConfigurationParameters.numericFalse, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintUseFrameOffset; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", |  | ||||||
|             ConfigurationParameters.numericTrue, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintEnableTransMotor; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", |  | ||||||
|             5.0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", |  | ||||||
|             0.1f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |  | ||||||
|             0.1f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintCFM; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |  | ||||||
|             0.1f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintERP; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |  | ||||||
| 	    new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", |  | ||||||
|             40, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); }, |  | ||||||
|             (s) => { return s.m_params[0].linkConstraintSolverIterations; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), |  | ||||||
| 
 |  | ||||||
|         new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", |  | ||||||
|             0f, |  | ||||||
|             (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, |  | ||||||
|             (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, |  | ||||||
|             (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     // Convert a boolean to our numeric true and false values |  | ||||||
|     public float NumericBool(bool b) |  | ||||||
|     { |  | ||||||
|         return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Convert numeric true and false values to a boolean |  | ||||||
|     public bool BoolNumeric(float b) |  | ||||||
|     { |  | ||||||
|         return (b == ConfigurationParameters.numericTrue ? true : false); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Search through the parameter definitions and return the matching |  | ||||||
|     //    ParameterDefn structure. |  | ||||||
|     // Case does not matter as names are compared after converting to lower case. |  | ||||||
|     // Returns 'false' if the parameter is not found. |  | ||||||
|     private bool TryGetParameter(string paramName, out ParameterDefn defn) |  | ||||||
|     { |  | ||||||
|         bool ret = false; |  | ||||||
|         ParameterDefn foundDefn = new ParameterDefn(); |  | ||||||
|         string pName = paramName.ToLower(); |  | ||||||
| 
 |  | ||||||
|         foreach (ParameterDefn parm in ParameterDefinitions) |  | ||||||
|         { |  | ||||||
|             if (pName == parm.name.ToLower()) |  | ||||||
|             { |  | ||||||
|                 foundDefn = parm; |  | ||||||
|                 ret = true; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         defn = foundDefn; |  | ||||||
|         return ret; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Pass through the settable parameters and set the default values |  | ||||||
|     private void SetParameterDefaultValues() |  | ||||||
|     { |  | ||||||
|         foreach (ParameterDefn parm in ParameterDefinitions) |  | ||||||
|         { |  | ||||||
|             parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Get user set values out of the ini file. |  | ||||||
|     private void SetParameterConfigurationValues(IConfig cfg) |  | ||||||
|     { |  | ||||||
|         foreach (ParameterDefn parm in ParameterDefinitions) |  | ||||||
|         { |  | ||||||
|             parm.userParam(this, cfg, parm.name, parm.defaultValue); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; |  | ||||||
| 
 |  | ||||||
|     // This creates an array in the correct format for returning the list of |  | ||||||
|     //    parameters. This is used by the 'list' option of the 'physics' command. |  | ||||||
|     private void BuildParameterTable() |  | ||||||
|     { |  | ||||||
|         if (SettableParameters.Length < ParameterDefinitions.Length) |  | ||||||
|         { |  | ||||||
|             List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); |  | ||||||
|             for (int ii = 0; ii < ParameterDefinitions.Length; ii++) |  | ||||||
|             { |  | ||||||
|                 ParameterDefn pd = ParameterDefinitions[ii]; |  | ||||||
|                 entries.Add(new PhysParameterEntry(pd.name, pd.desc)); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // make the list in alphabetical order for estetic reasons |  | ||||||
|             entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) |  | ||||||
|             { |  | ||||||
|                 return ppe1.name.CompareTo(ppe2.name); |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             SettableParameters = entries.ToArray(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     #region IPhysicsParameters |     #region IPhysicsParameters | ||||||
|     // Get the list of parameters this physics engine supports |     // Get the list of parameters this physics engine supports | ||||||
|     public PhysParameterEntry[] GetParameterList() |     public PhysParameterEntry[] GetParameterList() | ||||||
|     { |     { | ||||||
|         BuildParameterTable(); |         BSParam.BuildParameterTable(); | ||||||
|         return SettableParameters; |         return BSParam.SettableParameters; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Set parameter on a specific or all instances. |     // Set parameter on a specific or all instances. | ||||||
|  | @ -1434,8 +843,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     public bool SetPhysicsParameter(string parm, float val, uint localID) |     public bool SetPhysicsParameter(string parm, float val, uint localID) | ||||||
|     { |     { | ||||||
|         bool ret = false; |         bool ret = false; | ||||||
|         ParameterDefn theParam; |         BSParam.ParameterDefn theParam; | ||||||
|         if (TryGetParameter(parm, out theParam)) |         if (BSParam.TryGetParameter(parm, out theParam)) | ||||||
|         { |         { | ||||||
|             theParam.setter(this, parm, localID, val); |             theParam.setter(this, parm, localID, val); | ||||||
|             ret = true; |             ret = true; | ||||||
|  | @ -1447,19 +856,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     // If the local ID is APPLY_TO_NONE, just change the default value |     // If the local ID is APPLY_TO_NONE, just change the default value | ||||||
|     // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |     // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||||||
|     // If the localID is a specific object, apply the parameter change to only that object |     // If the localID is a specific object, apply the parameter change to only that object | ||||||
|     private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) |     internal delegate void AssignVal(float x); | ||||||
|  |     internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) | ||||||
|     { |     { | ||||||
|         List<uint> objectIDs = new List<uint>(); |         List<uint> objectIDs = new List<uint>(); | ||||||
|         switch (localID) |         switch (localID) | ||||||
|         { |         { | ||||||
|             case PhysParameterEntry.APPLY_TO_NONE: |             case PhysParameterEntry.APPLY_TO_NONE: | ||||||
|                 defaultLoc = val;   // setting only the default value |                 setDefault(val);            // setting only the default value | ||||||
|                 // This will cause a call into the physical world if some operation is specified (SetOnObject). |                 // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||||||
|                 objectIDs.Add(TERRAIN_ID); |                 objectIDs.Add(TERRAIN_ID); | ||||||
|                 TaintedUpdateParameter(parm, objectIDs, val); |                 TaintedUpdateParameter(parm, objectIDs, val); | ||||||
|                 break; |                 break; | ||||||
|             case PhysParameterEntry.APPLY_TO_ALL: |             case PhysParameterEntry.APPLY_TO_ALL: | ||||||
|                 defaultLoc = val;  // setting ALL also sets the default value |                 setDefault(val);  // setting ALL also sets the default value | ||||||
|                 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); |                 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||||||
|                 TaintedUpdateParameter(parm, objectIDs, val); |                 TaintedUpdateParameter(parm, objectIDs, val); | ||||||
|                 break; |                 break; | ||||||
|  | @ -1478,8 +888,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|         List<uint> xlIDs = lIDs; |         List<uint> xlIDs = lIDs; | ||||||
|         string xparm = parm; |         string xparm = parm; | ||||||
|         TaintedObject("BSScene.UpdateParameterSet", delegate() { |         TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||||||
|             ParameterDefn thisParam; |             BSParam.ParameterDefn thisParam; | ||||||
|             if (TryGetParameter(xparm, out thisParam)) |             if (BSParam.TryGetParameter(xparm, out thisParam)) | ||||||
|             { |             { | ||||||
|                 if (thisParam.onObject != null) |                 if (thisParam.onObject != null) | ||||||
|                 { |                 { | ||||||
|  | @ -1500,8 +910,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
|     { |     { | ||||||
|         float val = 0f; |         float val = 0f; | ||||||
|         bool ret = false; |         bool ret = false; | ||||||
|         ParameterDefn theParam; |         BSParam.ParameterDefn theParam; | ||||||
|         if (TryGetParameter(parm, out theParam)) |         if (BSParam.TryGetParameter(parm, out theParam)) | ||||||
|         { |         { | ||||||
|             val = theParam.getter(this); |             val = theParam.getter(this); | ||||||
|             ret = true; |             ret = true; | ||||||
|  | @ -1514,16 +924,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | ||||||
| 
 | 
 | ||||||
|     #endregion Runtime settable parameters |     #endregion Runtime settable parameters | ||||||
| 
 | 
 | ||||||
|     // Debugging routine for dumping detailed physical information for vehicle prims |  | ||||||
|     private void DumpVehicles() |  | ||||||
|     { |  | ||||||
|         foreach (BSPrim prim in m_vehicles) |  | ||||||
|         { |  | ||||||
|             BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); |  | ||||||
|             BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     // Invoke the detailed logger and output something if it's enabled. |     // Invoke the detailed logger and output something if it's enabled. | ||||||
|     public void DetailLog(string msg, params Object[] args) |     public void DetailLog(string msg, params Object[] args) | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -456,7 +456,7 @@ public sealed class BSShapeCollection : IDisposable | ||||||
|         if (!haveShape |         if (!haveShape | ||||||
|                 && pbs != null |                 && pbs != null | ||||||
|                 && nativeShapePossible |                 && nativeShapePossible | ||||||
|                 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) |                 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) | ||||||
|                     || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |                     || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||||||
|                         && pbs.ProfileHollow == 0 |                         && pbs.ProfileHollow == 0 | ||||||
|                         && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 |                         && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||||||
|  | @ -520,7 +520,7 @@ public sealed class BSShapeCollection : IDisposable | ||||||
|         bool ret = false; |         bool ret = false; | ||||||
|         // Note that if it's a native shape, the check for physical/non-physical is not |         // Note that if it's a native shape, the check for physical/non-physical is not | ||||||
|         //     made. Native shapes work in either case. |         //     made. Native shapes work in either case. | ||||||
|         if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) |         if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) | ||||||
|         { |         { | ||||||
|             // Update prim.BSShape to reference a hull of this shape. |             // Update prim.BSShape to reference a hull of this shape. | ||||||
|             ret = GetReferenceToHull(prim,shapeCallback); |             ret = GetReferenceToHull(prim,shapeCallback); | ||||||
|  | @ -836,14 +836,14 @@ public sealed class BSShapeCollection : IDisposable | ||||||
|     private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |     private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||||||
|     { |     { | ||||||
|         // level of detail based on size and type of the object |         // level of detail based on size and type of the object | ||||||
|         float lod = PhysicsScene.MeshLOD; |         float lod = BSParam.MeshLOD; | ||||||
|         if (pbs.SculptEntry) |         if (pbs.SculptEntry) | ||||||
|             lod = PhysicsScene.SculptLOD; |             lod = BSParam.SculptLOD; | ||||||
| 
 | 
 | ||||||
|         // Mega prims usually get more detail because one can interact with shape approximations at this size. |         // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||||||
|         float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); |         float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||||||
|         if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) |         if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||||||
|             lod = PhysicsScene.MeshMegaPrimLOD; |             lod = BSParam.MeshMegaPrimLOD; | ||||||
| 
 | 
 | ||||||
|         retLod = lod; |         retLod = lod; | ||||||
|         return pbs.GetMeshKey(size, lod); |         return pbs.GetMeshKey(size, lod); | ||||||
|  |  | ||||||
|  | @ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | ||||||
|     { |     { | ||||||
|         m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, |         m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | ||||||
|                                 m_mapInfo.minCoords, m_mapInfo.maxCoords,  |                                 m_mapInfo.minCoords, m_mapInfo.maxCoords,  | ||||||
|                                 m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); |                                 m_mapInfo.heightMap, BSParam.TerrainCollisionMargin); | ||||||
| 
 | 
 | ||||||
|         // Create the terrain shape from the mapInfo |         // Create the terrain shape from the mapInfo | ||||||
|         m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), |         m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | ||||||
|  | @ -110,9 +110,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | ||||||
|                                             m_mapInfo.ID, centerPos, Quaternion.Identity)); |                                             m_mapInfo.ID, centerPos, Quaternion.Identity)); | ||||||
| 
 | 
 | ||||||
|         // Set current terrain attributes |         // Set current terrain attributes | ||||||
|         BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); |         BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction); | ||||||
|         BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); |         BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction); | ||||||
|         BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); |         BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution); | ||||||
|         BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |         BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||||||
| 
 | 
 | ||||||
|         // Return the new terrain to the world of physical objects |         // Return the new terrain to the world of physical objects | ||||||
|  |  | ||||||
|  | @ -135,7 +135,7 @@ public sealed class BSTerrainManager : IDisposable | ||||||
|         // The ground plane is here to catch things that are trying to drop to negative infinity |         // The ground plane is here to catch things that are trying to drop to negative infinity | ||||||
|         BulletShape groundPlaneShape = new BulletShape( |         BulletShape groundPlaneShape = new BulletShape( | ||||||
|                     BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,  |                     BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,  | ||||||
|                                     PhysicsScene.Params.terrainCollisionMargin), |                                     BSParam.TerrainCollisionMargin), | ||||||
|                     BSPhysicsShapeType.SHAPE_GROUNDPLANE); |                     BSPhysicsShapeType.SHAPE_GROUNDPLANE); | ||||||
|         m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, |         m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | ||||||
|                         BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |                         BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | ||||||
|  | @ -309,9 +309,9 @@ public sealed class BSTerrainManager : IDisposable | ||||||
|     { |     { | ||||||
|         PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",  |         PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",  | ||||||
|                                             LogHeader, PhysicsScene.RegionName, terrainRegionBase,  |                                             LogHeader, PhysicsScene.RegionName, terrainRegionBase,  | ||||||
|                                             (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); |                                             (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | ||||||
|         BSTerrainPhys newTerrainPhys = null; |         BSTerrainPhys newTerrainPhys = null; | ||||||
|         switch ((int)PhysicsScene.Params.terrainImplementation) |         switch ((int)BSParam.TerrainImplementation) | ||||||
|         { |         { | ||||||
|             case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |             case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | ||||||
|                 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, |                 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | ||||||
|  | @ -324,8 +324,8 @@ public sealed class BSTerrainManager : IDisposable | ||||||
|             default: |             default: | ||||||
|                 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", |                 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | ||||||
|                                             LogHeader,  |                                             LogHeader,  | ||||||
|                                             (int)PhysicsScene.Params.terrainImplementation,  |                                             (int)BSParam.TerrainImplementation,  | ||||||
|                                             PhysicsScene.Params.terrainImplementation, |                                             BSParam.TerrainImplementation, | ||||||
|                                             PhysicsScene.RegionName, terrainRegionBase); |                                             PhysicsScene.RegionName, terrainRegionBase); | ||||||
|                 break; |                 break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -116,9 +116,9 @@ public sealed class BSTerrainMesh : BSTerrainPhys | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Set current terrain attributes |         // Set current terrain attributes | ||||||
|         BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); |         BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction); | ||||||
|         BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); |         BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction); | ||||||
|         BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); |         BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution); | ||||||
|         BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |         BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | ||||||
| 
 | 
 | ||||||
|         // Static objects are not very massive. |         // Static objects are not very massive. | ||||||
|  |  | ||||||
|  | @ -141,6 +141,8 @@ public struct EntityProperties | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Format of this structure must match the definition in the C++ code | // Format of this structure must match the definition in the C++ code | ||||||
|  | // NOTE: adding the X causes compile breaks if used. These are unused symbols | ||||||
|  | //      that can be removed from both here and the unmanaged definition of this structure. | ||||||
| [StructLayout(LayoutKind.Sequential)] | [StructLayout(LayoutKind.Sequential)] | ||||||
| public struct ConfigurationParameters | public struct ConfigurationParameters | ||||||
| { | { | ||||||
|  | @ -150,31 +152,31 @@ public struct ConfigurationParameters | ||||||
|     public float collisionMargin; |     public float collisionMargin; | ||||||
|     public float gravity; |     public float gravity; | ||||||
| 
 | 
 | ||||||
|     public float linearDamping; |     public float XlinearDamping; | ||||||
|     public float angularDamping; |     public float XangularDamping; | ||||||
|     public float deactivationTime; |     public float XdeactivationTime; | ||||||
|     public float linearSleepingThreshold; |     public float XlinearSleepingThreshold; | ||||||
|     public float angularSleepingThreshold; |     public float XangularSleepingThreshold; | ||||||
| 	public float ccdMotionThreshold; | 	public float XccdMotionThreshold; | ||||||
| 	public float ccdSweptSphereRadius; | 	public float XccdSweptSphereRadius; | ||||||
|     public float contactProcessingThreshold; |     public float XcontactProcessingThreshold; | ||||||
| 
 | 
 | ||||||
|     public float terrainImplementation; |     public float XterrainImplementation; | ||||||
|     public float terrainFriction; |     public float XterrainFriction; | ||||||
|     public float terrainHitFraction; |     public float XterrainHitFraction; | ||||||
|     public float terrainRestitution; |     public float XterrainRestitution; | ||||||
|     public float terrainCollisionMargin; |     public float XterrainCollisionMargin; | ||||||
| 
 | 
 | ||||||
|     public float avatarFriction; |     public float XavatarFriction; | ||||||
|     public float avatarStandingFriction; |     public float XavatarStandingFriction; | ||||||
|     public float avatarDensity; |     public float XavatarDensity; | ||||||
|     public float avatarRestitution; |     public float XavatarRestitution; | ||||||
|     public float avatarCapsuleWidth; |     public float XavatarCapsuleWidth; | ||||||
|     public float avatarCapsuleDepth; |     public float XavatarCapsuleDepth; | ||||||
|     public float avatarCapsuleHeight; |     public float XavatarCapsuleHeight; | ||||||
| 	public float avatarContactProcessingThreshold; | 	public float XavatarContactProcessingThreshold; | ||||||
| 
 | 
 | ||||||
|     public float vehicleAngularDamping; |     public float XvehicleAngularDamping; | ||||||
| 
 | 
 | ||||||
| 	public float maxPersistantManifoldPoolSize; | 	public float maxPersistantManifoldPoolSize; | ||||||
| 	public float maxCollisionAlgorithmPoolSize; | 	public float maxCollisionAlgorithmPoolSize; | ||||||
|  | @ -185,14 +187,14 @@ public struct ConfigurationParameters | ||||||
| 	public float shouldEnableFrictionCaching; | 	public float shouldEnableFrictionCaching; | ||||||
| 	public float numberOfSolverIterations; | 	public float numberOfSolverIterations; | ||||||
| 
 | 
 | ||||||
|     public float linksetImplementation; |     public float XlinksetImplementation; | ||||||
|     public float linkConstraintUseFrameOffset; |     public float XlinkConstraintUseFrameOffset; | ||||||
|     public float linkConstraintEnableTransMotor; |     public float XlinkConstraintEnableTransMotor; | ||||||
|     public float linkConstraintTransMotorMaxVel; |     public float XlinkConstraintTransMotorMaxVel; | ||||||
|     public float linkConstraintTransMotorMaxForce; |     public float XlinkConstraintTransMotorMaxForce; | ||||||
|     public float linkConstraintERP; |     public float XlinkConstraintERP; | ||||||
|     public float linkConstraintCFM; |     public float XlinkConstraintCFM; | ||||||
|     public float linkConstraintSolverIterations; |     public float XlinkConstraintSolverIterations; | ||||||
| 
 | 
 | ||||||
|     public float physicsLoggingFrames; |     public float physicsLoggingFrames; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -112,6 +112,9 @@ Test avatar walking up stairs. How does compare with SL. | ||||||
| Debounce avatar contact so legs don't keep folding up when standing. | Debounce avatar contact so legs don't keep folding up when standing. | ||||||
| Implement LSL physics controls. Like STATUS_ROTATE_X. | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||||||
| Add border extensions to terrain to help region crossings and objects leaving region. | Add border extensions to terrain to help region crossings and objects leaving region. | ||||||
|  | Use a different capsule shape for avatar when sitting | ||||||
|  | 	LL uses a pyrimidal shape scaled by the avatar's bounding box | ||||||
|  | 	http://wiki.secondlife.com/wiki/File:Avmeshforms.png | ||||||
| 
 | 
 | ||||||
| Performance test with lots of avatars. Can BulletSim support a thousand? | Performance test with lots of avatars. Can BulletSim support a thousand? | ||||||
| Optimize collisions in C++: only send up to the object subscribed to collisions. | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 Melanie
						Melanie