From ae67435146d65e1241c15677952f7d4a05ee794c Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Wed, 19 Dec 2012 01:51:30 +0000
Subject: Disable UDPPacketBuffer pooling for now to resolve an issue on
 Windows of interference between incoming packets.

On Windows, concurrent multi-threaded processing of inbound UDP somehow allows different data input processing to interfere with each other.
Possibly the endpoint reference is being switched, though I don't yet know the mechanism.  Not seen on Mono.
Also resolveable by setting RecyclePackets = false or RecycleBaseUDPPackets = false in [PacketPool]
Or async_packet_handling = false in [ClientStack.LindenUDP]
For now, will simply disable this particular pooling though will revisit this issue.
In response to http://opensimulator.org/mantis/view.php?id=6468
---
 OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
index 3f7ca2b..f143c32 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/OpenSimUDPBase.cs
@@ -208,9 +208,12 @@ namespace OpenMetaverse
         {
             UDPPacketBuffer buf;
 
-            if (UsePools)
-                buf = Pool.GetObject();
-            else
+            // FIXME: Disabled for now as this causes issues with reused packet objects interfering with each other 
+            // on Windows with m_asyncPacketHandling = true, though this has not been seen on Linux.
+            // Possibly some unexpected issue with fetching UDP data concurrently with multiple threads.  Requires more investigation.
+//            if (UsePools)
+//                buf = Pool.GetObject();
+//            else
                 buf = new UDPPacketBuffer();
 
             if (IsRunningInbound)
@@ -291,8 +294,8 @@ namespace OpenMetaverse
                 catch (ObjectDisposedException) { }
                 finally
                 {
-                    if (UsePools)
-                        Pool.ReturnObject(buffer);
+//                    if (UsePools)
+//                        Pool.ReturnObject(buffer);
 
                     // Synchronous mode waits until the packet callback completes
                     // before starting the receive to fetch another packet
-- 
cgit v1.1


From d15bfcf61404914c3d64c965db9e66295655bea5 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Tue, 18 Dec 2012 14:59:41 -0800
Subject: Replace axis rotation numeric constants (STATUS_ROTATE_XYZ) with
 symbols. Also made it so llSetStatus() can individually enable disable
 rotation axi using the bitmask of flags.

---
 OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs          |  9 +++++++++
 OpenSim/Region/Framework/Scenes/SceneObjectPart.cs           | 12 ++++++------
 .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs |  7 ++++---
 3 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 64a5811..35e7c45 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -99,6 +99,15 @@ namespace OpenSim.Region.Framework.Scenes
     /// </summary>
     public partial class SceneObjectGroup : EntityBase, ISceneObject
     {
+        // Axis selection bitmask used by SetAxisRotation()
+        // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
+        public enum axisSelect : int
+        {
+            STATUS_ROTATE_X = 0x002,
+            STATUS_ROTATE_Y = 0x004,
+            STATUS_ROTATE_Z = 0x008,
+        }
+
         // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
 
         /// <summary>
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index af7fae3..7a97e5f 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -1918,11 +1918,11 @@ namespace OpenSim.Region.Framework.Scenes
         public int GetAxisRotation(int axis)
         {
             //Cannot use ScriptBaseClass constants as no referance to it currently.
-            if (axis == 2)//STATUS_ROTATE_X
+            if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
                 return STATUS_ROTATE_X;
-            if (axis == 4)//STATUS_ROTATE_Y
+            if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
                 return STATUS_ROTATE_Y;
-            if (axis == 8)//STATUS_ROTATE_Z
+            if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
                 return STATUS_ROTATE_Z;
 
             return 0;
@@ -2671,13 +2671,13 @@ namespace OpenSim.Region.Framework.Scenes
             ParentGroup.SetAxisRotation(axis, rotate);
 
             //Cannot use ScriptBaseClass constants as no referance to it currently.
-            if (axis == 2)//STATUS_ROTATE_X
+            if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
                 STATUS_ROTATE_X = rotate;
 
-            if (axis == 4)//STATUS_ROTATE_Y
+            if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
                 STATUS_ROTATE_Y = rotate;
 
-            if (axis == 8)//STATUS_ROTATE_Z
+            if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
                 STATUS_ROTATE_Z = rotate;
         }
 
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 4108588..837779d 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -1334,19 +1334,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
                         return 0;
 
                 case ScriptBaseClass.STATUS_ROTATE_X:
-                    if (m_host.GetAxisRotation(2) == 2)
+                    // if (m_host.GetAxisRotation(2) != 0)
+                    if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
                         return 1;
                     else
                         return 0;
 
                 case ScriptBaseClass.STATUS_ROTATE_Y:
-                    if (m_host.GetAxisRotation(4) == 4)
+                    if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
                         return 1;
                     else
                         return 0;
 
                 case ScriptBaseClass.STATUS_ROTATE_Z:
-                    if (m_host.GetAxisRotation(8) == 8)
+                    if (m_host.GetAxisRotation((int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
                         return 1;
                     else
                         return 0;
-- 
cgit v1.1


From cf89e29ac315cbac74361b8fd85e0fdbf6157f09 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Tue, 18 Dec 2012 19:19:58 -0800
Subject: BulletSim: comments and TODO list update

---
 OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs         | 9 +++++++--
 OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | 3 ++-
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 758d92b..1c6f946 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -100,10 +100,15 @@ public sealed class BSPrim : BSPhysObject
         BaseShape = pbs;
         _isPhysical = pisPhysical;
         _isVolumeDetect = false;
-        _friction = PhysicsScene.Params.defaultFriction;  // TODO: compute based on object material
-        _density = PhysicsScene.Params.defaultDensity;    // TODO: compute based on object material
+
+        // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
+        // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
+        _density = PhysicsScene.Params.defaultDensity;
+        _friction = PhysicsScene.Params.defaultFriction;
         _restitution = PhysicsScene.Params.defaultRestitution;
+
         _vehicle = new BSDynamics(PhysicsScene, this);            // add vehicleness
+
         _mass = CalculateMass();
 
         // No body or shape yet
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 0d9a156..ad4e42b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -6,7 +6,7 @@ Eliminate all crashes (DONEish)
 Enable vehicle border crossings (at least as poorly as ODE)
 	Avatar created in previous region and not new region when crossing border
 	Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
-Calibrate turning radius
+Calibrate turning radius (DONE)
 limitMotorUp calibration (more down?)
 study PID motors (include 'efficiency' implementation
 	Add to avatar movement
@@ -82,6 +82,7 @@ Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
 	Also osGetPhysicsEngineVerion() maybe.
 Linkset.Position and Linkset.Orientation requre rewrite to properly return
 	child position. LinksetConstraint acts like it's at taint time!!
+Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
 
 LINKSETS
 ======================================================
-- 
cgit v1.1


From 7b84bcfbb8817feca25f33db85bee6c1fc7f0b98 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Tue, 18 Dec 2012 22:59:59 -0800
Subject: BulletSim: initial implementation of a PID motor. Not hooked up yet.

---
 OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 44 ++++++++++++++++++++----
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index e0faf4e..c718228 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -117,12 +117,12 @@ public class BSVMotor : BSMotor
 
     // A form of stepping that does not take the time quantum into account.
     // The caller must do the right thing later.
-    public Vector3 Step()
+    public virtual Vector3 Step()
     {
         return Step(1f);
     }
 
-    public Vector3 Step(float timeStep)
+    public virtual Vector3 Step(float timeStep)
     {
         Vector3 returnCurrent = Vector3.Zero;
         if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
@@ -204,17 +204,49 @@ public class BSFMotor : BSMotor
     public void SetTarget(float target)
     {
     }
-    public float Step(float timeStep)
+    public virtual float Step(float timeStep)
     {
         return 0f;
     }
 }
-public class BSPIDMotor : BSMotor
+
+// Proportional, Integral, Derivitive Motor
+// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
+public class BSPIDVMotor : BSVMotor
 {
-    // TODO: write and use this one
-    public BSPIDMotor(string useName)
+    public Vector3 pFactor { get; set; }    // Amount of direct correction of an error (sometimes called 'proportional gain')
+    public Vector3 iFactor { get; set; }    // 
+    public Vector3 dFactor { get; set; }
+
+    Vector3 IntegralFactor { get; set; }
+    Vector3 LastError { get; set; }
+
+    public BSPIDVMotor(string useName)
         : base(useName)
     {
+        // larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
+        pFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        iFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        dFactor = new Vector3(1.00f, 1.00f, 1.00f);
+    }
+
+    public override Vector3 Step(float timeStep)
+    {
+        // How far are we from where we should be
+        Vector3 error = TargetValue - CurrentValue;
+
+        // Add up the error so we can integrate over the accumulated errors
+        IntegralFactor += error * timeStep;
+
+        // A simple derivitive is the rate of change from the last error.
+        Vector3 derivFactor = (error - LastError) * timeStep;
+        LastError = error;
+
+        //                   Proportion                  Integral               Derivitive
+        // Correction = proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError
+        Vector3 ret =        error * pFactor    + IntegralFactor * iFactor + derivFactor * dFactor;
+
+        return ret;
     }
 }
 }
-- 
cgit v1.1


From a9b9c0f0351a6749bf55c29b2891fa40928b4c39 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Tue, 18 Dec 2012 23:05:59 -0800
Subject: BulletSim: improve angularVerticalAttraction calculation to compute
 angular correction velocity rather than estimating correction (excuse to use
 trig functions).

---
 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 33 ++++++++++------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5887249..912aadd 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -1003,7 +1003,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
                 // Not colliding if the vehicle is off the ground
                 if (!Prim.IsColliding)
                 {
-                    // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
                     // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
                     ret = new Vector3(0, 0, -distanceAboveGround);
                 }
@@ -1135,31 +1134,30 @@ namespace OpenSim.Region.Physics.BulletSPlugin
                 //         zero and one.
                 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
 
+                // Y error means needed rotation around X axis and visa versa.
+                // Since the error goes from zero to one, the asin is the corresponding angle.
+                ret.X = (float)Math.Asin(verticalError.Y);
+                ret.Y = (float)Math.Asin(verticalError.X);
+
                 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
                 if (verticalError.Z < 0f)
                 {
-                    verticalError.X = 2f - verticalError.X;
-                    verticalError.Y = 2f - verticalError.Y;
+                    ret.X += (float)Math.PI / 4f;
+                    ret.Y += (float)Math.PI / 4f;
                 }
 
-                // Y error means needed rotation around X axis and visa versa.
-                ret.X =    verticalError.Y;
-                ret.Y =  - verticalError.X;
-                ret.Z = 0f;
-
-                // Scale the correction force by how far we're off from vertical.
-                // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over.
-                float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f);
-                float vertForce = 1f / clampedSqrZError;
-
-                ret *= vertForce;
+                // Put the signs back on so the rotation is in the correct direction.
+                ret.X *= (float)Math.Sign(verticalError.Y);
+                // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
+                ret.Y *= -(float)Math.Sign(verticalError.X);
 
-                // Correction happens over a number of seconds.
+                // 'ret' is now the necessary velocity to correct tilt in one second.
+                //     Correction happens over a number of seconds.
                 Vector3 unscaledContrib = ret;
                 ret /= m_verticalAttractionTimescale;
 
-                VDetailLog("{0},  MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}",
-                                Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret);
+                VDetailLog("{0},  MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},vertAttr={4}",
+                                Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, ret);
             }
             return ret;
         }
@@ -1172,7 +1170,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         public Vector3 ComputeAngularDeflection()
         {
             Vector3 ret = Vector3.Zero;
-            return ret;     // DEBUG DEBUG DEBUG  debug one force at a time
 
             if (m_angularDeflectionEfficiency != 0)
             {
-- 
cgit v1.1


From b7ad44e3a687041a5a4761f1d0739a4226a901c2 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Thu, 20 Dec 2012 08:35:36 -0800
Subject: BulletSim: reorganize motor step code to separate error computation
 allowing subclass for PID error correction.

---
 OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 142 +++++++++++++++--------
 1 file changed, 91 insertions(+), 51 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index c718228..b57d2c8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -29,13 +29,14 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 using OpenMetaverse;
+using OpenSim.Framework;
 
 namespace OpenSim.Region.Physics.BulletSPlugin
 {
 public abstract class BSMotor
 {
     // Timescales and other things can be turned off by setting them to 'infinite'.
-    public const float Infinite = 12345f;
+    public const float Infinite = 12345.6f;
     public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
 
     public BSMotor(string useName)
@@ -62,12 +63,16 @@ public abstract class BSMotor
         }
     }
 }
-// Can all the incremental stepping be replaced with motor classes?
 
 // Motor which moves CurrentValue to TargetValue over TimeScale seconds.
 // The TargetValue decays in TargetValueDecayTimeScale and
 //     the CurrentValue will be held back by FrictionTimeScale.
-// TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay.
+// This motor will "zero itself" over time in that the targetValue will
+//    decay to zero and the currentValue will follow it to that zero.
+//    The overall effect is for the returned correction value to go from large
+//    values (the total difference between current and target minus friction)
+//    to small and eventually zero values.
+// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
 
 // For instance, if something is moving at speed X and the desired speed is Y,
 //    CurrentValue is X and TargetValue is Y. As the motor is stepped, new
@@ -81,13 +86,15 @@ public class BSVMotor : BSMotor
     // public Vector3 FrameOfReference { get; set; }
     // public Vector3 Offset { get; set; }
 
-    public float TimeScale { get; set; }
-    public float TargetValueDecayTimeScale { get; set; }
-    public Vector3 FrictionTimescale { get; set; }
-    public float Efficiency { get; set; }
+    public virtual float TimeScale { get; set; }
+    public virtual float TargetValueDecayTimeScale { get; set; }
+    public virtual Vector3 FrictionTimescale { get; set; }
+    public virtual float Efficiency { get; set; }
+
+    public virtual float ErrorZeroThreshold { get; set; }
 
-    public Vector3 TargetValue { get; private set; }
-    public Vector3 CurrentValue { get; private set; }
+    public virtual Vector3 TargetValue { get; private set; }
+    public virtual Vector3 CurrentValue { get; private set; }
 
     public BSVMotor(string useName)
         : base(useName)
@@ -96,6 +103,7 @@ public class BSVMotor : BSMotor
         Efficiency = 1f;
         FrictionTimescale = BSMotor.InfiniteVector;
         CurrentValue = TargetValue = Vector3.Zero;
+        ErrorZeroThreshold = 0.01f;
     }
     public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 
         : this(useName)
@@ -115,24 +123,19 @@ public class BSVMotor : BSMotor
         TargetValue = target;
     }
 
-    // A form of stepping that does not take the time quantum into account.
-    // The caller must do the right thing later.
-    public virtual Vector3 Step()
-    {
-        return Step(1f);
-    }
-
+    // Compute the next step and return the new current value
     public virtual Vector3 Step(float timeStep)
     {
-        Vector3 returnCurrent = Vector3.Zero;
-        if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
+        Vector3 origTarget = TargetValue;       // DEBUG
+        Vector3 origCurrVal = CurrentValue;     // DEBUG
+
+        Vector3 correction = Vector3.Zero;
+        Vector3 error = TargetValue - CurrentValue;
+        if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
         {
-            Vector3 origTarget = TargetValue;       // DEBUG
-            Vector3 origCurrVal = CurrentValue;   // DEBUG
+            correction = Step(timeStep, error);
 
-            // Addition =  (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
-            Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
-            CurrentValue += addAmount;
+            CurrentValue += correction;
 
             // The desired value reduces to zero which also reduces the difference with current.
             // If the decay time is infinite, don't decay at all.
@@ -143,39 +146,50 @@ public class BSVMotor : BSMotor
                 TargetValue *= (1f - decayFactor);
             }
 
+            // The amount we can correct the error is reduced by the friction
             Vector3 frictionFactor = Vector3.Zero;
             if (FrictionTimescale != BSMotor.InfiniteVector)
             {
                 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
                 // Individual friction components can be 'infinite' so compute each separately.
-                frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
-                frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
-                frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
+                frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
+                frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
+                frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
+                frictionFactor *= timeStep;
                 CurrentValue *= (Vector3.One - frictionFactor);
             }
 
-            returnCurrent = CurrentValue;
-
-            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
+            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},error={5},corr={6},targetDecay={6},decayFact={7},frictFac{8},curr={9},target={10},ret={11}",
                                 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
-                                timeStep, TimeScale, addAmount,
-                                TargetValueDecayTimeScale, decayFactor,
-                                FrictionTimescale, frictionFactor);
-            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
-                                    BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
-                                    addAmount, decayFactor, frictionFactor, returnCurrent);
+                                timeStep, error, correction,
+                                TargetValueDecayTimeScale, decayFactor, frictionFactor,
+                                CurrentValue, TargetValue, CurrentValue);
         }
         else
         {
             // Difference between what we have and target is small. Motor is done.
             CurrentValue = Vector3.Zero;
             TargetValue = Vector3.Zero;
+            MDetailLog("{0},  BSVMotor.Step,zero,{1},ret={2}",
+                        BSScene.DetailLogZero, UseName, CurrentValue);
+        }
 
