From ae4d932e7f00e781db9c9cdd5c29efc51e2425fb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 13:35:44 -0800 Subject: [PATCH 01/10] BulletSim: Move all the parameter variables, tables and get and fetch logic to a separate, static class for easier addition and to remove all that bulk from the BSScene class. --- .../Physics/BulletSPlugin/BSCharacter.cs | 30 +- .../Physics/BulletSPlugin/BSConstraint.cs | 2 +- .../Physics/BulletSPlugin/BSDynamics.cs | 2 +- .../Region/Physics/BulletSPlugin/BSLinkset.cs | 2 +- .../BulletSPlugin/BSLinksetConstraints.cs | 14 +- .../Region/Physics/BulletSPlugin/BSParam.cs | 558 ++++++++++++++++++ .../Region/Physics/BulletSPlugin/BSPrim.cs | 26 +- .../Region/Physics/BulletSPlugin/BSScene.cs | 549 ++--------------- .../BulletSPlugin/BSShapeCollection.cs | 12 +- .../BulletSPlugin/BSTerrainHeightmap.cs | 8 +- .../Physics/BulletSPlugin/BSTerrainManager.cs | 10 +- .../Physics/BulletSPlugin/BSTerrainMesh.cs | 6 +- .../Physics/BulletSPlugin/BulletSimAPI.cs | 62 +- 13 files changed, 678 insertions(+), 603 deletions(-) create mode 100755 OpenSim/Region/Physics/BulletSPlugin/BSParam.cs diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 57c5898e84..7bde1c12dc 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -88,8 +88,8 @@ public sealed class BSCharacter : BSPhysObject // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. _size = size; - if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; + if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; + if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; // A motor to control the acceleration and deceleration of the avatar movement. // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); @@ -108,8 +108,8 @@ public sealed class BSCharacter : BSPhysObject _velocity = OMV.Vector3.Zero; _appliedVelocity = OMV.Vector3.Zero; _buoyancy = ComputeBuoyancyFromFlying(isFlying); - _currentFriction = PhysicsScene.Params.avatarStandingFriction; - _avatarDensity = PhysicsScene.Params.avatarDensity; + _currentFriction = BSParam.AvatarStandingFriction; + _avatarDensity = BSParam.AvatarDensity; // The dimensions of the avatar capsule are kept in the scale. // Physics creates a unit capsule which is scaled by the physics engine. @@ -161,14 +161,14 @@ public sealed class BSCharacter : BSPhysObject // Needs to be reset especially when an avatar is recreated after crossing a region boundry. Flying = _flying; - BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); + BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution); BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); - BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); - if (PhysicsScene.Params.ccdMotionThreshold > 0f) + BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); + if (BSParam.CcdMotionThreshold > 0f) { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); + BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); + BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); } UpdatePhysicalMassProperties(RawMass); @@ -208,8 +208,8 @@ public sealed class BSCharacter : BSPhysObject _size = value; // Old versions of ScenePresence passed only the height. If width and/or depth are zero, // replace with the default values. - if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; - if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; + if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; + if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; ComputeAvatarScale(_size); ComputeAvatarVolumeAndMass(); @@ -468,18 +468,18 @@ public sealed class BSCharacter : BSPhysObject // to keep the avatar from slipping around if (_velocity.Length() == 0) { - if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) + if (_currentFriction != BSParam.AvatarStandingFriction) { - _currentFriction = PhysicsScene.Params.avatarStandingFriction; + _currentFriction = BSParam.AvatarStandingFriction; if (PhysBody.HasPhysicalBody) BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); } } else { - if (_currentFriction != PhysicsScene.Params.avatarFriction) + if (_currentFriction != BSParam.AvatarFriction) { - _currentFriction = PhysicsScene.Params.avatarFriction; + _currentFriction = BSParam.AvatarFriction; if (PhysBody.HasPhysicalBody) BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 6b1e304207..e77fb50206 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs @@ -122,7 +122,7 @@ public abstract class BSConstraint : IDisposable // Setting an object's mass to zero (making it static like when it's selected) // automatically disables the constraints. // 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 { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index a5acd86f89..e59ed8d390 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -563,7 +563,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // Moderate angular movement introduced by Bullet. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. // 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); // Vehicles report collision events so we know when it's on the ground diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 2017fa5656..8580928f15 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -56,7 +56,7 @@ public abstract class BSLinkset { BSLinkset ret = null; - switch ((int)physScene.Params.linksetImplementation) + switch ((int)BSParam.LinksetImplementation) { case (int)LinksetImplementation.Constraint: ret = new BSLinksetConstraints(physScene, parent); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 8c36c3153a..d95f223b71 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -226,14 +226,14 @@ public sealed class BSLinksetConstraints : BSLinkset constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); // tweek the constraint to increase stability - constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); - constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), - PhysicsScene.Params.linkConstraintTransMotorMaxVel, - PhysicsScene.Params.linkConstraintTransMotorMaxForce); - constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); - if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) + constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); + constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), + BSParam.LinkConstraintTransMotorMaxVel, + BSParam.LinkConstraintTransMotorMaxForce); + constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); + if (BSParam.LinkConstraintSolverIterations != 0f) { - constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); + constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); } return constrain; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs new file mode 100755 index 0000000000..1fb4c31c96 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -0,0 +1,558 @@ +/* + * 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 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 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 entries = new List(); + 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(); + } + } + + +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 68a0db6c82..e43bf8e72c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -720,10 +720,10 @@ public sealed class BSPrim : BSPhysObject // Mass is zero which disables a bunch of physics stuff in Bullet UpdatePhysicalMassProperties(0f); // Set collision detection parameters - if (PhysicsScene.Params.ccdMotionThreshold > 0f) + if (BSParam.CcdMotionThreshold > 0f) { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); + BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); + BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); } // The activation state is 'disabled' so Bullet will not try to act on it. @@ -761,17 +761,17 @@ public sealed class BSPrim : BSPhysObject UpdatePhysicalMassProperties(RawMass); // Set collision detection parameters - if (PhysicsScene.Params.ccdMotionThreshold > 0f) + if (BSParam.CcdMotionThreshold > 0f) { - BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); - BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); + BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); + BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); } // Various values for simulation limits - BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); - BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); - BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); - BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); + BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping); + BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime); + BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); + BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); // This collides like an object. PhysBody.collisionType = CollisionType.Dynamic; @@ -1361,11 +1361,7 @@ public sealed class BSPrim : BSPhysObject } */ - if (returnMass <= 0) - returnMass = 0.0001f; - - if (returnMass > PhysicsScene.MaximumObjectMass) - returnMass = PhysicsScene.MaximumObjectMass; + returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); return returnMass; }// end CalculateMass diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 2ca4912c8c..492a255f22 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -77,12 +77,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public ILog Logger { get { return m_log; } } 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 BulletSim World { get; private set; } @@ -90,21 +84,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public BSConstraintCollection Constraints { get; private set; } // Simulation parameters - private int m_maxSubSteps; - private float m_fixedTimeStep; - private long m_simulationStep = 0; + internal int m_maxSubSteps; + internal float m_fixedTimeStep; + internal long m_simulationStep = 0; public long SimulationStep { get { return m_simulationStep; } } - private int m_taintsToProcessPerStep; - - // 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; } + internal int m_taintsToProcessPerStep; public delegate void PreStepAction(float timeStep); public event PreStepAction BeforeStep; @@ -121,20 +105,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public bool InTaintTime { get; private set; } // Pinned memory used to pass step information between managed and unmanaged - private int m_maxCollisionsPerFrame; - private CollisionDesc[] m_collisionArray; - private GCHandle m_collisionArrayPinnedHandle; + internal int m_maxCollisionsPerFrame; + internal CollisionDesc[] m_collisionArray; + internal GCHandle m_collisionArrayPinnedHandle; - private int m_maxUpdatesPerFrame; - private EntityProperties[] m_updateArray; - private 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 + internal int m_maxUpdatesPerFrame; + internal EntityProperties[] m_updateArray; + internal GCHandle m_updateArrayPinnedHandle; public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero public const uint GROUNDPLANE_ID = 1; @@ -145,7 +122,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public ConfigurationParameters Params { - get { return m_params[0]; } + get { return UnmanagedParams[0]; } } public Vector3 DefaultGravity { @@ -157,8 +134,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters get { return Params.gravity; } } - public float MaximumObjectMass { get; private set; } - // When functions in the unmanaged code must be called, it is only // done at a known time just before the simulation step. The taint // 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 // Used to pass basic configuration values to the unmanaged code. - ConfigurationParameters[] m_params; + internal ConfigurationParameters[] UnmanagedParams; GCHandle m_paramsHandle; // 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); // Allocate pinned memory to pass parameters. - m_params = new ConfigurationParameters[1]; - m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); + UnmanagedParams = new ConfigurationParameters[1]; + m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned); // Set default values for physics parameters plus any overrides from the ini file GetInitialParameterValues(config); @@ -277,7 +252,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TerrainManager = new BSTerrainManager(this); 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; m_initialized = true; @@ -288,9 +263,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters private void GetInitialParameterValues(IConfigSource config) { ConfigurationParameters parms = new ConfigurationParameters(); - m_params[0] = parms; + UnmanagedParams[0] = parms; - SetParameterDefaultValues(); + BSParam.SetParameterDefaultValues(this); if (config != null) { @@ -298,7 +273,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters IConfig pConfig = config.Configs["BulletSim"]; if (pConfig != null) { - SetParameterConfigurationValues(pConfig); + BSParam.SetParameterConfigurationValues(this, pConfig); // Very detailed logging for physics debugging m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); @@ -889,7 +864,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { 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); - Util.PrintCallStack(); // Prints the stack into the DEBUG log file. + Util.PrintCallStack(DetailLog); // Prints the stack into the DEBUG log file. } return InTaintTime; } @@ -936,12 +911,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters private void DoPreStepActions(float timeStep) { + InTaintTime = true; // Only used for debugging so locking is not necessary. ProcessVehicles(timeStep); PreStepAction actions = BeforeStep; if (actions != null) actions(timeStep); + InTaintTime = false; + } // Some prims have extra vehicle actions @@ -957,472 +935,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters #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 entries = new List(); - 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 // Get the list of parameters this physics engine supports public PhysParameterEntry[] GetParameterList() { - BuildParameterTable(); - return SettableParameters; + BSParam.BuildParameterTable(); + return BSParam.SettableParameters; } // Set parameter on a specific or all instances. @@ -1434,8 +952,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public bool SetPhysicsParameter(string parm, float val, uint localID) { bool ret = false; - ParameterDefn theParam; - if (TryGetParameter(parm, out theParam)) + BSParam.ParameterDefn theParam; + if (BSParam.TryGetParameter(parm, out theParam)) { theParam.setter(this, parm, localID, val); ret = true; @@ -1447,19 +965,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // 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 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 objectIDs = new List(); switch (localID) { 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). objectIDs.Add(TERRAIN_ID); TaintedUpdateParameter(parm, objectIDs, val); break; 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(PhysObjects.Keys); TaintedUpdateParameter(parm, objectIDs, val); break; @@ -1478,8 +997,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters List xlIDs = lIDs; string xparm = parm; TaintedObject("BSScene.UpdateParameterSet", delegate() { - ParameterDefn thisParam; - if (TryGetParameter(xparm, out thisParam)) + BSParam.ParameterDefn thisParam; + if (BSParam.TryGetParameter(xparm, out thisParam)) { if (thisParam.onObject != null) { @@ -1500,8 +1019,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { float val = 0f; bool ret = false; - ParameterDefn theParam; - if (TryGetParameter(parm, out theParam)) + BSParam.ParameterDefn theParam; + if (BSParam.TryGetParameter(parm, out theParam)) { val = theParam.getter(this); ret = true; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index ea996ae59b..939d5e9797 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs @@ -456,7 +456,7 @@ public sealed class BSShapeCollection : IDisposable if (!haveShape && pbs != null && nativeShapePossible - && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) + && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 && pbs.ProfileHollow == 0 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 @@ -520,7 +520,7 @@ public sealed class BSShapeCollection : IDisposable bool ret = false; // Note that if it's a native shape, the check for physical/non-physical is not // 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. 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) { // level of detail based on size and type of the object - float lod = PhysicsScene.MeshLOD; + float lod = BSParam.MeshLOD; 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. float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); - if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) - lod = PhysicsScene.MeshMegaPrimLOD; + if (maxAxis > BSParam.MeshMegaPrimThreshold) + lod = BSParam.MeshMegaPrimLOD; retLod = lod; return pbs.GetMeshKey(size, lod); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 2b120d60db..07a9fd899c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs @@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys { m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, - m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); + m_mapInfo.heightMap, BSParam.TerrainCollisionMargin); // Create the terrain shape from the mapInfo 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)); // Set current terrain attributes - BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); - BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); - BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); + BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction); + BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction); + BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution); BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); // Return the new terrain to the world of physical objects diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 3428b9c0fa..86ccfbbf33 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -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 BulletShape groundPlaneShape = new BulletShape( BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, - PhysicsScene.Params.terrainCollisionMargin), + BSParam.TerrainCollisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); m_groundPlane = new BulletBody(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}", LogHeader, PhysicsScene.RegionName, terrainRegionBase, - (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); + (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); BSTerrainPhys newTerrainPhys = null; - switch ((int)PhysicsScene.Params.terrainImplementation) + switch ((int)BSParam.TerrainImplementation) { case (int)BSTerrainPhys.TerrainImplementation.Heightmap: newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, @@ -324,8 +324,8 @@ public sealed class BSTerrainManager : IDisposable default: PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", LogHeader, - (int)PhysicsScene.Params.terrainImplementation, - PhysicsScene.Params.terrainImplementation, + (int)BSParam.TerrainImplementation, + BSParam.TerrainImplementation, PhysicsScene.RegionName, terrainRegionBase); break; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index 6dc0d92857..061e232997 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -116,9 +116,9 @@ public sealed class BSTerrainMesh : BSTerrainPhys } // Set current terrain attributes - BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); - BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); - BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); + BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction); + BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction); + BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution); BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); // Static objects are not very massive. diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 962b5408f0..7857eaa411 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -141,6 +141,8 @@ public struct EntityProperties } // 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)] public struct ConfigurationParameters { @@ -150,31 +152,31 @@ public struct ConfigurationParameters public float collisionMargin; public float gravity; - public float linearDamping; - public float angularDamping; - public float deactivationTime; - public float linearSleepingThreshold; - public float angularSleepingThreshold; - public float ccdMotionThreshold; - public float ccdSweptSphereRadius; - public float contactProcessingThreshold; + public float XlinearDamping; + public float XangularDamping; + public float XdeactivationTime; + public float XlinearSleepingThreshold; + public float XangularSleepingThreshold; + public float XccdMotionThreshold; + public float XccdSweptSphereRadius; + public float XcontactProcessingThreshold; - public float terrainImplementation; - public float terrainFriction; - public float terrainHitFraction; - public float terrainRestitution; - public float terrainCollisionMargin; + public float XterrainImplementation; + public float XterrainFriction; + public float XterrainHitFraction; + public float XterrainRestitution; + public float XterrainCollisionMargin; - public float avatarFriction; - public float avatarStandingFriction; - public float avatarDensity; - public float avatarRestitution; - public float avatarCapsuleWidth; - public float avatarCapsuleDepth; - public float avatarCapsuleHeight; - public float avatarContactProcessingThreshold; + public float XavatarFriction; + public float XavatarStandingFriction; + public float XavatarDensity; + public float XavatarRestitution; + public float XavatarCapsuleWidth; + public float XavatarCapsuleDepth; + public float XavatarCapsuleHeight; + public float XavatarContactProcessingThreshold; - public float vehicleAngularDamping; + public float XvehicleAngularDamping; public float maxPersistantManifoldPoolSize; public float maxCollisionAlgorithmPoolSize; @@ -185,14 +187,14 @@ public struct ConfigurationParameters public float shouldEnableFrictionCaching; public float numberOfSolverIterations; - public float linksetImplementation; - public float linkConstraintUseFrameOffset; - public float linkConstraintEnableTransMotor; - public float linkConstraintTransMotorMaxVel; - public float linkConstraintTransMotorMaxForce; - public float linkConstraintERP; - public float linkConstraintCFM; - public float linkConstraintSolverIterations; + public float XlinksetImplementation; + public float XlinkConstraintUseFrameOffset; + public float XlinkConstraintEnableTransMotor; + public float XlinkConstraintTransMotorMaxVel; + public float XlinkConstraintTransMotorMaxForce; + public float XlinkConstraintERP; + public float XlinkConstraintCFM; + public float XlinkConstraintSolverIterations; public float physicsLoggingFrames; From 6dbf9c8ed4ca5646f47043f9937da5acbe124d0e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 15:21:32 -0800 Subject: [PATCH 02/10] BulletSim: repair vehicle problems introduced in previous 'improvements'. Fix line endings in BSParams. --- .../Physics/BulletSPlugin/BSDynamics.cs | 37 +- .../Region/Physics/BulletSPlugin/BSMotors.cs | 14 +- .../Region/Physics/BulletSPlugin/BSParam.cs | 1117 +++++++++-------- .../Region/Physics/BulletSPlugin/BSScene.cs | 2 +- 4 files changed, 598 insertions(+), 572 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index e59ed8d390..3fde57bed4 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -634,28 +634,33 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_knownHas = 0; m_knownChanged = 0; } + // Push all the changed values back into the physics engine private void PushKnownChanged() { if (m_knownChanged != 0) { if ((m_knownChanged & m_knownChangedPosition) != 0) - Prim.ForcePosition = VehiclePosition; + Prim.ForcePosition = m_knownPosition; + if ((m_knownChanged & m_knownChangedOrientation) != 0) - Prim.ForceOrientation = VehicleOrientation; + Prim.ForceOrientation = m_knownOrientation; + if ((m_knownChanged & m_knownChangedVelocity) != 0) { - Prim.ForceVelocity = VehicleVelocity; + Prim.ForceVelocity = m_knownVelocity; BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); } + if ((m_knownChanged & m_knownChangedForce) != 0) Prim.AddForce((Vector3)m_knownForce, false, true); 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. - BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity); + BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity); } + if ((m_knownChanged & m_knownChangedRotationalForce) != 0) 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 - // 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) { if ((m_knownHas & m_knownChangedTerrainHeight) == 0) @@ -699,12 +704,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_knownPosition = Prim.ForcePosition; m_knownHas |= m_knownChangedPosition; } - return (Vector3)m_knownPosition; + return m_knownPosition; } set { m_knownPosition = value; m_knownChanged |= m_knownChangedPosition; + m_knownHas |= m_knownChangedPosition; } } @@ -717,12 +723,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_knownOrientation = Prim.ForceOrientation; m_knownHas |= m_knownChangedOrientation; } - return (Quaternion)m_knownOrientation; + return m_knownOrientation; } set { m_knownOrientation = value; m_knownChanged |= m_knownChangedOrientation; + m_knownHas |= m_knownChangedOrientation; } } @@ -741,13 +748,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin { m_knownVelocity = value; m_knownChanged |= m_knownChangedVelocity; + m_knownHas |= m_knownChangedVelocity; } } private void VehicleAddForce(Vector3 aForce) { + if ((m_knownHas & m_knownChangedForce) == 0) + { + m_knownForce = Vector3.Zero; + } m_knownForce += aForce; m_knownChanged |= m_knownChangedForce; + m_knownHas |= m_knownChangedForce; } private Vector3 VehicleRotationalVelocity @@ -765,12 +778,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin { m_knownRotationalVelocity = value; m_knownChanged |= m_knownChangedRotationalVelocity; + m_knownHas |= m_knownChangedRotationalVelocity; } } private void VehicleAddAngularForce(Vector3 aForce) { + if ((m_knownHas & m_knownChangedRotationalForce) == 0) + { + m_knownRotationalForce = Vector3.Zero; + } m_knownRotationalForce += aForce; m_knownChanged |= m_knownChangedRotationalForce; + m_knownHas |= m_knownChangedRotationalForce; } // Vehicle relative forward velocity private Vector3 VehicleForwardVelocity @@ -782,7 +801,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); m_knownHas |= m_knownChangedForwardVelocity; } - return (Vector3)m_knownForwardVelocity; + return m_knownForwardVelocity; } } private float VehicleForwardSpeed diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 34a87c6c37..8781fe9628 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -268,12 +268,14 @@ public class BSPIDVMotor : BSVMotor public Vector3 proportionFactor { get; set; } public Vector3 integralFactor { get; set; } public Vector3 derivFactor { get; set; } + // Arbritrary factor range. // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. public float EfficiencyHigh = 0.4f; public float EfficiencyLow = 4.0f; - Vector3 IntegralFactor { get; set; } + // Running integration of the error + Vector3 RunningIntegration { get; set; } public BSPIDVMotor(string useName) : base(useName) @@ -281,7 +283,7 @@ public class BSPIDVMotor : BSVMotor proportionFactor = 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); - IntegralFactor = Vector3.Zero; + RunningIntegration = Vector3.Zero; LastError = Vector3.Zero; } @@ -312,14 +314,18 @@ public class BSPIDVMotor : BSVMotor public override Vector3 Step(float timeStep, Vector3 error) { // 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. Vector3 derivFactor = (error - LastError) * timeStep; LastError = error; // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) - Vector3 ret = -(error * proportionFactor + IntegralFactor * integralFactor + derivFactor * derivFactor); + Vector3 ret = -( + error * proportionFactor + + RunningIntegration * integralFactor + + derivFactor * derivFactor + ); return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 1fb4c31c96..5558ad5927 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs @@ -1,558 +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 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 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 entries = new List(); - 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(); - } - } - - -} -} +/* + * 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 entries = new List(); + 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(); + } + } + + +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 492a255f22..eb471788b9 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -864,7 +864,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { 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); - Util.PrintCallStack(DetailLog); // Prints the stack into the DEBUG log file. + Util.PrintCallStack(DetailLog); } return InTaintTime; } From 3d659fe97d79c04983dcfa8c78e9dde1623f54f2 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 17:27:53 -0800 Subject: [PATCH 03/10] BulletSim: add BSPhysObject code to manage registrations of preStep events. Use same to implement setForce and setTorque so the values are restored at the beginning of each step (since Bullet zeros forces applied last step). Simplify implementation of AddForce and AddTorque by relying on the addition of forces in Bullet. --- .../Physics/BulletSPlugin/BSCharacter.cs | 2 + .../Physics/BulletSPlugin/BSPhysObject.cs | 56 ++++++++- .../Region/Physics/BulletSPlugin/BSPrim.cs | 112 ++++++++---------- 3 files changed, 104 insertions(+), 66 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 7bde1c12dc..b392d75824 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -134,6 +134,8 @@ public sealed class BSCharacter : BSPhysObject // called when this character is being destroyed and the resources should be released public override void Destroy() { + base.Destroy(); + DetailLog("{0},BSCharacter.Destroy", LocalID); PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 92a5f2f054..9525a11def 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin * 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. */ + +/* + * 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 { protected BSPhysObject() @@ -69,6 +79,12 @@ public abstract class BSPhysObject : PhysicsActor CollidingGroundStep = 0; } + // Tell the object to clean up. + public virtual void Destroy() + { + UnRegisterAllPreStepActions(); + } + public BSScene PhysicsScene { get; protected set; } // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 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. 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 ForcePosition { get; set; } @@ -280,11 +293,48 @@ public abstract class BSPhysObject : PhysicsActor #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 RegisteredActions = new Dictionary(); + protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) + { + string identifier = op + "-" + id.ToString(); + RegisteredActions[identifier] = actn; + PhysicsScene.BeforeStep += actn; + } + + // 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(); + if (RegisteredActions.ContainsKey(identifier)) + { + PhysicsScene.BeforeStep -= RegisteredActions[identifier]; + RegisteredActions.Remove(identifier); + } + } + + protected void UnRegisterAllPreStepActions() + { + foreach (KeyValuePair kvp in RegisteredActions) + { + PhysicsScene.BeforeStep -= kvp.Value; + } + RegisteredActions.Clear(); + } + + + #endregion // Per Simulation Step actions + // High performance detailed logging routine used by the physical objects. protected void DetailLog(string msg, params Object[] args) { if (PhysicsScene.PhysicsLogging.Enabled) PhysicsScene.DetailLog(msg, args); } + } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e43bf8e72c..e6aeebb01d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -129,6 +129,7 @@ public sealed class BSPrim : BSPhysObject public override void Destroy() { // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); + base.Destroy(); // Undo any links between me and any other object BSPhysObject parentBefore = Linkset.LinksetRoot; @@ -434,12 +435,22 @@ public sealed class BSPrim : BSPhysObject get { return _force; } set { _force = value; - PhysicsScene.TaintedObject("BSPrim.setForce", delegate() + if (_force != OMV.Vector3.Zero) { - // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetObjectForce2(PhysBody.ptr, _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) + { + if (PhysBody.HasPhysicalBody) + BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force); + } + ); + } + else + { + UnRegisterPreStepAction("BSPrim.setForce", LocalID); + } } } @@ -550,7 +561,22 @@ public sealed class BSPrim : BSPhysObject get { return _torque; } set { _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); } } @@ -969,56 +995,32 @@ public sealed class BSPrim : BSPhysObject public override float APIDStrength { set { return; } } public override float APIDDamping { set { return; } } - private List m_accumulatedForces = new List(); public override void AddForce(OMV.Vector3 force, bool pushforce) { AddForce(force, pushforce, false); } // 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) { // for an object, doesn't matter if force is a pushforce or not if (force.IsFinite()) { - // _force += force; - lock (m_accumulatedForces) - m_accumulatedForces.Add(new OMV.Vector3(force)); + OMV.Vector3 addForce = force; + DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); + 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); + }); } else { m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 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 m_accumulatedAngularForces = new List(); public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { AddAngularForce(force, pushforce, false); } @@ -1026,36 +1028,20 @@ public sealed class BSPrim : BSPhysObject { if (force.IsFinite()) { - // _force += force; - lock (m_accumulatedAngularForces) - m_accumulatedAngularForces.Add(new OMV.Vector3(force)); + OMV.Vector3 angForce = force; + PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() + { + if (PhysBody.HasPhysicalBody) + BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce); + }); } else { m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 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. // ApplyTorqueImpulse adds torque directly to the angularVelocity. // AddAngularForce accumulates the force and applied it to the angular velocity all at once. From 37fb691ba56a72b95eeeacc13fb16c1f03af6006 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 23:03:27 -0800 Subject: [PATCH 04/10] BulletSim: Fix llApplyImpulse so it works after the first impulse. The problem was Bullet deactivating the object between the pushes (when, as far as the physics engine is concerned, it isn't moving). --- .../Physics/BulletSPlugin/BSPhysObject.cs | 5 ++++ .../Region/Physics/BulletSPlugin/BSPrim.cs | 28 ++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 9525a11def..19de1e559f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -304,17 +304,21 @@ public abstract class BSPhysObject : PhysicsActor 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() @@ -324,6 +328,7 @@ public abstract class BSPhysObject : PhysicsActor PhysicsScene.BeforeStep -= kvp.Value; } RegisteredActions.Clear(); + DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index e6aeebb01d..d137b2ace5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -442,8 +442,12 @@ public sealed class BSPrim : BSPhysObject RegisterPreStepAction("BSPrim.setForce", LocalID, delegate(float timeStep) { + DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); if (PhysBody.HasPhysicalBody) + { BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force); + ActivateIfPhysical(false); + } } ); } @@ -554,7 +558,10 @@ public sealed class BSPrim : BSPhysObject _velocity = value; if (PhysBody.HasPhysicalBody) + { BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); + ActivateIfPhysical(false); + } } } public override OMV.Vector3 Torque { @@ -845,7 +852,7 @@ public sealed class BSPrim : BSPhysObject // Called in taint-time!! private void ActivateIfPhysical(bool forceIt) { - if (IsPhysical) + if (IsPhysical && PhysBody.HasPhysicalBody) BulletSimAPI.Activate2(PhysBody.ptr, forceIt); } @@ -919,8 +926,7 @@ public sealed class BSPrim : BSPhysObject PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() { DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); - if (PhysBody.HasPhysicalBody) - BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); + ForceRotationalVelocity = _rotationalVelocity; }); } } @@ -930,7 +936,11 @@ public sealed class BSPrim : BSPhysObject } set { _rotationalVelocity = value; - BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); + if (PhysBody.HasPhysicalBody) + { + BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); + ActivateIfPhysical(false); + } } } public override bool Kinematic { @@ -959,6 +969,7 @@ public sealed class BSPrim : BSPhysObject { float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); + ActivateIfPhysical(false); } } } @@ -1011,7 +1022,10 @@ public sealed class BSPrim : BSPhysObject // 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 @@ -1032,7 +1046,10 @@ public sealed class BSPrim : BSPhysObject PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() { if (PhysBody.HasPhysicalBody) + { BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce); + ActivateIfPhysical(false); + } }); } else @@ -1052,7 +1069,10 @@ public sealed class BSPrim : BSPhysObject PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() { if (PhysBody.HasPhysicalBody) + { BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); + ActivateIfPhysical(false); + } }); } From a54392d7cc0c81d70d241393da8f50c409e9b895 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 23:05:05 -0800 Subject: [PATCH 05/10] BulletSim: remove the movement decay while flying. Made flying slow down over time. --- OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index b392d75824..01cd279a17 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -563,12 +563,6 @@ public sealed class BSCharacter : BSPhysObject set { _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 Buoyancy = ComputeBuoyancyFromFlying(_flying); } From 5b2cbc0ae69c041abb34d70fd03e4e1a4b7f4ea4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 21 Dec 2012 23:24:31 -0800 Subject: [PATCH 06/10] BulletSim: remove all special vehicle code from BSScene. Replace per-frame updates for vehicles with per-frame action registration. One fewer special case. --- .../Region/Physics/BulletSPlugin/BSPrim.cs | 26 ++--- .../Region/Physics/BulletSPlugin/BSScene.cs | 95 +++---------------- 2 files changed, 20 insertions(+), 101 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index d137b2ace5..26b8df5e06 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -465,15 +465,18 @@ public sealed class BSPrim : BSPhysObject set { 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() { // 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.ProcessTypeChange(type); 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); }); } } @@ -509,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 public override void SetVolumeDetect(int param) { bool newValue = (param != 0); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index eb471788b9..3a129a4b8a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -69,10 +69,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // every tick so OpenSim will update its animation. private HashSet m_avatars = new HashSet(); - // List of all the objects that have vehicle properties and should be called - // to update each physics step. - private List m_vehicles = new List(); - // let my minuions use my logger public ILog Logger { get { return m_log; } } @@ -480,21 +476,25 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // update the prim states while we know the physics engine is not busy int numTaints = _taintOperations.Count; + + InTaintTime = true; // Only used for debugging so locking is not necessary. + ProcessTaints(); - // Some of the prims operate with special vehicle properties + // Some of the physical objects requre individual, pre-step calls DoPreStepActions(timeStep); // the prestep actions might have added taints ProcessTaints(); + InTaintTime = false; // Only used for debugging so locking is not necessary. + // step the physical world one interval m_simulationStep++; int numSubSteps = 0; try { - if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, @@ -504,7 +504,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}", DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); - if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG } catch (Exception e) { @@ -701,15 +700,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TaintedObject(ident, callback); } + private void DoPreStepActions(float timeStep) + { + PreStepAction actions = BeforeStep; + if (actions != null) + actions(timeStep); + + } + // 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 // here just before the physics engine is called to step the simulation. public void ProcessTaints() { - InTaintTime = true; // Only used for debugging so locking is not necessary. ProcessRegularTaints(); ProcessPostTaintTaints(); - InTaintTime = false; } private void ProcessRegularTaints() @@ -871,68 +876,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters #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) - { - InTaintTime = true; // Only used for debugging so locking is not necessary. - ProcessVehicles(timeStep); - - PreStepAction actions = BeforeStep; - if (actions != null) - actions(timeStep); - - InTaintTime = false; - - } - - // 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 IPhysicsParameters @@ -1033,16 +976,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters #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. public void DetailLog(string msg, params Object[] args) { From 3e3c168987ba235ecb05079ed86e0ad3b6fe0dc8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 22 Dec 2012 17:04:53 -0800 Subject: [PATCH 07/10] Add helper routine Util.InRange() --- OpenSim/Framework/Util.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0c657c51eb..ea2d28a567 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -299,6 +299,13 @@ namespace OpenSim.Framework x; } + // Inclusive, within range test (true if equal to the endpoints) + public static bool InRange(T x, T min, T max) + where T : IComparable + { + return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0; + } + public static uint GetNextXferID() { uint id = 0; From 16e49035f7420979aa7f77ac63b951a32aa0bd6b Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 22 Dec 2012 17:06:13 -0800 Subject: [PATCH 08/10] BulletSim: add Enabled parameter and operation to motors. --- .../Region/Physics/BulletSPlugin/BSMotors.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 8781fe9628..9e1a9ba6e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -43,7 +43,9 @@ public abstract class BSMotor { UseName = useName; PhysicsScene = null; + Enabled = true; } + public virtual bool Enabled { get; set; } public virtual void Reset() { } public virtual void Zero() { } public virtual void GenerateTestOutput(float timeStep) { } @@ -98,6 +100,12 @@ public class BSVMotor : BSMotor public virtual Vector3 CurrentValue { 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) : base(useName) { @@ -105,7 +113,7 @@ public class BSVMotor : BSMotor Efficiency = 1f; FrictionTimescale = BSMotor.InfiniteVector; CurrentValue = TargetValue = Vector3.Zero; - ErrorZeroThreshold = 0.01f; + ErrorZeroThreshold = 0.001f; } public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) : this(useName) @@ -133,6 +141,8 @@ public class BSVMotor : BSMotor // Compute the next step and return the new current value public virtual Vector3 Step(float timeStep) { + if (!Enabled) return TargetValue; + Vector3 origTarget = TargetValue; // 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. 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); } @@ -186,6 +196,8 @@ public class BSVMotor : BSMotor } public virtual Vector3 Step(float timeStep, Vector3 error) { + if (!Enabled) return Vector3.Zero; + LastError = error; Vector3 returnCorrection = Vector3.Zero; if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) @@ -313,6 +325,8 @@ public class BSPIDVMotor : BSVMotor // Ignore Current and Target Values and just advance the PID computation on this 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 RunningIntegration += error * timeStep; From 144322a7c9e78a8df91c2e0026ade499b521e302 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 22 Dec 2012 17:07:52 -0800 Subject: [PATCH 09/10] BulletSim: remove post step one-time taints (doesn't make any sense). Rename pre and post step event invocation routines to Trigger* to be consistant. Remove old, unused code. --- .../Region/Physics/BulletSPlugin/BSScene.cs | 112 +++++------------- 1 file changed, 30 insertions(+), 82 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 3a129a4b8a..e8e0d50b57 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -85,9 +85,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters internal long m_simulationStep = 0; public long SimulationStep { get { return m_simulationStep; } } internal int m_taintsToProcessPerStep; + internal float LastTimeStep { get; private set; } + // Physical objects can register for prestep or poststep events public delegate void PreStepAction(float timeStep); + public delegate void PostStepAction(float timeStep); 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 // Set to 'now' just before all the prims and actors are called for collisions and updates @@ -463,6 +467,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Simulate one 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; IntPtr updatedEntitiesPtr; int collidersCount = 0; @@ -471,9 +480,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters int beforeTime = 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 int numTaints = _taintOperations.Count; @@ -482,7 +488,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters ProcessTaints(); // Some of the physical objects requre individual, pre-step calls - DoPreStepActions(timeStep); + TriggerPreStepEvent(timeStep); // the prestep actions might have added taints ProcessTaints(); @@ -582,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. // Only enable this in a limited test world with few objects. @@ -674,6 +680,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters public override bool IsThreaded { get { return false; } } #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 // because it might be busy. We delay changes to a known time. @@ -700,7 +715,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters TaintedObject(ident, callback); } - private void DoPreStepActions(float timeStep) + private void TriggerPreStepEvent(float timeStep) { PreStepAction actions = BeforeStep; if (actions != null) @@ -708,6 +723,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters } + 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 // 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. @@ -721,43 +744,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters { 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 List oldList; lock (_taintLock) @@ -796,6 +782,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters return; } + // Taints that happen after the normal taint processing but before the simulation step. private void ProcessPostTaintTaints() { if (_postTaintOperations.Count > 0) @@ -823,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 oldList; - lock (_taintLock) - { - oldList = _postStepOperations; - _postStepOperations = new List(); - } - - 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. public bool AssertInTaintTime(string whereFrom) { From 30807b81cc9f91917fd3b4bf8dc24a1622013afa Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 22 Dec 2012 17:09:40 -0800 Subject: [PATCH 10/10] BulletSim: modify avatar motor code to make falling movement better. Clean up some usages. Disable motor when done. --- .../Physics/BulletSPlugin/BSCharacter.cs | 75 ++++++++++--------- .../Physics/BulletSPlugin/BSPhysObject.cs | 2 +- .../Physics/BulletSPlugin/BulletSimTODO.txt | 3 + 3 files changed, 45 insertions(+), 35 deletions(-) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 01cd279a17..8e059eec19 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -158,6 +158,7 @@ public sealed class BSCharacter : BSPhysObject _velocityMotor.Reset(); _velocityMotor.SetCurrent(_velocity); _velocityMotor.SetTarget(_velocity); + _velocityMotor.Enabled = false; // 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. @@ -435,13 +436,13 @@ public sealed class BSCharacter : BSPhysObject OMV.Vector3 targetVel = value; PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() { - float timeStep = 0.089f; // DEBUG DEBUG FIX FIX FIX _velocityMotor.Reset(); _velocityMotor.SetTarget(targetVel); _velocityMotor.SetCurrent(_velocity); - // Compute a velocity value and make sure it gets pushed into the avatar. - // This makes sure the avatar will start from a stop. - ForceVelocity = _velocityMotor.Step(timeStep); + _velocityMotor.Enabled = true; + + // Make sure a property update happens next step so the motor gets incorporated. + BulletSimAPI.PushUpdate2(PhysBody.ptr); }); } } @@ -450,12 +451,15 @@ public sealed class BSCharacter : BSPhysObject get { return _velocity; } set { _velocity = value; - _velocityMotor.Reset(); - _velocityMotor.SetCurrent(_velocity); - _velocityMotor.SetTarget(_velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 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); ForceVelocity = _velocity; }); @@ -466,6 +470,7 @@ public sealed class BSCharacter : BSPhysObject set { PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); + _velocity = value; // Depending on whether the avatar is moving or not, change the friction // to keep the avatar from slipping around if (_velocity.Length() == 0) @@ -486,7 +491,6 @@ public sealed class BSCharacter : BSPhysObject BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); } } - _velocity = value; // Remember the set velocity so we can suppress the reduction by friction, ... _appliedVelocity = value; @@ -746,39 +750,42 @@ public sealed class BSCharacter : BSPhysObject _velocity = entprop.Velocity; _acceleration = entprop.Acceleration; _rotationalVelocity = entprop.RotationalVelocity; + // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 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 LastEntityProperties = CurrentEntityProperties; 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 Linkset.UpdateProperties(this, true); diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 19de1e559f..c76f869d81 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -153,7 +153,7 @@ public abstract class BSPhysObject : PhysicsActor public abstract OMV.Quaternion ForceOrientation { get; set; } // 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 { get { return m_targetVelocity; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index c084ab4e2b..9a7e965246 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt @@ -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. Implement LSL physics controls. Like STATUS_ROTATE_X. 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? Optimize collisions in C++: only send up to the object subscribed to collisions.