-            MDetailLog("{0},  BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
-                                    BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
+        return CurrentValue;
+    }
+    public virtual Vector3 Step(float timeStep, Vector3 error)
+    {
+        Vector3 returnCorrection = Vector3.Zero;
+        if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
+        {
+            // correction =  error / secondsItShouldTakeToCorrect
+            Vector3 correctionAmount = error / TimeScale * timeStep;
 
+            returnCorrection = correctionAmount;
+            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5},frictTS={6},ret={7}",
+                                    BSScene.DetailLogZero, UseName, timeStep, TimeScale, error,
+                                    correctionAmount, FrictionTimescale, returnCorrection);
         }
-        return returnCurrent;
+        return returnCorrection;
     }
     public override string ToString()
     {
@@ -214,9 +228,14 @@ public class BSFMotor : BSMotor
 // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
 public class BSPIDVMotor : BSVMotor
 {
-    public Vector3 pFactor { get; set; }    // Amount of direct correction of an error (sometimes called 'proportional gain')
-    public Vector3 iFactor { get; set; }    // 
-    public Vector3 dFactor { get; set; }
+    // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
+    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; }
     Vector3 LastError { get; set; }
@@ -224,17 +243,39 @@ public class BSPIDVMotor : BSVMotor
     public BSPIDVMotor(string useName)
         : base(useName)
     {
-        // larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
-        pFactor = new Vector3(1.00f, 1.00f, 1.00f);
-        iFactor = new Vector3(1.00f, 1.00f, 1.00f);
-        dFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
+        IntegralFactor = Vector3.Zero;
+        LastError = Vector3.Zero;
     }
 
-    public override Vector3 Step(float timeStep)
+    public override void Zero()
     {
-        // How far are we from where we should be
-        Vector3 error = TargetValue - CurrentValue;
+        base.Zero();
+    }
+
+    public override float Efficiency
+    {
+        get { return base.Efficiency; }
+        set
+        {
+            base.Efficiency = Util.Clamp(value, 0f, 1f);
+            // Compute factors based on efficiency.
+            // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
+            // If efficiency is low (0f), use a factor value that overcorrects.
+            // TODO: might want to vary contribution of different factor depending on efficiency.
+            float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
+            // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
+            proportionFactor = new Vector3(factor, factor, factor);
+            integralFactor = new Vector3(factor, factor, factor);
+            derivFactor = new Vector3(factor, factor, factor);
+        }
+    }
 
+    // Ignore Current and Target Values and just advance the PID computation on this error.
+    public Vector3 Step(float timeStep, Vector3 error)
+    {
         // Add up the error so we can integrate over the accumulated errors
         IntegralFactor += error * timeStep;
 
@@ -242,9 +283,8 @@ public class BSPIDVMotor : BSVMotor
         Vector3 derivFactor = (error - LastError) * timeStep;
         LastError = error;
 
-        //                   Proportion                  Integral               Derivitive
-        // Correction = proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError
-        Vector3 ret =        error * pFactor    + IntegralFactor * iFactor + derivFactor * dFactor;
+        // Correction = -(proportionOfPresentError +      accumulationOfPastError    +     rateOfChangeOfError)
+        Vector3 ret   = -(error * proportionFactor + IntegralFactor * integralFactor + derivFactor * derivFactor);
 
         return ret;
     }
-- 
cgit v1.1


From e73dac4debcf79cba83b94255d62fce0815871cb Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Thu, 20 Dec 2012 10:19:16 -0800
Subject: BulletSim: angularMotorUp working again (seems a little slow as it
 takes longer than timescale to correct, but getting better). Disabled
 angularDeflection (need to resolve interactions between angular corrections).
 Update TODO list.

---
 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 65 +++++++++++++++-------
 .../Region/Physics/BulletSPlugin/BulletSimTODO.txt | 33 +++++++----
 2 files changed, 66 insertions(+), 32 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 912aadd..77ec76d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -91,6 +91,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private Vector3 m_lastVertAttractor = Vector3.Zero;             // what VA was last applied to body
 
         //Deflection properties
+        private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
         private float m_angularDeflectionEfficiency = 0;
         private float m_angularDeflectionTimescale = 0;
         private float m_linearDeflectionEfficiency = 0;
@@ -102,6 +103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private float m_bankingTimescale = 0;
 
         //Hover and Buoyancy properties
+        private BSVMotor m_hoverMotor = new BSVMotor("Hover");
         private float m_VhoverHeight = 0f;
         private float m_VhoverEfficiency = 0f;
         private float m_VhoverTimescale = 0f;
@@ -118,6 +120,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         // Timescale > cutoff  means no vert attractor.
         private float m_verticalAttractionTimescale = 510f;
 
+        // Just some recomputed constants:
+        static readonly float PIOverFour = ((float)Math.PI) / 4f;
+        static readonly float PIOverTwo = ((float)Math.PI) / 2f;
+
         public BSDynamics(BSScene myScene, BSPrim myPrim)
         {
             PhysicsScene = myScene;
@@ -563,9 +569,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
                 // Vehicles report collision events so we know when it's on the ground
                 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS);
 
-                // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
-                // Vector3 localInertia = new Vector3(1f, 1f, 1f);
-                // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
                 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass);
                 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
                 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr);
@@ -613,7 +616,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private Quaternion? m_knownOrientation;
         private Vector3? m_knownRotationalVelocity;
         private Vector3 m_knownRotationalForce;
-        private float? m_knownForwardSpeed;
+        private Vector3? m_knownForwardVelocity;    // vehicle relative forward speed
 
         private const int m_knownChangedPosition           = 1 << 0;
         private const int m_knownChangedVelocity           = 1 << 1;
@@ -632,7 +635,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
             m_knownOrientation = null;
             m_knownRotationalVelocity = null;
             m_knownRotationalForce = Vector3.Zero;
-            m_knownForwardSpeed = null;
+            m_knownForwardVelocity = null;
             m_knownChanged = 0;
         }
         private void PushKnownChanged()
@@ -755,13 +758,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
             m_knownRotationalForce += aForce;
             m_knownChanged |= m_knownChangedRotationalForce;
         }
+        // Vehicle relative forward velocity
+        private Vector3 VehicleForwardVelocity
+        {
+            get
+            {
+                if (m_knownForwardVelocity == null)
+                    m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
+                return (Vector3)m_knownForwardVelocity;
+            }
+        }
         private float VehicleForwardSpeed
         {
             get
             {
-                if (m_knownForwardSpeed == null)
-                    m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X;
-                return (float)m_knownForwardSpeed;
+                return VehicleForwardVelocity.X;
             }
         }
 
@@ -1025,7 +1036,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         //     set directly on the vehicle.
         private void MoveAngular(float pTimestep)
         {
-            // The user wants how many radians per second angular change?
+            // The user wants this many radians per second angular change?
             Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
 
             // ==================================================================
@@ -1137,27 +1148,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
                 // Y error means needed rotation around X axis and visa versa.
                 // Since the error goes from zero to one, the asin is the corresponding angle.
                 ret.X = (float)Math.Asin(verticalError.Y);
-                ret.Y = (float)Math.Asin(verticalError.X);
+                // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
+                ret.Y = -(float)Math.Asin(verticalError.X);
 
                 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
                 if (verticalError.Z < 0f)
                 {
-                    ret.X += (float)Math.PI / 4f;
-                    ret.Y += (float)Math.PI / 4f;
+                    ret.X += PIOverFour;
+                    ret.Y += PIOverFour;
                 }
 
-                // Put the signs back on so the rotation is in the correct direction.
-                ret.X *= (float)Math.Sign(verticalError.Y);
-                // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
-                ret.Y *= -(float)Math.Sign(verticalError.X);
-
                 // 'ret' is now the necessary velocity to correct tilt in one second.
                 //     Correction happens over a number of seconds.
                 Vector3 unscaledContrib = ret;
                 ret /= m_verticalAttractionTimescale;
 
-                VDetailLog("{0},  MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},vertAttr={4}",
-                                Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, ret);
+                VDetailLog("{0},  MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
+                                Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
             }
             return ret;
         }
@@ -1170,6 +1177,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         public Vector3 ComputeAngularDeflection()
         {
             Vector3 ret = Vector3.Zero;
+            return ret;         // DEBUG DEBUG DEBUG
+            // Disable angular deflection for the moment.
+            // Since angularMotorUp and angularDeflection are computed independently, they will calculate
+            //     approximately the same X or Y correction. When added together (when contributions are combined)
+            //     this creates an over-correction and then wabbling as the target is overshot.
+            // TODO: rethink how the different correction computations inter-relate.
 
             if (m_angularDeflectionEfficiency != 0)
             {
@@ -1181,15 +1194,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
                 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
                 pointingDirection.Normalize();
 
-                // The difference between what is and what should be
+                // The difference between what is and what should be.
                 Vector3 deflectionError = movingDirection - pointingDirection;
 
+                // Don't try to correct very large errors (not our job)
+                if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
+                if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
+                if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
+
+                // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
+
                 // Scale the correction by recovery timescale and efficiency
-                ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency;
+                ret = (-deflectionError) * m_angularDeflectionEfficiency;
                 ret /= m_angularDeflectionTimescale;
 
                 VDetailLog("{0},  MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
                     Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
+                VDetailLog("{0},  MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
+                    Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
             }
             return ret;
         }
@@ -1305,6 +1327,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private float ClampInRange(float low, float val, float high)
         {
             return Math.Max(low, Math.Min(val, high));
+            // return Utils.Clamp(val, low, high);
         }
 
         // Invoke the detailed logger and output something if it's enabled.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index ad4e42b..8a9aec9 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -8,9 +8,10 @@ Enable vehicle border crossings (at least as poorly as ODE)
 	Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
 Calibrate turning radius (DONE)
 limitMotorUp calibration (more down?)
-study PID motors (include 'efficiency' implementation
+study PID motors (include 'efficiency' implementation (DONE)
 	Add to avatar movement
 
+
 CRASHES
 =================================================
 20121129.1411: editting/moving phys object across region boundries causes crash
@@ -25,7 +26,6 @@ CRASHES
 VEHICLES TODO LIST:
 =================================================
 Border crossing with linked vehicle causes crash
-Neb vehicle taking > 25ms of physics time!!
 Vehicles (Move smoothly)
 Add vehicle collisions so IsColliding is properly reported.
 	Needed for banking, limitMotorUp, movementLimiting, ...
@@ -34,28 +34,25 @@ Cannot edit/move a vehicle being ridden: it jumps back to the origional position
 Neb car jiggling left and right
 	Happens on terrain and any other mesh object. Flat cubes are much smoother.
 	This has been reduced but not eliminated.
-Light cycle falling over when driving
 Implement referenceFrame for all the motion routines.
 Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
 	Verify that angular motion specified around Z moves in the vehicle coordinates.
 Verify llGetVel() is returning a smooth and good value for vehicle movement.
 llGetVel() should return the root's velocity if requested in a child prim.
 Implement function efficiency for lineaar and angular motion.
-Should vehicle angular/linear movement friction happen after all the components
-	or does it only apply to the basic movement?
 After getting off a vehicle, the root prim is phantom (can be walked through)
     Need to force a position update for the root prim after compound shape destruction
 Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
 For limitMotorUp, use raycast down to find if vehicle is in the air.
 Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
 	A kludge that isn't fixing the real problem of Bullet adding extra motion.
+Incorporate inter-relationship of angular corrections. For instance, angularDeflection
+	and angularMotorUp will compute same X or Y correction. When added together
+	creates over-correction and over-shoot and wabbling.
 
 BULLETSIM TODO LIST:
 =================================================
 Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
-Avatar height off after unsitting (floats off ground)
-	Editting appearance then moving restores.
-	Must not be initializing height when recreating capsule after unsit.
 Duplicating a physical prim causes old prim to jump away
 	Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
 Scenes with hundred of thousands of static objects take a lot of physics CPU time.
@@ -83,6 +80,8 @@ Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
 Linkset.Position and Linkset.Orientation requre rewrite to properly return
 	child position. LinksetConstraint acts like it's at taint time!!
 Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
+Should the different PID factors have non-equal contributions for different
+	values of Efficiency?
 
 LINKSETS
 ======================================================
@@ -100,17 +99,16 @@ Disable activity of passive linkset children.
 	Since the linkset is a compound object, the old prims are left lying
 	around and need to be phantomized so they don't collide, ...
 Speed up creation of large physical linksets
-	For instance, sitting in Neb's car (130 prims) takes several seconds to become physical
+	For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
+	REALLY bad for very large physical linksets (freezes the sim for many seconds).
 Eliminate collisions between objects in a linkset. (LinksetConstraint)
     Have UserPointer point to struct with localID and linksetID?
     Objects in original linkset still collide with each other?
 
 MORE
 ======================================================
-Find/remove avatar collision with ID=0.
 Test avatar walking up stairs. How does compare with SL.
     Radius of the capsule affects ability to climb edges.
-Tune terrain/object friction to be closer to 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.
@@ -203,3 +201,16 @@ Single prim vehicles don't seem to properly vehiclize.
 Add material type linkage and input all the material property definitions.
 	Skeleton classes and table are in the sources but are not filled or used.
 	(Resolution: 
+Neb vehicle taking > 25ms of physics time!!
+	(Resolution: compound linksets were being rebuild WAY too often)
+Avatar height off after unsitting (floats off ground)
+	Editting appearance then moving restores.
+	Must not be initializing height when recreating capsule after unsit.
+	(Resolution: confusion of scale vs size for native objects removed)
+Light cycle falling over when driving (Resolution: implemented angularMotorUp)
+Should vehicle angular/linear movement friction happen after all the components
+	or does it only apply to the basic movement?
+	(Resolution: friction added before returning newly computed motor value.
+	What is expected by some vehicles (turning up friction to moderate speed))
+Tune terrain/object friction to be closer to SL.
+	(Resolution: added material type with friction and resolution)
-- 
cgit v1.1


From a5b2539cf92aac65c11a36d4eb41d04f1c55b042 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Thu, 20 Dec 2012 10:32:33 -0800
Subject: BulletSim: replace use of funky nullable values for vehicle property
 update control (m_known* stuff). Bitmaps will be quicker to test and to
 clear.

---
 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 69 ++++++++++++++--------
 1 file changed, 43 insertions(+), 26 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 77ec76d..c3d75ea 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -602,21 +602,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 
         #region Known vehicle value functions
         // Vehicle physical parameters that we buffer from constant getting and setting.
-        // The "m_known*" variables are initialized to 'null', fetched only if referenced
-        //      and stored back into the physics engine only if updated.
+        // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
+        //      Changing is remembered and the parameter is stored back into the physics engine only if updated.
         //      This does two things: 1) saves continuious calls into unmanaged code, and
         //      2) signals when a physics property update must happen back to the simulator
         //      to update values modified for the vehicle.
         private int m_knownChanged;
-        private float? m_knownTerrainHeight;
-        private float? m_knownWaterLevel;
-        private Vector3? m_knownPosition;
-        private Vector3? m_knownVelocity;
+        private int m_knownHas;
+        private float m_knownTerrainHeight;
+        private float m_knownWaterLevel;
+        private Vector3 m_knownPosition;
+        private Vector3 m_knownVelocity;
         private Vector3 m_knownForce;
-        private Quaternion? m_knownOrientation;
-        private Vector3? m_knownRotationalVelocity;
+        private Quaternion m_knownOrientation;
+        private Vector3 m_knownRotationalVelocity;
         private Vector3 m_knownRotationalForce;
-        private Vector3? m_knownForwardVelocity;    // vehicle relative forward speed
+        private Vector3 m_knownForwardVelocity;    // vehicle relative forward speed
 
         private const int m_knownChangedPosition           = 1 << 0;
         private const int m_knownChangedVelocity           = 1 << 1;
@@ -624,18 +625,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private const int m_knownChangedOrientation        = 1 << 3;
         private const int m_knownChangedRotationalVelocity = 1 << 4;
         private const int m_knownChangedRotationalForce    = 1 << 5;
+        private const int m_knownChangedTerrainHeight      = 1 << 6;
+        private const int m_knownChangedWaterLevel         = 1 << 7;
+        private const int m_knownChangedForwardVelocity    = 1 << 7;
 
         private void ForgetKnownVehicleProperties()
         {
-            m_knownTerrainHeight = null;
-            m_knownWaterLevel = null;
-            m_knownPosition = null;
-            m_knownVelocity = null;
-            m_knownForce = Vector3.Zero;
-            m_knownOrientation = null;
-            m_knownRotationalVelocity = null;
-            m_knownRotationalForce = Vector3.Zero;
-            m_knownForwardVelocity = null;
+            m_knownHas = 0;
             m_knownChanged = 0;
         }
         private void PushKnownChanged()
@@ -674,17 +670,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         //    is used ot fetch the height only once for each vehicle simulation step.
         private float GetTerrainHeight(Vector3 pos)
         {
-            if (m_knownTerrainHeight == null)
+            if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
+            {
                 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
-            return (float)m_knownTerrainHeight;
+                m_knownHas |= m_knownChangedTerrainHeight;
+            }
+            return m_knownTerrainHeight;
         }
 
         // Since the computation of water level can be a little involved, this routine
         //    is used ot fetch the level only once for each vehicle simulation step.
         private float GetWaterLevel(Vector3 pos)
         {
-            if (m_knownWaterLevel == null)
+            if ((m_knownHas & m_knownChangedWaterLevel) == 0)
+            {
                 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
+                m_knownHas |= m_knownChangedWaterLevel;
+            }
             return (float)m_knownWaterLevel;
         }
 
@@ -692,8 +694,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         {
             get
             {
-                if (m_knownPosition == null)
+                if ((m_knownHas & m_knownChangedPosition) == 0)
+                {
                     m_knownPosition = Prim.ForcePosition;
+                    m_knownHas |= m_knownChangedPosition;
+                }
                 return (Vector3)m_knownPosition;
             }
             set
@@ -707,8 +712,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         {
             get
             {
-                if (m_knownOrientation == null)
+                if ((m_knownHas & m_knownChangedOrientation) == 0)
+                {
                     m_knownOrientation = Prim.ForceOrientation;
+                    m_knownHas |= m_knownChangedOrientation;
+                }
                 return (Quaternion)m_knownOrientation;
             }
             set
@@ -722,8 +730,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         {
             get
             {
-                if (m_knownVelocity == null)
+                if ((m_knownHas & m_knownChangedVelocity) == 0)
+                {
                     m_knownVelocity = Prim.ForceVelocity;
+                    m_knownHas |= m_knownChangedVelocity;
+                }
                 return (Vector3)m_knownVelocity;
             }
             set
@@ -743,8 +754,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         {
             get
             {
-                if (m_knownRotationalVelocity == null)
+                if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
+                {
                     m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
+                    m_knownHas |= m_knownChangedRotationalVelocity;
+                }
                 return (Vector3)m_knownRotationalVelocity;
             }
             set
@@ -763,8 +777,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         {
             get
             {
-                if (m_knownForwardVelocity == null)
+                if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
+                {
                     m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
+                    m_knownHas |= m_knownChangedForwardVelocity;
+                }
                 return (Vector3)m_knownForwardVelocity;
             }
         }
-- 
cgit v1.1


From e522bdb96a86ed1789e1438e4aac1ed522db70b8 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Thu, 20 Dec 2012 16:05:33 -0800
Subject: BulletSim: Check for unspecified TimeScale in BSVMotor and don't
 scale if not specified. Add test dump routine. Don'e zero current and target
 values when error goes to zero as the values could be used externally to
 store the actual target values, etc.

---
 OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 52 ++++++++++++++++++++----
 1 file changed, 43 insertions(+), 9 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index b57d2c8..a6af40d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -46,6 +46,7 @@ public abstract class BSMotor
     }
     public virtual void Reset() { }
     public virtual void Zero() { }
+    public virtual void GenerateTestOutput(float timeStep) { }
 
     // A name passed at motor creation for easily identifyable debugging messages.
     public string UseName { get; private set; }
@@ -93,8 +94,9 @@ public class BSVMotor : BSMotor
 
     public virtual float ErrorZeroThreshold { get; set; }
 
-    public virtual Vector3 TargetValue { get; private set; }
-    public virtual Vector3 CurrentValue { get; private set; }
+    public virtual Vector3 TargetValue { get; protected set; }
+    public virtual Vector3 CurrentValue { get; protected set; }
+    public virtual Vector3 LastError { get; protected set; }
 
     public BSVMotor(string useName)
         : base(useName)
@@ -122,6 +124,11 @@ public class BSVMotor : BSMotor
     {
         TargetValue = target;
     }
+    public override void Zero()
+    {
+        base.Zero();
+        CurrentValue = TargetValue = Vector3.Zero;
+    }
 
     // Compute the next step and return the new current value
     public virtual Vector3 Step(float timeStep)
@@ -168,21 +175,25 @@ public class BSVMotor : BSMotor
         else
         {
             // Difference between what we have and target is small. Motor is done.
-            CurrentValue = Vector3.Zero;
-            TargetValue = Vector3.Zero;
-            MDetailLog("{0},  BSVMotor.Step,zero,{1},ret={2}",
-                        BSScene.DetailLogZero, UseName, CurrentValue);
+            CurrentValue = TargetValue;
+            MDetailLog("{0},  BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={2}",
+                        BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
         }
 
         return CurrentValue;
     }
     public virtual Vector3 Step(float timeStep, Vector3 error)
     {
+        LastError = error;
         Vector3 returnCorrection = Vector3.Zero;
         if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
         {
             // correction =  error / secondsItShouldTakeToCorrect
-            Vector3 correctionAmount = error / TimeScale * timeStep;
+            Vector3 correctionAmount;
+            if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
+                correctionAmount = error * timeStep;
+            else
+                correctionAmount = error / TimeScale * timeStep;
 
             returnCorrection = correctionAmount;
             MDetailLog("{0},  BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5},frictTS={6},ret={7}",
@@ -191,6 +202,30 @@ public class BSVMotor : BSMotor
         }
         return returnCorrection;
     }
+
+    // The user sets all the parameters and calls this which outputs values until error is zero.
+    public override void GenerateTestOutput(float timeStep)
+    {
+        // maximum number of outputs to generate.
+        int maxOutput = 50;
+        MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
+        MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
+                                BSScene.DetailLogZero, UseName,
+                                TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 
+                                CurrentValue, TargetValue);
+
+        LastError = BSMotor.InfiniteVector;
+        while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
+        {
+            Vector3 lastStep = Step(timeStep);
+            MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
+                            BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
+        }
+        MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
+        
+
+    }
+
     public override string ToString()
     {
         return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
@@ -238,7 +273,6 @@ public class BSPIDVMotor : BSVMotor
     public float EfficiencyLow = 4.0f;
 
     Vector3 IntegralFactor { get; set; }
-    Vector3 LastError { get; set; }
 
     public BSPIDVMotor(string useName)
         : base(useName)
@@ -274,7 +308,7 @@ public class BSPIDVMotor : BSVMotor
     }
 
     // Ignore Current and Target Values and just advance the PID computation on this error.
-    public Vector3 Step(float timeStep, Vector3 error)
+    public override Vector3 Step(float timeStep, Vector3 error)
     {
         // Add up the error so we can integrate over the accumulated errors
         IntegralFactor += error * timeStep;
-- 
cgit v1.1


From 9d2f569d600cad688ac7e06fcac7e94023b3600a Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Thu, 20 Dec 2012 16:06:52 -0800
Subject: BulletSim: fix incorrectly defined property changed flag.

---
 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index c3d75ea..a5acd86 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -627,7 +627,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private const int m_knownChangedRotationalForce    = 1 << 5;
         private const int m_knownChangedTerrainHeight      = 1 << 6;
         private const int m_knownChangedWaterLevel         = 1 << 7;
-        private const int m_knownChangedForwardVelocity    = 1 << 7;
+        private const int m_knownChangedForwardVelocity    = 1 << 8;
 
         private void ForgetKnownVehicleProperties()
         {
@@ -860,13 +860,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
             // ==================================================================
             // Clamp high or low velocities
             float newVelocityLengthSq = newVelocity.LengthSquared();
-            // if (newVelocityLengthSq > 1e6f)
             if (newVelocityLengthSq > 1000f)
             {
                 newVelocity /= newVelocity.Length();
                 newVelocity *= 1000f;
             }
-            // else if (newVelocityLengthSq < 1e-6f)
             else if (newVelocityLengthSq < 0.001f)
                 newVelocity = Vector3.Zero;
 
-- 
cgit v1.1


From 750492796d3f19028ddd7fdf5f696933f083fd33 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Fri, 21 Dec 2012 09:55:20 -0800
Subject: BulletSim: begin movement of parameters from pinned memory block to
 variables all in managed code. Add note to TODO list to remember to do the
 rest. Other updates to TODO list.

---
 OpenSim/Region/Physics/BulletSPlugin/BSScene.cs        | 10 ++++++++++
 OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | 16 +++++++++-------
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 069cb0d..2ca4912 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -96,6 +96,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
     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; }
+
     public delegate void PreStepAction(float timeStep);
     public event PreStepAction BeforeStep;
 
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 8a9aec9..c084ab4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -1,16 +1,16 @@
 CURRENT PRIORITIES
 =================================================
-Eliminate all crashes (DONEish)
-	Editing/deleting physical linkset (DONE)
-	Border crossing of physical linkset (DONE)
+Smooth avatar movement with motor
+	Should motor update be all at taint-time?
 Enable vehicle border crossings (at least as poorly as ODE)
+	Terrain skirts
 	Avatar created in previous region and not new region when crossing border
 	Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
-Calibrate turning radius (DONE)
+Vehicle movement on terrain smoothness
+Vehicle script tuning/debugging
+	Avanti speed script
+	Weapon shooter script
 limitMotorUp calibration (more down?)
-study PID motors (include 'efficiency' implementation (DONE)
-	Add to avatar movement
-
 
 CRASHES
 =================================================
@@ -139,6 +139,8 @@ Consider moving prim/character body and shape destruction in destroy()
 	to postTimeTime rather than protecting all the potential sets that
 	might have been queued up.
 Remove unused fields from ShapeData (not used in API2)
+Remove unused fields from pinned memory shared parameter block
+	Create parameter variables in BSScene to replace same.
 Breakout code for mesh/hull/compound/native into separate BSShape* classes
     Standardize access to building and reference code.
 	The skeleton classes are in the sources but are not complete or linked in.
-- 
cgit v1.1


From b4f8a05e9a30373942c3a0511e43dcce3df11184 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Fri, 21 Dec 2012 09:56:31 -0800
Subject: BulletSim: Better detail logging of VMotor actions.

---
 OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index a6af40d..34a87c6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -166,11 +166,13 @@ public class BSVMotor : BSMotor
                 CurrentValue *= (Vector3.One - frictionFactor);
             }
 
-            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},error={5},corr={6},targetDecay={6},decayFact={7},frictFac{8},curr={9},target={10},ret={11}",
+            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
                                 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
-                                timeStep, error, correction,
-                                TargetValueDecayTimeScale, decayFactor, frictionFactor,
-                                CurrentValue, TargetValue, CurrentValue);
+                                timeStep, error, correction);
+            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
+                                BSScene.DetailLogZero, UseName,
+                                TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
+                                TargetValue, CurrentValue);
         }
         else
         {
@@ -196,9 +198,8 @@ public class BSVMotor : BSMotor
                 correctionAmount = error / TimeScale * timeStep;
 
             returnCorrection = correctionAmount;
-            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5},frictTS={6},ret={7}",
-                                    BSScene.DetailLogZero, UseName, timeStep, TimeScale, error,
-                                    correctionAmount, FrictionTimescale, returnCorrection);
+            MDetailLog("{0},  BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
+                                    BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
         }
         return returnCorrection;
     }
-- 
cgit v1.1


From 8c99f63239702bcdb8f1e0efa57efc91c98fc3d7 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Fri, 21 Dec 2012 10:00:03 -0800
Subject: BulletSim: avatar movement smoothed with motor that modifies avatar
 velocity to target velocity. Fails in incorporating physical world effects
 (gravity) so avatar doesn't fly correctly.

---
 .../Region/Physics/BulletSPlugin/BSCharacter.cs    | 77 +++++++++++++++++++++-
 OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs     |  8 ++-
 2 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4dd6264..695896e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -69,6 +69,8 @@ public sealed class BSCharacter : BSPhysObject
     private OMV.Vector3 _appliedVelocity;   // the last velocity applied to the avatar
     private float _currentFriction;         // the friction currently being used (changed by setVelocity).
 
+    private BSVMotor _velocityMotor;
+
     private OMV.Vector3 _PIDTarget;
     private bool _usePID;
     private float _PIDTau;
@@ -89,6 +91,18 @@ public sealed class BSCharacter : BSPhysObject
         if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
         if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
 
+        // A motor to control the acceleration and deceleration of the avatar movement.
+        // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
+        // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
+        // Infinite decay and timescale values so motor only changes current to target values.
+        _velocityMotor = new BSVMotor("BSCharacter.Velocity", 
+                                            0.2f,                       // time scale
+                                            BSMotor.Infinite,           // decay time scale
+                                            BSMotor.InfiniteVector,     // friction timescale
+                                            1f                          // efficiency
+        );
+        _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
+
         _flying = isFlying;
         _orientation = OMV.Quaternion.Identity;
         _velocity = OMV.Vector3.Zero;
@@ -138,6 +152,10 @@ public sealed class BSCharacter : BSPhysObject
         ForcePosition = _position;
         // Set the velocity and compute the proper friction
         ForceVelocity = _velocity;
+        // Setting the current and target in the motor will cause it to start computing any deceleration.
+        _velocityMotor.Reset();
+        _velocityMotor.SetCurrent(_velocity);
+        _velocityMotor.SetTarget(_velocity);
 
         // 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.
@@ -239,6 +257,7 @@ public sealed class BSCharacter : BSPhysObject
     public override void ZeroMotion(bool inTaintTime)
     {
         _velocity = OMV.Vector3.Zero;
+        _velocityMotor.Zero();
         _acceleration = OMV.Vector3.Zero;
         _rotationalVelocity = OMV.Vector3.Zero;
 
@@ -400,10 +419,38 @@ public sealed class BSCharacter : BSPhysObject
 
     public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
     public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
+
+    // Sets the target in the motor. This starts the changing of the avatar's velocity.
+    public override OMV.Vector3 TargetVelocity
+    {
+        get
+        {
+            return _velocityMotor.TargetValue;
+        }
+        set
+        {
+            DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
+            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);
+            });
+        }
+    }
+    // Directly setting velocity means this is what the user really wants now.
     public override OMV.Vector3 Velocity {
         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()
             {
@@ -415,6 +462,8 @@ public sealed class BSCharacter : BSPhysObject
     public override OMV.Vector3 ForceVelocity {
         get { return _velocity; }
         set {
+            PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
+
             // Depending on whether the avatar is moving or not, change the friction
             //    to keep the avatar from slipping around
             if (_velocity.Length() == 0)
@@ -511,6 +560,13 @@ public sealed class BSCharacter : BSPhysObject
         get { return _flying; }
         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);
         }
@@ -581,7 +637,10 @@ public sealed class BSCharacter : BSPhysObject
     }
     public override float ForceBuoyancy {
         get { return _buoyancy; }
-        set { _buoyancy = value;
+        set { 
+            PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
+
+            _buoyancy = value;
             DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
             // Buoyancy is faked by changing the gravity applied to the object
             float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
@@ -698,6 +757,21 @@ public sealed class BSCharacter : BSPhysObject
         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);
+        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.
@@ -706,6 +780,7 @@ public sealed class BSCharacter : BSPhysObject
             _velocity = avVel;
             BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
         }
+         */
 
         // Tell the linkset about value changes
         Linkset.UpdateProperties(this, true);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 1c6f946..68a0db6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -532,16 +532,18 @@ public sealed class BSPrim : BSPhysObject
             PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
             {
                 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
-                if (PhysBody.HasPhysicalBody)
-                    BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
+                ForceVelocity = _velocity;
             });
         }
     }
     public override OMV.Vector3 ForceVelocity {
         get { return _velocity; }
         set {
+            PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
+
             _velocity = value;
-            BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
+            if (PhysBody.HasPhysicalBody)
+                BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
         }
     }
     public override OMV.Vector3 Torque {
-- 
cgit v1.1


From 2e3e95e84634853366d61fa483b44597f8c53797 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Fri, 21 Dec 2012 10:04:12 -0800
Subject: BulletSim: small fix to avatar movement motor use which keeps avatar
 from flying up forever. This doesn't fix the overall problem but keeps avatar
 flying from being totally unusable.

---
 OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 695896e..57c5898 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -763,7 +763,8 @@ public sealed class BSCharacter : BSPhysObject
         //     and that velocity component must be retained.
         float timeStep = 0.089f;        // DEBUG DEBUG FIX FIX FIX
         OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
-        stepVelocity.Z += entprop.Velocity.Z;
+        // 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);
         /*
-- 
cgit v1.1