Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs OpenSim/Region/Physics/Meshing/Meshmerizer.csavinationmerge
						commit
						daa1d99513
					
				| 
						 | 
				
			
			@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
 | 
			
		|||
    /// <summary>This is a base class for testing any Data service for any DBMS. 
 | 
			
		||||
    /// Requires NUnit 2.5 or better (to support the generics).
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <remarks>
 | 
			
		||||
    /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with 
 | 
			
		||||
    /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
 | 
			
		||||
    /// and similar on EstateTests, InventoryTests and RegionTests.
 | 
			
		||||
    /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
 | 
			
		||||
    /// </remarks>
 | 
			
		||||
    /// <typeparam name="TConn"></typeparam>
 | 
			
		||||
    /// <typeparam name="TService"></typeparam>
 | 
			
		||||
    public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase
 | 
			
		||||
    public class BasicDataServiceTest<TConn, TService>
 | 
			
		||||
        where TConn : DbConnection, new()
 | 
			
		||||
        where TService : class, new()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
 | 
			
		|||
                }
 | 
			
		||||
 | 
			
		||||
                if (groupsConfig.GetString("Module", "Default") != "Default")
 | 
			
		||||
                {
 | 
			
		||||
                    m_Enabled = false;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
 | 
			
		|||
                {
 | 
			
		||||
                    foreach (GridInstantMessage im in msglist)
 | 
			
		||||
                    {
 | 
			
		||||
                        // client.SendInstantMessage(im);
 | 
			
		||||
                        if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
 | 
			
		||||
                            // send it directly or else the item will be given twice
 | 
			
		||||
                            client.SendInstantMessage(im);
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // Send through scene event manager so all modules get a chance
 | 
			
		||||
                            // to look at this message before it gets delivered.
 | 
			
		||||
                            //
 | 
			
		||||
                            // Needed for proper state management for stored group
 | 
			
		||||
                            // invitations
 | 
			
		||||
                            //
 | 
			
		||||
 | 
			
		||||
                        // Send through scene event manager so all modules get a chance
 | 
			
		||||
                        // to look at this message before it gets delivered.
 | 
			
		||||
                        //
 | 
			
		||||
                        // Needed for proper state management for stored group
 | 
			
		||||
                        // invitations
 | 
			
		||||
                        //
 | 
			
		||||
                            im.offline = 1;
 | 
			
		||||
 | 
			
		||||
                        im.offline = 1;
 | 
			
		||||
 | 
			
		||||
                        Scene s = FindScene(client.AgentId);
 | 
			
		||||
                        if (s != null)
 | 
			
		||||
                            s.EventManager.TriggerIncomingInstantMessage(im);
 | 
			
		||||
                            Scene s = FindScene(client.AgentId);
 | 
			
		||||
                            if (s != null)
 | 
			
		||||
                                s.EventManager.TriggerIncomingInstantMessage(im);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
 | 
			
		|||
 | 
			
		||||
            if (mainParams.Count < 4)
 | 
			
		||||
            {
 | 
			
		||||
                m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
 | 
			
		||||
                //m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
 | 
			
		||||
                m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
 | 
			
		|||
 | 
			
		||||
            if (mainParams.Count < 5)
 | 
			
		||||
            {
 | 
			
		||||
                //m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
 | 
			
		||||
                m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
 | 
			
		|||
 | 
			
		||||
            if (mainParams.Count < 4)
 | 
			
		||||
            {
 | 
			
		||||
                m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
 | 
			
		||||
                m_console.OutputFormat("Usage: show part name [--regex] <name>");
 | 
			
		||||
                //m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
 | 
			
		|||
            cdl.AddRow("Link number", sop.LinkNum);
 | 
			
		||||
            cdl.AddRow("Flags", sop.Flags);
 | 
			
		||||
 | 
			
		||||
            if (showFull)
 | 
			
		||||
            {
 | 
			
		||||
                PrimitiveBaseShape s = sop.Shape;
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.FlexiDrag);
 | 
			
		||||
                cdl.AddRow("FlexiEntry", s.FlexiEntry);
 | 
			
		||||
                cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
 | 
			
		||||
                cdl.AddRow("FlexiGravity", s.FlexiGravity);
 | 
			
		||||
                cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
 | 
			
		||||
                cdl.AddRow("HollowShape", s.HollowShape);
 | 
			
		||||
                cdl.AddRow(
 | 
			
		||||
                    "LightColor", 
 | 
			
		||||
                    string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.LightCutoff);
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.LightEntry);
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.LightFalloff);
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.LightIntensity);
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.LightRadius);
 | 
			
		||||
                cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
 | 
			
		||||
                cdl.AddRow("PathBegin", s.PathBegin);
 | 
			
		||||
                cdl.AddRow("PathEnd", s.PathEnd);
 | 
			
		||||
                cdl.AddRow("PathCurve", s.PathCurve);
 | 
			
		||||
                cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
 | 
			
		||||
                cdl.AddRow("PathRevolutions", s.PathRevolutions);
 | 
			
		||||
                cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
 | 
			
		||||
                cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
 | 
			
		||||
                cdl.AddRow("FlexiDrag", s.PathSkew);
 | 
			
		||||
                cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
 | 
			
		||||
                cdl.AddRow("PathTwist", s.PathTwist);
 | 
			
		||||
                cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
 | 
			
		||||
                cdl.AddRow("PCode", s.PCode);
 | 
			
		||||
                cdl.AddRow("ProfileBegin", s.ProfileBegin);
 | 
			
		||||
                cdl.AddRow("ProfileEnd", s.ProfileEnd);
 | 
			
		||||
                cdl.AddRow("ProfileHollow", s.ProfileHollow);
 | 
			
		||||
                cdl.AddRow("ProfileShape", s.ProfileShape);
 | 
			
		||||
                cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
 | 
			
		||||
                cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
 | 
			
		||||
                cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
 | 
			
		||||
                cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
 | 
			
		||||
                cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
 | 
			
		||||
                cdl.AddRow("Scale", s.Scale);
 | 
			
		||||
                cdl.AddRow(
 | 
			
		||||
                    "SculptData", 
 | 
			
		||||
                    string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
 | 
			
		||||
                cdl.AddRow("SculptEntry", s.SculptEntry);
 | 
			
		||||
                cdl.AddRow("SculptTexture", s.SculptTexture);
 | 
			
		||||
                cdl.AddRow("SculptType", s.SculptType);
 | 
			
		||||
                cdl.AddRow("State", s.State);
 | 
			
		||||
 | 
			
		||||
                // TODO, unpack and display texture entries
 | 
			
		||||
                //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            object itemsOutput;
 | 
			
		||||
            if (showFull)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
 | 
			
		|||
                itemsOutput = sop.Inventory.Count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            cdl.AddRow("Items", itemsOutput);
 | 
			
		||||
 | 
			
		||||
            return sb.Append(cdl.ToString());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
 | 
			
		|||
        }
 | 
			
		||||
        if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
 | 
			
		||||
            float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
 | 
			
		||||
            if (Position.Z < waterHeight)
 | 
			
		||||
            {
 | 
			
		||||
                _position.Z = waterHeight;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
        private Quaternion m_referenceFrame = Quaternion.Identity;
 | 
			
		||||
 | 
			
		||||
        // Linear properties
 | 
			
		||||
        private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
 | 
			
		||||
        private Vector3 m_linearMotorDirection = Vector3.Zero;          // velocity requested by LSL, decayed by time
 | 
			
		||||
        private Vector3 m_linearMotorOffset = Vector3.Zero;             // the point of force can be offset from the center
 | 
			
		||||
        private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero;   // velocity requested by LSL
 | 
			
		||||
        private Vector3 m_newVelocity = Vector3.Zero;                   // velocity computed to be applied to body
 | 
			
		||||
        private Vector3 m_linearFrictionTimescale = Vector3.Zero;
 | 
			
		||||
        private float m_linearMotorDecayTimescale = 0;
 | 
			
		||||
        private float m_linearMotorTimescale = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
        // private Vector3 m_linearMotorOffset = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
        //Angular properties
 | 
			
		||||
        private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
 | 
			
		||||
        private Vector3 m_angularMotorDirection = Vector3.Zero;         // angular velocity requested by LSL motor
 | 
			
		||||
        // private int m_angularMotorApply = 0;                            // application frame counter
 | 
			
		||||
        private Vector3 m_angularMotorVelocity = Vector3.Zero;          // current angular motor velocity
 | 
			
		||||
| 
						 | 
				
			
			@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
 | 
			
		||||
 | 
			
		||||
        //Attractor properties
 | 
			
		||||
        private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
 | 
			
		||||
        private float m_verticalAttractionEfficiency = 1.0f;        // damped
 | 
			
		||||
        private float m_verticalAttractionTimescale = 500f;         // Timescale > 300  means no vert attractor.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
 | 
			
		||||
                    m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
 | 
			
		||||
                    m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.ANGULAR_MOTOR_TIMESCALE:
 | 
			
		||||
                    m_angularMotorTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    m_angularMotor.TimeScale = m_angularMotorTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.BANKING_EFFICIENCY:
 | 
			
		||||
                    m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
 | 
			
		||||
| 
						 | 
				
			
			@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
 | 
			
		||||
                    m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
 | 
			
		||||
                    m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_TIMESCALE:
 | 
			
		||||
                    m_linearMotorTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    m_linearMotor.TimeScale = m_linearMotorTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
 | 
			
		||||
                    m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
 | 
			
		||||
                    m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
 | 
			
		||||
                    m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
 | 
			
		||||
                    m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                // These are vector properties but the engine lets you use a single float value to
 | 
			
		||||
                // set all of the components to the same value
 | 
			
		||||
                case Vehicle.ANGULAR_FRICTION_TIMESCALE:
 | 
			
		||||
                    m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
                    m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.ANGULAR_MOTOR_DIRECTION:
 | 
			
		||||
                    m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
                    // m_angularMotorApply = 100;
 | 
			
		||||
                    m_angularMotor.SetTarget(m_angularMotorDirection);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_FRICTION_TIMESCALE:
 | 
			
		||||
                    m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
                    m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_DIRECTION:
 | 
			
		||||
                    m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
                    m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
                    m_linearMotor.SetTarget(m_linearMotorDirection);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_OFFSET:
 | 
			
		||||
                    m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
 | 
			
		||||
| 
						 | 
				
			
			@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
            {
 | 
			
		||||
                case Vehicle.ANGULAR_FRICTION_TIMESCALE:
 | 
			
		||||
                    m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
                    m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.ANGULAR_MOTOR_DIRECTION:
 | 
			
		||||
                    // Limit requested angular speed to 2 rps= 4 pi rads/sec
 | 
			
		||||
| 
						 | 
				
			
			@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
 | 
			
		||||
                    pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
 | 
			
		||||
                    m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
                    // m_angularMotorApply = 100;
 | 
			
		||||
                    m_angularMotor.SetTarget(m_angularMotorDirection);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_FRICTION_TIMESCALE:
 | 
			
		||||
                    m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
                    m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_DIRECTION:
 | 
			
		||||
                    m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
                    m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
                    m_linearMotor.SetTarget(m_linearMotorDirection);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.LINEAR_MOTOR_OFFSET:
 | 
			
		||||
                    m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    m_VhoverEfficiency = 0;
 | 
			
		||||
                    m_VhoverTimescale = 0;
 | 
			
		||||
                    m_VehicleBuoyancy = 0;
 | 
			
		||||
                    
 | 
			
		||||
 | 
			
		||||
                    m_linearDeflectionEfficiency = 1;
 | 
			
		||||
                    m_linearDeflectionTimescale = 1;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
 | 
			
		||||
                    m_referenceFrame = Quaternion.Identity;
 | 
			
		||||
                    m_flags = (VehicleFlag)0;
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case Vehicle.TYPE_SLED:
 | 
			
		||||
| 
						 | 
				
			
			@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    m_bankingMix = 1;
 | 
			
		||||
 | 
			
		||||
                    m_referenceFrame = Quaternion.Identity;
 | 
			
		||||
                    m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
 | 
			
		||||
                    m_flags &=
 | 
			
		||||
                         ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
 | 
			
		||||
                           VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
 | 
			
		||||
                    m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
 | 
			
		||||
                                | VehicleFlag.HOVER_TERRAIN_ONLY
 | 
			
		||||
                                | VehicleFlag.HOVER_GLOBAL_HEIGHT
 | 
			
		||||
                                | VehicleFlag.HOVER_UP_ONLY);
 | 
			
		||||
                    m_flags |= (VehicleFlag.NO_DEFLECTION_UP
 | 
			
		||||
                            | VehicleFlag.LIMIT_ROLL_ONLY
 | 
			
		||||
                            | VehicleFlag.LIMIT_MOTOR_UP);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.TYPE_CAR:
 | 
			
		||||
                    m_linearMotorDirection = Vector3.Zero;
 | 
			
		||||
| 
						 | 
				
			
			@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
 | 
			
		||||
                                    | VehicleFlag.HOVER_GLOBAL_HEIGHT
 | 
			
		||||
                                    | VehicleFlag.LIMIT_ROLL_ONLY
 | 
			
		||||
                                    | VehicleFlag.LIMIT_MOTOR_UP
 | 
			
		||||
                                    | VehicleFlag.HOVER_UP_ONLY);
 | 
			
		||||
                    m_flags |= (VehicleFlag.NO_DEFLECTION_UP
 | 
			
		||||
                                    | VehicleFlag.LIMIT_MOTOR_UP
 | 
			
		||||
                                    | VehicleFlag.HOVER_WATER_ONLY);
 | 
			
		||||
                    break;
 | 
			
		||||
                case Vehicle.TYPE_AIRPLANE:
 | 
			
		||||
| 
						 | 
				
			
			@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                                    | VehicleFlag.HOVER_GLOBAL_HEIGHT);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update any physical parameters based on this type.
 | 
			
		||||
            Refresh();
 | 
			
		||||
 | 
			
		||||
            m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
 | 
			
		||||
                                m_linearMotorDecayTimescale, m_linearFrictionTimescale,
 | 
			
		||||
                                1f);
 | 
			
		||||
            m_linearMotor.PhysicsScene = PhysicsScene;  // DEBUG DEBUG DEBUG (enables detail logging)
 | 
			
		||||
 | 
			
		||||
            m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
 | 
			
		||||
                                m_angularMotorDecayTimescale, m_angularFrictionTimescale,
 | 
			
		||||
                                1f);
 | 
			
		||||
            m_angularMotor.PhysicsScene = PhysicsScene;  // DEBUG DEBUG DEBUG (enables detail logging)
 | 
			
		||||
 | 
			
		||||
            m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
 | 
			
		||||
                                BSMotor.Infinite, BSMotor.InfiniteVector,
 | 
			
		||||
                                m_verticalAttractionEfficiency);
 | 
			
		||||
            // Z goes away and we keep X and Y
 | 
			
		||||
            m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
 | 
			
		||||
            m_verticalAttractionMotor.PhysicsScene = PhysicsScene;  // DEBUG DEBUG DEBUG (enables detail logging)
 | 
			
		||||
 | 
			
		||||
            // m_bankingMotor = new BSVMotor("BankingMotor", ...);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Some of the properties of this prim may have changed.
 | 
			
		||||
| 
						 | 
				
			
			@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
        {
 | 
			
		||||
            if (IsActive)
 | 
			
		||||
            {
 | 
			
		||||
                m_vehicleMass = Prim.Linkset.LinksetMass;
 | 
			
		||||
 | 
			
		||||
                // Friction effects are handled by this vehicle code
 | 
			
		||||
                BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
 | 
			
		||||
                BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
 | 
			
		||||
                float friction = 0f;
 | 
			
		||||
                BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
 | 
			
		||||
 | 
			
		||||
                // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
 | 
			
		||||
                // 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;
 | 
			
		||||
                BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
 | 
			
		||||
                // 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);
 | 
			
		||||
                BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
 | 
			
		||||
                                Prim.LocalID, friction, localInertia, angularDamping);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
        {
 | 
			
		||||
            if (!IsActive) return;
 | 
			
		||||
 | 
			
		||||
            // DEBUG
 | 
			
		||||
            // Because Bullet does apply forces to the vehicle, our last computed
 | 
			
		||||
            //     linear and angular velocities are not what is happening now.
 | 
			
		||||
            // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
 | 
			
		||||
            // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
 | 
			
		||||
            // m_lastAngularVelocity = Prim.ForceRotationalVelocity;   // DEBUG: account for what Bullet did last time
 | 
			
		||||
            // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation);        // DEBUG:
 | 
			
		||||
            // END DEBUG
 | 
			
		||||
 | 
			
		||||
            m_vehicleMass = Prim.Linkset.LinksetMass;
 | 
			
		||||
 | 
			
		||||
            MoveLinear(pTimestep);
 | 
			
		||||
            // Commented out for debug
 | 
			
		||||
            MoveAngular(pTimestep);
 | 
			
		||||
            // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false);    // DEBUG DEBUG
 | 
			
		||||
            // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity;    // DEBUG DEBUG
 | 
			
		||||
 | 
			
		||||
            LimitRotation(pTimestep);
 | 
			
		||||
 | 
			
		||||
            // remember the position so next step we can limit absolute movement effects
 | 
			
		||||
            m_lastPositionVector = Prim.ForcePosition;
 | 
			
		||||
 | 
			
		||||
            VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}",        // DEBUG DEBUG
 | 
			
		||||
                                    Prim.LocalID, 
 | 
			
		||||
                                    BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
 | 
			
		||||
                                    BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
 | 
			
		||||
                                    Prim.Inertia,
 | 
			
		||||
                                    m_vehicleMass
 | 
			
		||||
                                    );
 | 
			
		||||
            VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
 | 
			
		||||
                    Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
 | 
			
		||||
        }// end Step
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Apply the effect of the linear motor.
 | 
			
		||||
        // Also does hover and float.
 | 
			
		||||
        private void MoveLinear(float pTimestep)
 | 
			
		||||
        {
 | 
			
		||||
            // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
 | 
			
		||||
            // m_lastLinearVelocityVector is the current speed we are moving in that direction
 | 
			
		||||
            if (m_linearMotorDirection.LengthSquared() > 0.001f)
 | 
			
		||||
            {
 | 
			
		||||
                Vector3 origDir = m_linearMotorDirection;       // DEBUG
 | 
			
		||||
                Vector3 origVel = m_lastLinearVelocityVector;   // DEBUG
 | 
			
		||||
                // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
 | 
			
		||||
                Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation);   // DEBUG
 | 
			
		||||
            Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
 | 
			
		||||
 | 
			
		||||
                // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
 | 
			
		||||
                Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
 | 
			
		||||
                m_lastLinearVelocityVector += addAmount;
 | 
			
		||||
 | 
			
		||||
                float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
 | 
			
		||||
                m_linearMotorDirection *= (1f - decayFactor);
 | 
			
		||||
 | 
			
		||||
                // Rotate new object velocity from vehicle relative to world coordinates
 | 
			
		||||
                m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
 | 
			
		||||
 | 
			
		||||
                // Apply friction for next time
 | 
			
		||||
                Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
 | 
			
		||||
                m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
 | 
			
		||||
                                Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 
 | 
			
		||||
                                m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // if what remains of direction is very small, zero it.
 | 
			
		||||
                m_linearMotorDirection = Vector3.Zero;
 | 
			
		||||
                m_lastLinearVelocityVector = Vector3.Zero;
 | 
			
		||||
                m_newVelocity = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // m_newVelocity is velocity computed from linear motor in world coordinates
 | 
			
		||||
            // Rotate new object velocity from vehicle relative to world coordinates
 | 
			
		||||
            linearMotorContribution *= Prim.ForceOrientation;
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            // Gravity and Buoyancy
 | 
			
		||||
            // There is some gravity, make a gravity force vector that is applied after object velocity.
 | 
			
		||||
            // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
 | 
			
		||||
            Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
 | 
			
		||||
            // Preserve the current Z velocity
 | 
			
		||||
            Vector3 vel_now = m_prim.Velocity;
 | 
			
		||||
            m_dir.Z = vel_now.Z;        // Preserve the accumulated falling velocity
 | 
			
		||||
             */
 | 
			
		||||
 | 
			
		||||
            Vector3 pos = Prim.ForcePosition;
 | 
			
		||||
//            Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
 | 
			
		||||
 | 
			
		||||
            // If below the terrain, move us above the ground a little.
 | 
			
		||||
            float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
 | 
			
		||||
 | 
			
		||||
            Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
 | 
			
		||||
 | 
			
		||||
            Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
 | 
			
		||||
 | 
			
		||||
            ComputeLinearBlockingEndPoint(pTimestep, ref pos);
 | 
			
		||||
 | 
			
		||||
            Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            Vector3 newVelocity = linearMotorContribution
 | 
			
		||||
                            + terrainHeightContribution
 | 
			
		||||
                            + hoverContribution
 | 
			
		||||
                            + limitMotorUpContribution;
 | 
			
		||||
 | 
			
		||||
            // If not changing some axis, reduce out velocity
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_X)) != 0)
 | 
			
		||||
                newVelocity.X = 0;
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_Y)) != 0)
 | 
			
		||||
                newVelocity.Y = 0;
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_Z)) != 0)
 | 
			
		||||
                newVelocity.Z = 0;
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            // Clamp REALLY high or low velocities
 | 
			
		||||
            float newVelocityLengthSq = newVelocity.LengthSquared();
 | 
			
		||||
            if (newVelocityLengthSq > 1e6f)
 | 
			
		||||
            {
 | 
			
		||||
                newVelocity /= newVelocity.Length();
 | 
			
		||||
                newVelocity *= 1000f;
 | 
			
		||||
            }
 | 
			
		||||
            else if (newVelocityLengthSq < 1e-6f)
 | 
			
		||||
                newVelocity = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            // Stuff new linear velocity into the vehicle
 | 
			
		||||
            Prim.ForceVelocity = newVelocity;
 | 
			
		||||
            // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false);    // DEBUG DEBUG
 | 
			
		||||
 | 
			
		||||
            // Other linear forces are applied as forces.
 | 
			
		||||
            Vector3 totalDownForce = grav * m_vehicleMass;
 | 
			
		||||
            if (totalDownForce != Vector3.Zero)
 | 
			
		||||
            {
 | 
			
		||||
                Prim.AddForce(totalDownForce, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
 | 
			
		||||
                                Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
 | 
			
		||||
                                newVelocity, Prim.Velocity, totalDownForce);
 | 
			
		||||
 | 
			
		||||
        } // end MoveLinear()
 | 
			
		||||
 | 
			
		||||
        public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
            // If below the terrain, move us above the ground a little.
 | 
			
		||||
            // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
 | 
			
		||||
            //     TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
 | 
			
		||||
            // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
 | 
			
		||||
            // if (rotatedSize.Z < terrainHeight)
 | 
			
		||||
            if (pos.Z < terrainHeight)
 | 
			
		||||
            {
 | 
			
		||||
                // TODO: correct position by applying force rather than forcing position.
 | 
			
		||||
                pos.Z = terrainHeight + 2;
 | 
			
		||||
                Prim.ForcePosition = pos;
 | 
			
		||||
                VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
 | 
			
		||||
            }
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // Check if hovering
 | 
			
		||||
            // m_VhoverEfficiency: 0=bouncy, 1=totally damped
 | 
			
		||||
            // m_VhoverTimescale: time to achieve height
 | 
			
		||||
            if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -663,7 +713,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                // We should hover, get the target height
 | 
			
		||||
                if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
 | 
			
		||||
                    m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
 | 
			
		||||
                }
 | 
			
		||||
                if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
 | 
			
		||||
                {
 | 
			
		||||
| 
						 | 
				
			
			@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    if (pos.Z > m_VhoverTargetHeight)
 | 
			
		||||
                        m_VhoverTargetHeight = pos.Z;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
 | 
			
		||||
| 
						 | 
				
			
			@ -694,28 +745,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                    // RA: where does the 50 come from?
 | 
			
		||||
                    float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
 | 
			
		||||
                    // Replace Vertical speed with correction figure if significant
 | 
			
		||||
                    if (Math.Abs(verticalError) > 0.01f)
 | 
			
		||||
                    if (verticalError > 0.01f)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_newVelocity.Z += verticalCorrectionVelocity;
 | 
			
		||||
                        ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
 | 
			
		||||
                        //KF: m_VhoverEfficiency is not yet implemented
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (verticalError < -0.01)
 | 
			
		||||
                    {
 | 
			
		||||
                        m_newVelocity.Z -= verticalCorrectionVelocity;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        m_newVelocity.Z = 0f;
 | 
			
		||||
                        ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
 | 
			
		||||
                VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
 | 
			
		||||
                                Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
 | 
			
		||||
        {
 | 
			
		||||
            bool changed = false;
 | 
			
		||||
 | 
			
		||||
            Vector3 posChange = pos - m_lastPositionVector;
 | 
			
		||||
            if (m_BlockingEndPoint != Vector3.Zero)
 | 
			
		||||
            {
 | 
			
		||||
                bool changed = false;
 | 
			
		||||
                if (pos.X >= (m_BlockingEndPoint.X - (float)1))
 | 
			
		||||
                {
 | 
			
		||||
                    pos.X -= posChange.X + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                                Prim.LocalID, m_BlockingEndPoint, posChange, pos);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return changed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            #region downForce
 | 
			
		||||
            Vector3 downForce = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
        // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
 | 
			
		||||
        //    Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when
 | 
			
		||||
        //    used with conjunction with banking: the strength of the banking will decay when the
 | 
			
		||||
        //    vehicle no longer experiences collisions. The decay timescale is the same as
 | 
			
		||||
        //    VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
 | 
			
		||||
        //    when they are in mid jump. 
 | 
			
		||||
        // TODO: this code is wrong. Also, what should it do for boats?
 | 
			
		||||
        public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
            if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                // If the vehicle is motoring into the sky, get it going back down.
 | 
			
		||||
                // Is this an angular force or both linear and angular??
 | 
			
		||||
                float distanceAboveGround = pos.Z - terrainHeight;
 | 
			
		||||
                if (distanceAboveGround > 2f)
 | 
			
		||||
                if (distanceAboveGround > 1f)
 | 
			
		||||
                {
 | 
			
		||||
                    // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
 | 
			
		||||
                    // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
 | 
			
		||||
                    downForce = new Vector3(0, 0, -distanceAboveGround);
 | 
			
		||||
                    ret = new Vector3(0, 0, -distanceAboveGround);
 | 
			
		||||
                }
 | 
			
		||||
                // TODO: this calculation is all wrong. From the description at
 | 
			
		||||
                // TODO: this calculation is wrong. From the description at
 | 
			
		||||
                //     (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
 | 
			
		||||
                //     has a decay factor. This says this force should
 | 
			
		||||
                //     be computed with a motor.
 | 
			
		||||
                VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 
 | 
			
		||||
                                    Prim.LocalID, distanceAboveGround, downForce);
 | 
			
		||||
                // TODO: add interaction with banking.
 | 
			
		||||
                VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
 | 
			
		||||
                                    Prim.LocalID, distanceAboveGround, ret);
 | 
			
		||||
            }
 | 
			
		||||
            #endregion // downForce
 | 
			
		||||
 | 
			
		||||
            // If not changing some axis, reduce out velocity
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_X)) != 0)
 | 
			
		||||
                m_newVelocity.X = 0;
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_Y)) != 0)
 | 
			
		||||
                m_newVelocity.Y = 0;
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_Z)) != 0)
 | 
			
		||||
                m_newVelocity.Z = 0;
 | 
			
		||||
 | 
			
		||||
            // Clamp REALLY high or low velocities
 | 
			
		||||
            if (m_newVelocity.LengthSquared() > 1e6f)
 | 
			
		||||
            {
 | 
			
		||||
                m_newVelocity /= m_newVelocity.Length();
 | 
			
		||||
                m_newVelocity *= 1000f;
 | 
			
		||||
            }
 | 
			
		||||
            else if (m_newVelocity.LengthSquared() < 1e-6f)
 | 
			
		||||
                m_newVelocity = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // Stuff new linear velocity into the vehicle
 | 
			
		||||
            Prim.ForceVelocity = m_newVelocity;
 | 
			
		||||
            // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false);    // DEBUG DEBUG
 | 
			
		||||
 | 
			
		||||
            Vector3 totalDownForce = downForce + grav;
 | 
			
		||||
            if (totalDownForce != Vector3.Zero)
 | 
			
		||||
            {
 | 
			
		||||
                Prim.AddForce(totalDownForce * m_vehicleMass, false);
 | 
			
		||||
                // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
 | 
			
		||||
                    Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
 | 
			
		||||
 | 
			
		||||
        } // end MoveLinear()
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // =======================================================================
 | 
			
		||||
        // =======================================================================
 | 
			
		||||
        // Apply the effect of the angular motor.
 | 
			
		||||
        private void MoveAngular(float pTimestep)
 | 
			
		||||
        {
 | 
			
		||||
            // m_angularMotorDirection         // angular velocity requested by LSL motor
 | 
			
		||||
            // m_angularMotorApply             // application frame counter
 | 
			
		||||
            // m_angularMotorVelocity          // current angular motor velocity (ramps up and down)
 | 
			
		||||
            // m_angularMotorTimescale         // motor angular velocity ramp up rate
 | 
			
		||||
            // m_angularMotorTimescale         // motor angular velocity ramp up time
 | 
			
		||||
            // m_angularMotorDecayTimescale    // motor angular velocity decay rate
 | 
			
		||||
            // m_angularFrictionTimescale      // body angular velocity  decay rate
 | 
			
		||||
            // m_lastAngularVelocity           // what was last applied to body
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
            if (m_angularMotorDirection.LengthSquared() > 0.0001)
 | 
			
		||||
            {
 | 
			
		||||
                Vector3 origVel = m_angularMotorVelocity;
 | 
			
		||||
| 
						 | 
				
			
			@ -835,141 +867,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
            {
 | 
			
		||||
                m_angularMotorVelocity = Vector3.Zero;
 | 
			
		||||
            }
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            #region Vertical attactor
 | 
			
		||||
            Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
 | 
			
		||||
 | 
			
		||||
            Vector3 vertattr = Vector3.Zero;
 | 
			
		||||
            Vector3 deflection = Vector3.Zero;
 | 
			
		||||
            Vector3 banking = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // If vertical attaction timescale is reasonable and we applied an angular force last time...
 | 
			
		||||
            if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
 | 
			
		||||
            //    This flag prevents linear deflection parallel to world z-axis. This is useful
 | 
			
		||||
            //    for preventing ground vehicles with large linear deflection, like bumper cars,
 | 
			
		||||
            //    from climbing their linear deflection into the sky. 
 | 
			
		||||
            // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
 | 
			
		||||
                if (Prim.IsColliding)
 | 
			
		||||
                    VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
 | 
			
		||||
 | 
			
		||||
                VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
 | 
			
		||||
 | 
			
		||||
                // Create a vector of the vehicle "up" in world coordinates
 | 
			
		||||
                Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
 | 
			
		||||
                // verticalError.X and .Y are the World error amounts. They are 0 when there is no
 | 
			
		||||
                //      error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
 | 
			
		||||
                //      side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
 | 
			
		||||
                //      and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
 | 
			
		||||
                //      modulated to prevent a stable inverted body.
 | 
			
		||||
 | 
			
		||||
                // Error is 0 (no error) to +/- 2 (max error)
 | 
			
		||||
                if (verticalError.Z < 0.0f)
 | 
			
		||||
                {
 | 
			
		||||
                    verticalError.X = 2.0f - verticalError.X;
 | 
			
		||||
                    verticalError.Y = 2.0f - verticalError.Y;
 | 
			
		||||
                }
 | 
			
		||||
                // scale it by VAservo (timestep and timescale)
 | 
			
		||||
                verticalError = verticalError * VAservo;
 | 
			
		||||
 | 
			
		||||
                // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
 | 
			
		||||
                //     then .X increases, so change  Body angular velocity  X based on Y, and Y based on X.
 | 
			
		||||
                //     Z is not changed.
 | 
			
		||||
                vertattr.X =    verticalError.Y;
 | 
			
		||||
                vertattr.Y =  - verticalError.X;
 | 
			
		||||
                vertattr.Z = 0f;
 | 
			
		||||
 | 
			
		||||
                // scaling appears better usingsquare-law
 | 
			
		||||
                Vector3 angularVelocity = Prim.ForceRotationalVelocity;
 | 
			
		||||
                float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
 | 
			
		||||
                vertattr.X += bounce * angularVelocity.X;
 | 
			
		||||
                vertattr.Y += bounce * angularVelocity.Y;
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
 | 
			
		||||
                            Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            #endregion // Vertical attactor
 | 
			
		||||
 | 
			
		||||
            #region Deflection
 | 
			
		||||
 | 
			
		||||
            if (m_angularDeflectionEfficiency != 0)
 | 
			
		||||
            {
 | 
			
		||||
                // Compute a scaled vector that points in the preferred axis (X direction)
 | 
			
		||||
                Vector3 scaledDefaultDirection =
 | 
			
		||||
                    new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
 | 
			
		||||
                // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
 | 
			
		||||
                // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
 | 
			
		||||
                Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
 | 
			
		||||
 | 
			
		||||
                // Scale by efficiency and timescale
 | 
			
		||||
                deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", 
 | 
			
		||||
                                        Prim.LocalID, preferredAxisOfMotion, deflection);
 | 
			
		||||
                // This deflection computation is not correct.
 | 
			
		||||
                deflection = Vector3.Zero;
 | 
			
		||||
                angularMotorContribution.X = 0f;
 | 
			
		||||
                angularMotorContribution.Y = 0f;
 | 
			
		||||
                VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #endregion
 | 
			
		||||
            Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
 | 
			
		||||
 | 
			
		||||
            #region Banking
 | 
			
		||||
            Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
 | 
			
		||||
 | 
			
		||||
            if (m_bankingEfficiency != 0)
 | 
			
		||||
            {
 | 
			
		||||
                Vector3 dir = Vector3.One * Prim.ForceOrientation;
 | 
			
		||||
                float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
 | 
			
		||||
                    //Changes which way it banks in and out of turns
 | 
			
		||||
            Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
 | 
			
		||||
 | 
			
		||||
                //Use the square of the efficiency, as it looks much more how SL banking works
 | 
			
		||||
                float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
 | 
			
		||||
                if (m_bankingEfficiency < 0)
 | 
			
		||||
                    effSquared *= -1; //Keep the negative!
 | 
			
		||||
 | 
			
		||||
                float mix = Math.Abs(m_bankingMix);
 | 
			
		||||
                if (m_angularMotorVelocity.X == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
 | 
			
		||||
                    {
 | 
			
		||||
                        Vector3 axisAngle;
 | 
			
		||||
                        float angle;
 | 
			
		||||
                        parent.Orientation.GetAxisAngle(out axisAngle, out angle);
 | 
			
		||||
                        Vector3 rotatedVel = parent.Velocity * parent.Orientation;
 | 
			
		||||
                        if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
 | 
			
		||||
                            m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
 | 
			
		||||
                        else
 | 
			
		||||
                            m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
 | 
			
		||||
                    }*/
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                    banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
 | 
			
		||||
                if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
 | 
			
		||||
                    //If they are colliding, we probably shouldn't shove the prim around... probably
 | 
			
		||||
                {
 | 
			
		||||
                    float angVelZ = m_angularMotorVelocity.X*-1;
 | 
			
		||||
                    /*if(angVelZ > mix)
 | 
			
		||||
                        angVelZ = mix;
 | 
			
		||||
                    else if(angVelZ < -mix)
 | 
			
		||||
                        angVelZ = -mix;*/
 | 
			
		||||
                    //This controls how fast and how far the banking occurs
 | 
			
		||||
                    Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
 | 
			
		||||
                    if (bankingRot.X > 3)
 | 
			
		||||
                        bankingRot.X = 3;
 | 
			
		||||
                    else if (bankingRot.X < -3)
 | 
			
		||||
                        bankingRot.X = -3;
 | 
			
		||||
                    bankingRot *= Prim.ForceOrientation;
 | 
			
		||||
                    banking += bankingRot;
 | 
			
		||||
                }
 | 
			
		||||
                m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
 | 
			
		||||
                VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", 
 | 
			
		||||
                                Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            m_lastVertAttractor = vertattr;
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            m_lastVertAttractor = verticalAttractionContribution;
 | 
			
		||||
 | 
			
		||||
            // Sum velocities
 | 
			
		||||
            m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
 | 
			
		||||
 | 
			
		||||
            #region Linear Motor Offset
 | 
			
		||||
            m_lastAngularVelocity = angularMotorContribution
 | 
			
		||||
                                    + verticalAttractionContribution
 | 
			
		||||
                                    + deflectionContribution
 | 
			
		||||
                                    + bankingContribution;
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            //Offset section
 | 
			
		||||
            if (m_linearMotorOffset != Vector3.Zero)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -985,8 +915,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                //
 | 
			
		||||
                // The torque created is the linear velocity crossed with the offset
 | 
			
		||||
 | 
			
		||||
                // NOTE: this computation does should be in the linear section
 | 
			
		||||
                //    because there we know the impulse being applied.
 | 
			
		||||
                // TODO: this computation should be in the linear section
 | 
			
		||||
                //    because that is where we know the impulse being applied.
 | 
			
		||||
                Vector3 torqueFromOffset = Vector3.Zero;
 | 
			
		||||
                // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
 | 
			
		||||
                if (float.IsNaN(torqueFromOffset.X))
 | 
			
		||||
| 
						 | 
				
			
			@ -1000,20 +930,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #endregion
 | 
			
		||||
 | 
			
		||||
            if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                m_lastAngularVelocity.X = 0;
 | 
			
		||||
                m_lastAngularVelocity.Y = 0;
 | 
			
		||||
                VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // ==================================================================
 | 
			
		||||
            if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
 | 
			
		||||
            {
 | 
			
		||||
                m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
 | 
			
		||||
                Prim.ZeroAngularMotion(true);
 | 
			
		||||
                // TODO: zeroing is good but it also sets values in unmanaged code. Remove the stores when idle.
 | 
			
		||||
                VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
 | 
			
		||||
                Prim.ZeroAngularMotion(true);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -1021,18 +944,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		|||
                // The above calculates the absolute angular velocity needed. Angular velocity is massless.
 | 
			
		||||
                // Since we are stuffing the angular velocity directly into the object, the computed
 | 
			
		||||
                //     velocity needs to be scaled by the timestep.
 | 
			
		||||
                Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
 | 
			
		||||
                // Also remove any motion that is on the object so added motion is only from vehicle.
 | 
			
		||||
                Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
 | 
			
		||||
                                                - Prim.ForceRotationalVelocity);
 | 
			
		||||
                // Unscale the force by the angular factor so it overwhelmes the Bullet additions.
 | 
			
		||||
                Prim.ForceRotationalVelocity = applyAngularForce;
 | 
			
		||||
 | 
			
		||||
                // Decay the angular movement for next time
 | 
			
		||||
                Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
 | 
			
		||||
                m_lastAngularVelocity *= Vector3.One - decayamount;
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 
 | 
			
		||||
                                    Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
 | 
			
		||||
                VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
 | 
			
		||||
                                    Prim.LocalID,
 | 
			
		||||
                                    angularMotorContribution, verticalAttractionContribution,
 | 
			
		||||
                                    bankingContribution, deflectionContribution,
 | 
			
		||||
                                    applyAngularForce, m_lastAngularVelocity
 | 
			
		||||
                                    );
 | 
			
		||||
            }
 | 
			
		||||
        } //end MoveAngular
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // If vertical attaction timescale is reasonable and we applied an angular force last time...
 | 
			
		||||
            if (m_verticalAttractionTimescale < 500)
 | 
			
		||||
            {
 | 
			
		||||
                Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
 | 
			
		||||
                verticalError.Normalize();
 | 
			
		||||
                m_verticalAttractionMotor.SetCurrent(verticalError);
 | 
			
		||||
                m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
 | 
			
		||||
                ret = m_verticalAttractionMotor.Step(pTimestep);
 | 
			
		||||
                /*
 | 
			
		||||
                // Take a vector pointing up and convert it from world to vehicle relative coords.
 | 
			
		||||
                Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
 | 
			
		||||
                verticalError.Normalize();
 | 
			
		||||
 | 
			
		||||
                // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
 | 
			
		||||
                //    is now leaning to one side (rotated around the X axis) and the Y value will
 | 
			
		||||
                //    go from zero (nearly straight up) to one (completely to the side) or leaning
 | 
			
		||||
                //    front-to-back (rotated around the Y axis) and the value of X will be between
 | 
			
		||||
                //    zero and one.
 | 
			
		||||
                // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
 | 
			
		||||
 | 
			
		||||
                // 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;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Y error means needed rotation around X axis and visa versa.
 | 
			
		||||
                verticalAttractionContribution.X =    verticalError.Y;
 | 
			
		||||
                verticalAttractionContribution.Y =  - verticalError.X;
 | 
			
		||||
                verticalAttractionContribution.Z = 0f;
 | 
			
		||||
 | 
			
		||||
                // scale by the time scale and timestep
 | 
			
		||||
                Vector3 unscaledContrib = verticalAttractionContribution;
 | 
			
		||||
                verticalAttractionContribution /= m_verticalAttractionTimescale;
 | 
			
		||||
                verticalAttractionContribution *= pTimestep;
 | 
			
		||||
 | 
			
		||||
                // apply efficiency
 | 
			
		||||
                Vector3 preEfficiencyContrib = verticalAttractionContribution;
 | 
			
		||||
                float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
 | 
			
		||||
                verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
 | 
			
		||||
                                            Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
 | 
			
		||||
                                            m_verticalAttractionEfficiency, efficencySquared,
 | 
			
		||||
                                            verticalAttractionContribution);
 | 
			
		||||
                 */
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Vector3 ComputeAngularDeflection(float pTimestep)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            if (m_angularDeflectionEfficiency != 0)
 | 
			
		||||
            {
 | 
			
		||||
                // Compute a scaled vector that points in the preferred axis (X direction)
 | 
			
		||||
                Vector3 scaledDefaultDirection =
 | 
			
		||||
                    new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
 | 
			
		||||
                // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
 | 
			
		||||
                // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
 | 
			
		||||
                Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
 | 
			
		||||
 | 
			
		||||
                // Scale by efficiency and timescale
 | 
			
		||||
                ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
 | 
			
		||||
 | 
			
		||||
                VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
 | 
			
		||||
 | 
			
		||||
                // This deflection computation is not correct.
 | 
			
		||||
                ret = Vector3.Zero;
 | 
			
		||||
            }
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Vector3 ComputeAngularBanking(float pTimestep)
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 ret = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            if (m_bankingEfficiency != 0)
 | 
			
		||||
            {
 | 
			
		||||
                Vector3 dir = Vector3.One * Prim.ForceOrientation;
 | 
			
		||||
                float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
 | 
			
		||||
                //Changes which way it banks in and out of turns
 | 
			
		||||
 | 
			
		||||
                //Use the square of the efficiency, as it looks much more how SL banking works
 | 
			
		||||
                float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
 | 
			
		||||
                if (m_bankingEfficiency < 0)
 | 
			
		||||
                    effSquared *= -1; //Keep the negative!
 | 
			
		||||
 | 
			
		||||
                float mix = Math.Abs(m_bankingMix);
 | 
			
		||||
                if (m_angularMotorVelocity.X == 0)
 | 
			
		||||
                {
 | 
			
		||||
                    // The vehicle is stopped
 | 
			
		||||
                    /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
 | 
			
		||||
                    {
 | 
			
		||||
                        Vector3 axisAngle;
 | 
			
		||||
                        float angle;
 | 
			
		||||
                        parent.Orientation.GetAxisAngle(out axisAngle, out angle);
 | 
			
		||||
                        Vector3 rotatedVel = parent.Velocity * parent.Orientation;
 | 
			
		||||
                        if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
 | 
			
		||||
                            m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
 | 
			
		||||
                        else
 | 
			
		||||
                            m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
 | 
			
		||||
                    }*/
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //If they are colliding, we probably shouldn't shove the prim around... probably
 | 
			
		||||
                if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
 | 
			
		||||
                {
 | 
			
		||||
                    float angVelZ = m_angularMotorVelocity.X * -1;
 | 
			
		||||
                    /*if(angVelZ > mix)
 | 
			
		||||
                        angVelZ = mix;
 | 
			
		||||
                    else if(angVelZ < -mix)
 | 
			
		||||
                        angVelZ = -mix;*/
 | 
			
		||||
                    //This controls how fast and how far the banking occurs
 | 
			
		||||
                    Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
 | 
			
		||||
                    if (bankingRot.X > 3)
 | 
			
		||||
                        bankingRot.X = 3;
 | 
			
		||||
                    else if (bankingRot.X < -3)
 | 
			
		||||
                        bankingRot.X = -3;
 | 
			
		||||
                    bankingRot *= Prim.ForceOrientation;
 | 
			
		||||
                    ret += bankingRot;
 | 
			
		||||
                }
 | 
			
		||||
                m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
 | 
			
		||||
                VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
 | 
			
		||||
                                Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
 | 
			
		||||
            }
 | 
			
		||||
            return ret;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // This is from previous instantiations of XXXDynamics.cs.
 | 
			
		||||
        // Applies roll reference frame.
 | 
			
		||||
        // TODO: is this the right way to separate the code to do this operation?
 | 
			
		||||
        //    Should this be in MoveAngular()?
 | 
			
		||||
        internal void LimitRotation(float timestep)
 | 
			
		||||
        {
 | 
			
		||||
            Quaternion rotq = Prim.ForceOrientation;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
/*
 | 
			
		||||
 * 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 System.Reflection;
 | 
			
		||||
using Nini.Config;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
public struct MaterialAttributes
 | 
			
		||||
{
 | 
			
		||||
    // Material type values that correspond with definitions for LSL
 | 
			
		||||
    public enum Material : int
 | 
			
		||||
    {
 | 
			
		||||
        Stone = 0,
 | 
			
		||||
        Metal,
 | 
			
		||||
        Glass,
 | 
			
		||||
        Wood,
 | 
			
		||||
        Flesh,
 | 
			
		||||
        Plastic,
 | 
			
		||||
        Rubber,
 | 
			
		||||
        Light,
 | 
			
		||||
        // Hereafter are BulletSim additions
 | 
			
		||||
        Avatar,
 | 
			
		||||
        NumberOfTypes   // the count of types in the enum.
 | 
			
		||||
    }
 | 
			
		||||
    // Names must be in the order of the above enum.
 | 
			
		||||
    public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 
 | 
			
		||||
                                     "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
 | 
			
		||||
    public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", 
 | 
			
		||||
                                   "ccdMotionThreshold", "ccdSweptSphereRadius" };
 | 
			
		||||
 | 
			
		||||
    public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
 | 
			
		||||
    {
 | 
			
		||||
        type = t;
 | 
			
		||||
        density = d;
 | 
			
		||||
        friction = f;
 | 
			
		||||
        restitution = r;
 | 
			
		||||
        ccdMotionThreshold = ccdM;
 | 
			
		||||
        ccdSweptSphereRadius = ccdS;
 | 
			
		||||
    }
 | 
			
		||||
    public string type;
 | 
			
		||||
    public float density;
 | 
			
		||||
    public float friction;
 | 
			
		||||
    public float restitution;
 | 
			
		||||
    public float ccdMotionThreshold;
 | 
			
		||||
    public float ccdSweptSphereRadius;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public static class BSMaterials
 | 
			
		||||
{
 | 
			
		||||
    public static MaterialAttributes[] Attributes;
 | 
			
		||||
 | 
			
		||||
    static BSMaterials()
 | 
			
		||||
    {
 | 
			
		||||
        // Attribute sets for both the non-physical and physical instances of materials.
 | 
			
		||||
        Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This is where all the default material attributes are defined.
 | 
			
		||||
    public static void InitializeFromDefaults(ConfigurationParameters parms)
 | 
			
		||||
    {
 | 
			
		||||
    // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", 
 | 
			
		||||
      //                                "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
 | 
			
		||||
        float dFriction = parms.defaultFriction;
 | 
			
		||||
        float dRestitution = parms.defaultRestitution;
 | 
			
		||||
        float dDensity = parms.defaultDensity;
 | 
			
		||||
        float dCcdM = parms.ccdMotionThreshold;
 | 
			
		||||
        float dCcdS = parms.ccdSweptSphereRadius;
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Stone] =
 | 
			
		||||
            new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Metal] =
 | 
			
		||||
            new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Glass] =
 | 
			
		||||
            new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Wood] =
 | 
			
		||||
            new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Flesh] =
 | 
			
		||||
            new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Plastic] =
 | 
			
		||||
            new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Rubber] =
 | 
			
		||||
            new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Light] =
 | 
			
		||||
            new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Avatar] =
 | 
			
		||||
            new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
        Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
 | 
			
		||||
            new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Under the [BulletSim] section, one can change the individual material
 | 
			
		||||
    //    attribute values. The format of the configuration parameter is:
 | 
			
		||||
    //        <materialName><Attribute>["Physical"] = floatValue
 | 
			
		||||
    //    For instance:
 | 
			
		||||
    //        [BulletSim]
 | 
			
		||||
    //             StoneFriction = 0.2
 | 
			
		||||
    //             FleshRestitutionPhysical = 0.8
 | 
			
		||||
    // Materials can have different parameters for their static and
 | 
			
		||||
    //    physical instantiations. When setting the non-physical value,
 | 
			
		||||
    //    both values are changed. Setting the physical value only changes
 | 
			
		||||
    //    the physical value.
 | 
			
		||||
    public static void InitializefromParameters(IConfig pConfig)
 | 
			
		||||
    {
 | 
			
		||||
        int matType = 0;
 | 
			
		||||
        foreach (string matName in MaterialAttributes.MaterialNames)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (string attribName in MaterialAttributes.MaterialAttribs)
 | 
			
		||||
            {
 | 
			
		||||
                string paramName = matName + attribName;
 | 
			
		||||
                if (pConfig.Contains(paramName))
 | 
			
		||||
                {
 | 
			
		||||
                    float paramValue = pConfig.GetFloat(paramName);
 | 
			
		||||
                    SetAttributeValue(matType, attribName, paramValue);
 | 
			
		||||
                    // set the physical value also
 | 
			
		||||
                    SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
 | 
			
		||||
                }
 | 
			
		||||
                paramName += "Physical";
 | 
			
		||||
                if (pConfig.Contains(paramName))
 | 
			
		||||
                {
 | 
			
		||||
                    float paramValue = pConfig.GetFloat(paramName);
 | 
			
		||||
                    SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            matType++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void SetAttributeValue(int matType, string attribName, float val)
 | 
			
		||||
    {
 | 
			
		||||
        MaterialAttributes thisAttrib = Attributes[matType];
 | 
			
		||||
        FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
 | 
			
		||||
        if (fieldInfo != null)
 | 
			
		||||
        {
 | 
			
		||||
            fieldInfo.SetValue(thisAttrib, val);
 | 
			
		||||
            Attributes[matType] = thisAttrib;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
 | 
			
		||||
    {
 | 
			
		||||
        int ind = (int)type;
 | 
			
		||||
        if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
 | 
			
		||||
        return Attributes[ind];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,104 +1,169 @@
 | 
			
		|||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
namespace OpenSim.Region.Physics.BulletSPlugin
 | 
			
		||||
{
 | 
			
		||||
public abstract class BSMotor
 | 
			
		||||
{
 | 
			
		||||
    public virtual void Reset() { }
 | 
			
		||||
    public virtual void Zero() { }
 | 
			
		||||
}
 | 
			
		||||
// Can all the incremental stepping be replaced with motor classes?
 | 
			
		||||
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 CurrentValueReductionTimescale { get; set; }
 | 
			
		||||
    public float Efficiency { get; set; }
 | 
			
		||||
 | 
			
		||||
    public Vector3 TargetValue { get; private set; }
 | 
			
		||||
    public Vector3 CurrentValue { get; private set; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
 | 
			
		||||
    {
 | 
			
		||||
        TimeScale = timeScale;
 | 
			
		||||
        TargetValueDecayTimeScale = decayTimeScale;
 | 
			
		||||
        CurrentValueReductionTimescale = frictionTimeScale;
 | 
			
		||||
        Efficiency = efficiency;
 | 
			
		||||
    }
 | 
			
		||||
    public void SetCurrent(Vector3 current)
 | 
			
		||||
    {
 | 
			
		||||
        CurrentValue = current;
 | 
			
		||||
    }
 | 
			
		||||
    public void SetTarget(Vector3 target)
 | 
			
		||||
    {
 | 
			
		||||
        TargetValue = target;
 | 
			
		||||
    }
 | 
			
		||||
    public Vector3 Step(float timeStep)
 | 
			
		||||
    {
 | 
			
		||||
        if (CurrentValue.LengthSquared() > 0.001f)
 | 
			
		||||
        {
 | 
			
		||||
            // Vector3 origDir = Target;       // DEBUG
 | 
			
		||||
            // Vector3 origVel = CurrentValue;   // DEBUG
 | 
			
		||||
 | 
			
		||||
            // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
 | 
			
		||||
            Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
 | 
			
		||||
            CurrentValue += addAmount;
 | 
			
		||||
 | 
			
		||||
            float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
 | 
			
		||||
            TargetValue *= (1f - decayFactor);
 | 
			
		||||
 | 
			
		||||
            Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
 | 
			
		||||
            CurrentValue *= (Vector3.One - frictionFactor);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // if what remains of direction is very small, zero it.
 | 
			
		||||
            TargetValue = Vector3.Zero;
 | 
			
		||||
            CurrentValue = Vector3.Zero;
 | 
			
		||||
 | 
			
		||||
            // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
 | 
			
		||||
        }
 | 
			
		||||
        return CurrentValue;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class BSFMotor : BSMotor
 | 
			
		||||
{
 | 
			
		||||
    public float TimeScale { get; set; }
 | 
			
		||||
    public float DecayTimeScale { get; set; }
 | 
			
		||||
    public float Friction { get; set; }
 | 
			
		||||
    public float Efficiency { get; set; }
 | 
			
		||||
 | 
			
		||||
    public float Target { get; private set; }
 | 
			
		||||
    public float CurrentValue { get; private set; }
 | 
			
		||||
 | 
			
		||||
    BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public void SetCurrent(float target)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public void SetTarget(float target)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public float Step(float timeStep)
 | 
			
		||||
    {
 | 
			
		||||
        return 0f;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
public class BSPIDMotor : BSMotor
 | 
			
		||||
{
 | 
			
		||||
    // TODO: write and use this one
 | 
			
		||||
    BSPIDMotor()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Text;
 | 
			
		||||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
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 = 10000f;
 | 
			
		||||
    public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
 | 
			
		||||
 | 
			
		||||
    public BSMotor(string useName)
 | 
			
		||||
    {
 | 
			
		||||
        UseName = useName;
 | 
			
		||||
        PhysicsScene = null;
 | 
			
		||||
    }
 | 
			
		||||
    public virtual void Reset() { }
 | 
			
		||||
    public virtual void Zero() { }
 | 
			
		||||
 | 
			
		||||
    public string UseName { get; private set; }
 | 
			
		||||
    // Used only for outputting debug information. Might not be set so check for null.
 | 
			
		||||
    public BSScene PhysicsScene { get; set; }
 | 
			
		||||
    protected void MDetailLog(string msg, params Object[] parms)
 | 
			
		||||
    {
 | 
			
		||||
        if (PhysicsScene != null)
 | 
			
		||||
        {
 | 
			
		||||
            if (PhysicsScene.VehicleLoggingEnabled)
 | 
			
		||||
            {
 | 
			
		||||
                PhysicsScene.DetailLog(msg, parms);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
// Can all the incremental stepping be replaced with motor classes?
 | 
			
		||||
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 Vector3 TargetValue { get; private set; }
 | 
			
		||||
    public Vector3 CurrentValue { get; private set; }
 | 
			
		||||
 | 
			
		||||
    public BSVMotor(string useName)
 | 
			
		||||
        : base(useName)
 | 
			
		||||
    {
 | 
			
		||||
        TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
 | 
			
		||||
        Efficiency = 1f;
 | 
			
		||||
        FrictionTimescale = BSMotor.InfiniteVector;
 | 
			
		||||
        CurrentValue = TargetValue = Vector3.Zero;
 | 
			
		||||
    }
 | 
			
		||||
    public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 
 | 
			
		||||
        : this(useName)
 | 
			
		||||
    {
 | 
			
		||||
        TimeScale = timeScale;
 | 
			
		||||
        TargetValueDecayTimeScale = decayTimeScale;
 | 
			
		||||
        FrictionTimescale = frictionTimeScale;
 | 
			
		||||
        Efficiency = efficiency;
 | 
			
		||||
        CurrentValue = TargetValue = Vector3.Zero;
 | 
			
		||||
    }
 | 
			
		||||
    public void SetCurrent(Vector3 current)
 | 
			
		||||
    {
 | 
			
		||||
        CurrentValue = current;
 | 
			
		||||
    }
 | 
			
		||||
    public void SetTarget(Vector3 target)
 | 
			
		||||
    {
 | 
			
		||||
        TargetValue = target;
 | 
			
		||||
    }
 | 
			
		||||
    public Vector3 Step(float timeStep)
 | 
			
		||||
    {
 | 
			
		||||
        Vector3 returnCurrent = Vector3.Zero;
 | 
			
		||||
        if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
 | 
			
		||||
        {
 | 
			
		||||
            Vector3 origTarget = TargetValue;       // DEBUG
 | 
			
		||||
            Vector3 origCurrVal = CurrentValue;   // DEBUG
 | 
			
		||||
 | 
			
		||||
            // Addition =  (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
 | 
			
		||||
            Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
 | 
			
		||||
            CurrentValue += addAmount;
 | 
			
		||||
 | 
			
		||||
            returnCurrent = CurrentValue;
 | 
			
		||||
 | 
			
		||||
            // The desired value reduces to zero which also reduces the difference with current.
 | 
			
		||||
            // If the decay time is infinite, don't decay at all.
 | 
			
		||||
            float decayFactor = 0f;
 | 
			
		||||
            if (TargetValueDecayTimeScale != BSMotor.Infinite)
 | 
			
		||||
            {
 | 
			
		||||
                decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
 | 
			
		||||
                TargetValue *= (1f - decayFactor);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Vector3 frictionFactor = Vector3.Zero;
 | 
			
		||||
            if (FrictionTimescale != BSMotor.InfiniteVector)
 | 
			
		||||
            {
 | 
			
		||||
                // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
 | 
			
		||||
                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;
 | 
			
		||||
                CurrentValue *= (Vector3.One - frictionFactor);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
 | 
			
		||||
                                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);
 | 
			
		||||
        }
 | 
			
		||||
        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},curr={2},target={3},ret={4}",
 | 
			
		||||
                                    BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
        return returnCurrent;
 | 
			
		||||
    }
 | 
			
		||||
    public override string ToString()
 | 
			
		||||
    {
 | 
			
		||||
        return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
 | 
			
		||||
            UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public class BSFMotor : BSMotor
 | 
			
		||||
{
 | 
			
		||||
    public float TimeScale { get; set; }
 | 
			
		||||
    public float DecayTimeScale { get; set; }
 | 
			
		||||
    public float Friction { get; set; }
 | 
			
		||||
    public float Efficiency { get; set; }
 | 
			
		||||
 | 
			
		||||
    public float Target { get; private set; }
 | 
			
		||||
    public float CurrentValue { get; private set; }
 | 
			
		||||
 | 
			
		||||
    public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
 | 
			
		||||
        : base(useName)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public void SetCurrent(float target)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public void SetTarget(float target)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
    public float Step(float timeStep)
 | 
			
		||||
    {
 | 
			
		||||
        return 0f;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
public class BSPIDMotor : BSMotor
 | 
			
		||||
{
 | 
			
		||||
    // TODO: write and use this one
 | 
			
		||||
    public BSPIDMotor(string useName)
 | 
			
		||||
        : base(useName)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
 | 
			
		|||
        // Zero some other properties in the physics engine
 | 
			
		||||
        PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
 | 
			
		||||
        {
 | 
			
		||||
            BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
 | 
			
		||||
            BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
 | 
			
		||||
            // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
 | 
			
		||||
            BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
 | 
			
		||||
            BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
 | 
			
		|||
 | 
			
		||||
        if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
 | 
			
		||||
        {
 | 
			
		||||
            float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
 | 
			
		||||
            float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
 | 
			
		||||
            // TODO: a floating motor so object will bob in the water
 | 
			
		||||
            if (Math.Abs(Position.Z - waterHeight) > 0.1f)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject
 | 
			
		|||
        // TODO: check for out of bounds
 | 
			
		||||
 | 
			
		||||
        // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
 | 
			
		||||
        // TODO: This should be intergrated with a geneal physics action mechanism.
 | 
			
		||||
        // TODO: This should be moderated with PID'ness.
 | 
			
		||||
        if (ret)
 | 
			
		||||
        {
 | 
			
		||||
            PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
 | 
			
		||||
            {
 | 
			
		||||
                // Apply upforce and overcome gravity.
 | 
			
		||||
                ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
 | 
			
		||||
            });
 | 
			
		||||
            // Apply upforce and overcome gravity.
 | 
			
		||||
            AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
 | 
			
		|||
 | 
			
		||||
    public override void UpdateProperties(EntityProperties entprop)
 | 
			
		||||
    {
 | 
			
		||||
        /*
 | 
			
		||||
        UpdatedProperties changed = 0;
 | 
			
		||||
        // assign to the local variables so the normal set action does not happen
 | 
			
		||||
        // if (_position != entprop.Position)
 | 
			
		||||
        if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
 | 
			
		||||
        {
 | 
			
		||||
            _position = entprop.Position;
 | 
			
		||||
            changed |= UpdatedProperties.Position;
 | 
			
		||||
        }
 | 
			
		||||
        // if (_orientation != entprop.Rotation)
 | 
			
		||||
        if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
 | 
			
		||||
        {
 | 
			
		||||
            _orientation = entprop.Rotation;
 | 
			
		||||
            changed |= UpdatedProperties.Rotation;
 | 
			
		||||
        }
 | 
			
		||||
        // if (_velocity != entprop.Velocity)
 | 
			
		||||
        if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
 | 
			
		||||
        {
 | 
			
		||||
            _velocity = entprop.Velocity;
 | 
			
		||||
            changed |= UpdatedProperties.Velocity;
 | 
			
		||||
        }
 | 
			
		||||
        // if (_acceleration != entprop.Acceleration)
 | 
			
		||||
        if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
 | 
			
		||||
        {
 | 
			
		||||
            _acceleration = entprop.Acceleration;
 | 
			
		||||
            changed |= UpdatedProperties.Acceleration;
 | 
			
		||||
        }
 | 
			
		||||
        // if (_rotationalVelocity != entprop.RotationalVelocity)
 | 
			
		||||
        if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
 | 
			
		||||
        {
 | 
			
		||||
            _rotationalVelocity = entprop.RotationalVelocity;
 | 
			
		||||
            changed |= UpdatedProperties.RotationalVel;
 | 
			
		||||
        }
 | 
			
		||||
        if (changed != 0)
 | 
			
		||||
        {
 | 
			
		||||
            // Only update the position of single objects and linkset roots
 | 
			
		||||
            if (Linkset.IsRoot(this))
 | 
			
		||||
            {
 | 
			
		||||
                base.RequestPhysicsterseUpdate();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
 | 
			
		||||
 | 
			
		||||
        // Updates only for individual prims and for the root object of a linkset.
 | 
			
		||||
        if (Linkset.IsRoot(this))
 | 
			
		||||
        {
 | 
			
		||||
            // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
 | 
			
		||||
            // TODO: handle physics introduced by Bullet with computed vehicle physics.
 | 
			
		||||
            if (_vehicle.IsActive)
 | 
			
		||||
            {
 | 
			
		||||
                entprop.RotationalVelocity = OMV.Vector3.Zero;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Assign directly to the local variables so the normal set action does not happen
 | 
			
		||||
            _position = entprop.Position;
 | 
			
		||||
            _orientation = entprop.Rotation;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,23 +39,10 @@ using log4net;
 | 
			
		|||
using OpenMetaverse;
 | 
			
		||||
 | 
			
		||||
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
 | 
			
		||||
// Test sculpties (verified that they don't work)
 | 
			
		||||
// Compute physics FPS reasonably
 | 
			
		||||
// Based on material, set density and friction
 | 
			
		||||
// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
 | 
			
		||||
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
 | 
			
		||||
//     In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
 | 
			
		||||
//     At the moment, physical and phantom causes object to drop through the terrain
 | 
			
		||||
// Physical phantom objects and related typing (collision options )
 | 
			
		||||
// Check out llVolumeDetect. Must do something for that.
 | 
			
		||||
// Use collision masks for collision with terrain and phantom objects
 | 
			
		||||
// More efficient memory usage when passing hull information from BSPrim to BulletSim
 | 
			
		||||
// Should prim.link() and prim.delink() membership checking happen at taint time?
 | 
			
		||||
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
 | 
			
		||||
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
 | 
			
		||||
// Implement LockAngularMotion
 | 
			
		||||
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
 | 
			
		||||
// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
 | 
			
		||||
// Add PID movement operations. What does ScenePresence.MoveToTarget do?
 | 
			
		||||
// Check terrain size. 128 or 127?
 | 
			
		||||
// Raycast
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
    public const uint GROUNDPLANE_ID = 1;
 | 
			
		||||
    public const uint CHILDTERRAIN_ID = 2;  // Terrain allocated based on our mega-prim childre start here
 | 
			
		||||
 | 
			
		||||
    private float m_waterLevel;
 | 
			
		||||
    public float SimpleWaterLevel { get; set; }
 | 
			
		||||
    public BSTerrainManager TerrainManager { get; private set; }
 | 
			
		||||
 | 
			
		||||
    public ConfigurationParameters Params
 | 
			
		||||
| 
						 | 
				
			
			@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
    private string m_physicsLoggingDir;
 | 
			
		||||
    private string m_physicsLoggingPrefix;
 | 
			
		||||
    private int m_physicsLoggingFileMinutes;
 | 
			
		||||
    private bool m_physicsLoggingDoFlush;
 | 
			
		||||
    // 'true' of the vehicle code is to log lots of details
 | 
			
		||||
    public bool VehicleLoggingEnabled { get; private set; }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
        if (m_physicsLoggingEnabled)
 | 
			
		||||
        {
 | 
			
		||||
            PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
 | 
			
		||||
            PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
                m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
 | 
			
		||||
                m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
 | 
			
		||||
                m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
 | 
			
		||||
                m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
 | 
			
		||||
                // Very detailed logging for vehicle debugging
 | 
			
		||||
                VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
 | 
			
		||||
 | 
			
		||||
                // Do any replacements in the parameters
 | 
			
		||||
                m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // The material characteristics.
 | 
			
		||||
            BSMaterials.InitializeFromDefaults(Params);
 | 
			
		||||
            if (pConfig != null)
 | 
			
		||||
            {
 | 
			
		||||
                BSMaterials.InitializefromParameters(pConfig);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -499,7 +496,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            if (VehicleLoggingEnabled) DumpVehicles();  // DEBUG
 | 
			
		||||
            // if (VehicleLoggingEnabled) DumpVehicles();  // DEBUG
 | 
			
		||||
            if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
 | 
			
		||||
 | 
			
		||||
            numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
 | 
			
		||||
| 
						 | 
				
			
			@ -508,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
 | 
			
		||||
            DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
 | 
			
		||||
                        DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
 | 
			
		||||
            if (VehicleLoggingEnabled) DumpVehicles();  // DEBUG
 | 
			
		||||
            // if (VehicleLoggingEnabled) DumpVehicles();  // DEBUG
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            collidersCount = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
 | 
			
		||||
        // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
 | 
			
		||||
 | 
			
		||||
        // Get a value for 'now' so all the collision and update routines don't have to get their own
 | 
			
		||||
        // Get a value for 'now' so all the collision and update routines don't have to get their own.
 | 
			
		||||
        SimulationNowTime = Util.EnvironmentTickCount();
 | 
			
		||||
 | 
			
		||||
        // If there were collisions, process them by sending the event to the prim.
 | 
			
		||||
| 
						 | 
				
			
			@ -568,6 +565,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
                ObjectsWithCollisions.Remove(po);
 | 
			
		||||
            ObjectsWithNoMoreCollisions.Clear();
 | 
			
		||||
        }
 | 
			
		||||
        // Done with collisions.
 | 
			
		||||
 | 
			
		||||
        // If any of the objects had updated properties, tell the object it has been changed by the physics engine
 | 
			
		||||
        if (updatedEntityCount > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -591,9 +589,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
 | 
			
		||||
        // The physics engine returns the number of milliseconds it simulated this call.
 | 
			
		||||
        // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
 | 
			
		||||
        // We multiply by 55 to give a recognizable running rate (55 or less).
 | 
			
		||||
        return numSubSteps * m_fixedTimeStep * 1000 * 55;
 | 
			
		||||
        // return timeStep * 1000 * 55;
 | 
			
		||||
        // Multiply by 55 to give a nominal frame rate of 55.
 | 
			
		||||
        return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Something has collided
 | 
			
		||||
| 
						 | 
				
			
			@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
 | 
			
		||||
    public override void SetWaterLevel(float baseheight)
 | 
			
		||||
    {
 | 
			
		||||
        m_waterLevel = baseheight;
 | 
			
		||||
    }
 | 
			
		||||
    // Someday....
 | 
			
		||||
    public float GetWaterLevelAtXYZ(Vector3 loc)
 | 
			
		||||
    {
 | 
			
		||||
        return m_waterLevel;
 | 
			
		||||
        SimpleWaterLevel = baseheight;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override void DeleteTerrain()
 | 
			
		||||
| 
						 | 
				
			
			@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            (s,p,l,v) => { s.PID_P = v; } ),
 | 
			
		||||
 | 
			
		||||
        new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
 | 
			
		||||
            0.5f,
 | 
			
		||||
            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; } ),
 | 
			
		||||
| 
						 | 
				
			
			@ -1084,7 +1076,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            (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!)",
 | 
			
		||||
            0f,
 | 
			
		||||
            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; } ),
 | 
			
		||||
| 
						 | 
				
			
			@ -1151,7 +1143,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            (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.5f,
 | 
			
		||||
            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 */} ),
 | 
			
		||||
| 
						 | 
				
			
			@ -1165,13 +1157,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            (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.",
 | 
			
		||||
            10f,
 | 
			
		||||
            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; } ),
 | 
			
		||||
| 
						 | 
				
			
			@ -1206,6 +1204,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
            (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,
 | 
			
		||||
| 
						 | 
				
			
			@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
 | 
			
		|||
    {
 | 
			
		||||
        PhysicsLogging.Write(msg, args);
 | 
			
		||||
        // Add the Flush() if debugging crashes. Gets all the messages written out.
 | 
			
		||||
        // PhysicsLogging.Flush();
 | 
			
		||||
        if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
 | 
			
		||||
    }
 | 
			
		||||
    // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
 | 
			
		||||
    public const string DetailLogZero = "0000000000";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
 | 
			
		||||
                                m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
 | 
			
		||||
 | 
			
		||||
        // Create the terrain shape from the mapInfo
 | 
			
		||||
        m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    // The passed position is relative to the base of the region.
 | 
			
		||||
    public override float GetHeightAtXYZ(Vector3 pos)
 | 
			
		||||
    public override float GetTerrainHeightAtXYZ(Vector3 pos)
 | 
			
		||||
    {
 | 
			
		||||
        float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
 | 
			
		|||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The passed position is relative to the base of the region.
 | 
			
		||||
    public override float GetWaterLevelAtXYZ(Vector3 pos)
 | 
			
		||||
    {
 | 
			
		||||
        return PhysicsScene.SimpleWaterLevel;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
 | 
			
		|||
        ID = id;
 | 
			
		||||
    }
 | 
			
		||||
    public abstract void Dispose();
 | 
			
		||||
    public abstract float GetHeightAtXYZ(Vector3 pos);
 | 
			
		||||
    public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
 | 
			
		||||
    public abstract float GetWaterLevelAtXYZ(Vector3 pos);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ==========================================================================================
 | 
			
		||||
| 
						 | 
				
			
			@ -75,13 +76,12 @@ public sealed class BSTerrainManager
 | 
			
		|||
    public const float HEIGHT_INITIALIZATION = 24.987f;
 | 
			
		||||
    public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
 | 
			
		||||
    public const float HEIGHT_GETHEIGHT_RET = 24.765f;
 | 
			
		||||
    public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
 | 
			
		||||
 | 
			
		||||
    // If the min and max height are equal, we reduce the min by this
 | 
			
		||||
    //    amount to make sure that a bounding box is built for the terrain.
 | 
			
		||||
    public const float HEIGHT_EQUAL_FUDGE = 0.2f;
 | 
			
		||||
 | 
			
		||||
    public const float TERRAIN_COLLISION_MARGIN = 0.0f;
 | 
			
		||||
 | 
			
		||||
    // Until the whole simulator is changed to pass us the region size, we rely on constants.
 | 
			
		||||
    public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,7 +129,8 @@ public sealed class BSTerrainManager
 | 
			
		|||
    {
 | 
			
		||||
        // 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, TERRAIN_COLLISION_MARGIN),
 | 
			
		||||
                    BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, 
 | 
			
		||||
                                    PhysicsScene.Params.terrainCollisionMargin),
 | 
			
		||||
                    BSPhysicsShapeType.SHAPE_GROUNDPLANE);
 | 
			
		||||
        m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
 | 
			
		||||
                        BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
 | 
			
		||||
| 
						 | 
				
			
			@ -165,17 +166,22 @@ public sealed class BSTerrainManager
 | 
			
		|||
    // Release all the terrain we have allocated
 | 
			
		||||
    public void ReleaseTerrain()
 | 
			
		||||
    {
 | 
			
		||||
        foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
 | 
			
		||||
        lock (m_terrains)
 | 
			
		||||
        {
 | 
			
		||||
            kvp.Value.Dispose();
 | 
			
		||||
            foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
 | 
			
		||||
            {
 | 
			
		||||
                kvp.Value.Dispose();
 | 
			
		||||
            }
 | 
			
		||||
            m_terrains.Clear();
 | 
			
		||||
        }
 | 
			
		||||
        m_terrains.Clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The simulator wants to set a new heightmap for the terrain.
 | 
			
		||||
    public void SetTerrain(float[] heightMap) {
 | 
			
		||||
        float[] localHeightMap = heightMap;
 | 
			
		||||
        PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
 | 
			
		||||
        // If there are multiple requests for changes to the same terrain between ticks,
 | 
			
		||||
        //      only do that last one.
 | 
			
		||||
        PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
 | 
			
		||||
        {
 | 
			
		||||
            if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
 | 
			
		||||
            {
 | 
			
		||||
| 
						 | 
				
			
			@ -211,6 +217,7 @@ public sealed class BSTerrainManager
 | 
			
		|||
    //     terrain shape is created and added to the body.
 | 
			
		||||
    //     This call is most often used to update the heightMap and parameters of the terrain.
 | 
			
		||||
    // (The above does suggest that some simplification/refactoring is in order.)
 | 
			
		||||
    // Called during taint-time.
 | 
			
		||||
    private void UpdateTerrain(uint id, float[] heightMap, 
 | 
			
		||||
                            Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			@ -220,7 +227,7 @@ public sealed class BSTerrainManager
 | 
			
		|||
        // Find high and low points of passed heightmap.
 | 
			
		||||
        // The min and max passed in is usually the area objects can be in (maximum
 | 
			
		||||
        //     object height, for instance). The terrain wants the bounding box for the
 | 
			
		||||
        //     terrain so we replace passed min and max Z with the actual terrain min/max Z.
 | 
			
		||||
        //     terrain so replace passed min and max Z with the actual terrain min/max Z.
 | 
			
		||||
        float minZ = float.MaxValue;
 | 
			
		||||
        float maxZ = float.MinValue;
 | 
			
		||||
        foreach (float height in heightMap)
 | 
			
		||||
| 
						 | 
				
			
			@ -238,15 +245,15 @@ public sealed class BSTerrainManager
 | 
			
		|||
 | 
			
		||||
        Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
 | 
			
		||||
 | 
			
		||||
        BSTerrainPhys terrainPhys;
 | 
			
		||||
        if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
 | 
			
		||||
        lock (m_terrains)
 | 
			
		||||
        {
 | 
			
		||||
            // There is already a terrain in this spot. Free the old and build the new.
 | 
			
		||||
            DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
 | 
			
		||||
                            BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
 | 
			
		||||
 | 
			
		||||
            PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
 | 
			
		||||
            BSTerrainPhys terrainPhys;
 | 
			
		||||
            if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
 | 
			
		||||
            {
 | 
			
		||||
                // There is already a terrain in this spot. Free the old and build the new.
 | 
			
		||||
                DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
 | 
			
		||||
                                BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
 | 
			
		||||
 | 
			
		||||
                // Remove old terrain from the collection
 | 
			
		||||
                m_terrains.Remove(terrainRegionBase);
 | 
			
		||||
                // Release any physical memory it may be using.
 | 
			
		||||
| 
						 | 
				
			
			@ -271,35 +278,24 @@ public sealed class BSTerrainManager
 | 
			
		|||
                    // I hate doing this, but just bail
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // We don't know about this terrain so either we are creating a new terrain or
 | 
			
		||||
            //    our mega-prim child is giving us a new terrain to add to the phys world
 | 
			
		||||
 | 
			
		||||
            // if this is a child terrain, calculate a unique terrain id
 | 
			
		||||
            uint newTerrainID = id;
 | 
			
		||||
            if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
 | 
			
		||||
                newTerrainID = ++m_terrainCount;
 | 
			
		||||
 | 
			
		||||
            float[] heightMapX = heightMap;
 | 
			
		||||
            Vector3 minCoordsX = minCoords;
 | 
			
		||||
            Vector3 maxCoordsX = maxCoords;
 | 
			
		||||
 | 
			
		||||
            DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
 | 
			
		||||
                            BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
 | 
			
		||||
 | 
			
		||||
            // Code that must happen at taint-time
 | 
			
		||||
            PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", 
 | 
			
		||||
                                            BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
 | 
			
		||||
                // We don't know about this terrain so either we are creating a new terrain or
 | 
			
		||||
                //    our mega-prim child is giving us a new terrain to add to the phys world
 | 
			
		||||
 | 
			
		||||
                // if this is a child terrain, calculate a unique terrain id
 | 
			
		||||
                uint newTerrainID = id;
 | 
			
		||||
                if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
 | 
			
		||||
                    newTerrainID = ++m_terrainCount;
 | 
			
		||||
 | 
			
		||||
                DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
 | 
			
		||||
                                            BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
 | 
			
		||||
                BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
 | 
			
		||||
                m_terrains.Add(terrainRegionBase, newTerrainPhys);
 | 
			
		||||
 | 
			
		||||
                m_terrainModified = true;
 | 
			
		||||
            });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -349,6 +345,7 @@ public sealed class BSTerrainManager
 | 
			
		|||
        //    with the same parameters as last time.
 | 
			
		||||
        if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
 | 
			
		||||
            return lastHeight;
 | 
			
		||||
        m_terrainModified = false;
 | 
			
		||||
 | 
			
		||||
        lastHeightTX = tX;
 | 
			
		||||
        lastHeightTY = tY;
 | 
			
		||||
| 
						 | 
				
			
			@ -358,23 +355,50 @@ public sealed class BSTerrainManager
 | 
			
		|||
        int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
 | 
			
		||||
        Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
 | 
			
		||||
 | 
			
		||||
        BSTerrainPhys physTerrain;
 | 
			
		||||
        if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
 | 
			
		||||
        lock (m_terrains)
 | 
			
		||||
        {
 | 
			
		||||
            ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
 | 
			
		||||
            DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
 | 
			
		||||
                                             BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
 | 
			
		||||
            BSTerrainPhys physTerrain;
 | 
			
		||||
            if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
 | 
			
		||||
            {
 | 
			
		||||
                ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
 | 
			
		||||
                        LogHeader, PhysicsScene.RegionName, tX, tY);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
 | 
			
		||||
                    LogHeader, PhysicsScene.RegionName, tX, tY);
 | 
			
		||||
        }
 | 
			
		||||
        m_terrainModified = false;
 | 
			
		||||
        lastHeight = ret;
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float GetWaterLevelAtXYZ(Vector3 pos)
 | 
			
		||||
    {
 | 
			
		||||
        float ret = WATER_HEIGHT_GETHEIGHT_RET;
 | 
			
		||||
 | 
			
		||||
        float tX = pos.X;
 | 
			
		||||
        float tY = pos.Y;
 | 
			
		||||
 | 
			
		||||
        Vector3 terrainBaseXYZ = Vector3.Zero;
 | 
			
		||||
        terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
 | 
			
		||||
        terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
 | 
			
		||||
 | 
			
		||||
        lock (m_terrains)
 | 
			
		||||
        {
 | 
			
		||||
            BSTerrainPhys physTerrain;
 | 
			
		||||
            if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
 | 
			
		||||
            {
 | 
			
		||||
                ret = physTerrain.GetWaterLevelAtXYZ(pos);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
 | 
			
		||||
                        LogHeader, PhysicsScene.RegionName, tX, tY);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Although no one seems to check this, I do support combining.
 | 
			
		||||
    public bool SupportsCombining()
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
            // Something is very messed up and a crash is in our future.
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", 
 | 
			
		||||
                                ID, indicesCount, indices.Length, verticesCount, vertices.Length);
 | 
			
		||||
 | 
			
		||||
        m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
 | 
			
		||||
                                        indicesCount, indices, verticesCount, vertices),
 | 
			
		||||
                                                    indicesCount, indices, verticesCount, vertices),
 | 
			
		||||
                                        BSPhysicsShapeType.SHAPE_MESH);
 | 
			
		||||
        if (m_terrainShape.ptr == IntPtr.Zero)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
        // Static objects are not very massive.
 | 
			
		||||
        BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
 | 
			
		||||
 | 
			
		||||
        // Return the new terrain to the world of physical objects
 | 
			
		||||
        // Put the new terrain to the world of physical objects
 | 
			
		||||
        BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
 | 
			
		||||
 | 
			
		||||
        // redo its bounding box now that it is in the world
 | 
			
		||||
        // Redo its bounding box now that it is in the world
 | 
			
		||||
        BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
 | 
			
		||||
 | 
			
		||||
        BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
 | 
			
		||||
| 
						 | 
				
			
			@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public override float GetHeightAtXYZ(Vector3 pos)
 | 
			
		||||
    public override float GetTerrainHeightAtXYZ(Vector3 pos)
 | 
			
		||||
    {
 | 
			
		||||
        // For the moment use the saved heightmap to get the terrain height.
 | 
			
		||||
        // TODO: raycast downward to find the true terrain below the position.
 | 
			
		||||
| 
						 | 
				
			
			@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The passed position is relative to the base of the region.
 | 
			
		||||
    public override float GetWaterLevelAtXYZ(Vector3 pos)
 | 
			
		||||
    {
 | 
			
		||||
        return PhysicsScene.SimpleWaterLevel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
 | 
			
		||||
    // Return 'true' if successfully created.
 | 
			
		||||
    public static bool ConvertHeightmapToMesh(
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
        // Simple mesh creation which assumes magnification == 1.
 | 
			
		||||
        // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
 | 
			
		||||
 | 
			
		||||
        // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
 | 
			
		||||
        //    from zero to <= sizeX). The triangle indices are then generated as two triangles
 | 
			
		||||
        //    per heightmap point. There are sizeX by sizeY of these squares. The extra row and
 | 
			
		||||
        //    column of vertices are used to complete the triangles of the last row and column
 | 
			
		||||
        //    of the heightmap.
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            // One vertice per heightmap value plus the vertices off the top and bottom edge.
 | 
			
		||||
| 
						 | 
				
			
			@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
            float magY = (float)sizeY / extentY;
 | 
			
		||||
            physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
 | 
			
		||||
                                    BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
 | 
			
		||||
            float minHeight = float.MaxValue;
 | 
			
		||||
            // Note that sizeX+1 vertices are created since there is land between this and the next region.
 | 
			
		||||
            for (int yy = 0; yy <= sizeY; yy++)
 | 
			
		||||
            {
 | 
			
		||||
                for (int xx = 0; xx <= sizeX; xx++)     // Hint: the "<=" means we got through sizeX + 1 times
 | 
			
		||||
                for (int xx = 0; xx <= sizeX; xx++)     // Hint: the "<=" means we go around sizeX + 1 times
 | 
			
		||||
                {
 | 
			
		||||
                    int offset = yy * sizeX + xx;
 | 
			
		||||
                    // Extend the height from the height from the last row or column
 | 
			
		||||
                    // Extend the height with the height from the last row or column
 | 
			
		||||
                    if (yy == sizeY) offset -= sizeX;
 | 
			
		||||
                    if (xx == sizeX) offset -= 1;
 | 
			
		||||
                    float height = heightMap[offset];
 | 
			
		||||
                    minHeight = Math.Min(minHeight, height);
 | 
			
		||||
                    vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
 | 
			
		||||
                    vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
 | 
			
		||||
                    vertices[verticesCount + 2] = height + extentBase.Z;
 | 
			
		||||
| 
						 | 
				
			
			@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
                }
 | 
			
		||||
            }
 | 
			
		||||
            verticesCount = verticesCount / 3;
 | 
			
		||||
            physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", 
 | 
			
		||||
                                            BSScene.DetailLogZero, verticesCount);
 | 
			
		||||
 | 
			
		||||
            for (int yy = 0; yy < sizeY; yy++)
 | 
			
		||||
            {
 | 
			
		||||
                for (int xx = 0; xx < sizeX; xx++)
 | 
			
		||||
                {
 | 
			
		||||
                    int offset = yy * sizeX + xx;
 | 
			
		||||
                    int offset = yy * (sizeX + 1) + xx;
 | 
			
		||||
                    // Each vertices is presumed to be the upper left corner of a box of two triangles
 | 
			
		||||
                    indices[indicesCount + 0] = offset;
 | 
			
		||||
                    indices[indicesCount + 1] = offset + 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
 | 
			
		|||
                    indicesCount += 6;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}",   // DEEBUG DEBUG DEBUG
 | 
			
		||||
                                                        LogHeader, indicesCount);                        // DEBUG
 | 
			
		||||
 | 
			
		||||
            ret = true;
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception e)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -287,6 +287,8 @@ public struct ConfigurationParameters
 | 
			
		|||
    public float terrainFriction;
 | 
			
		||||
    public float terrainHitFraction;
 | 
			
		||||
    public float terrainRestitution;
 | 
			
		||||
    public float terrainCollisionMargin;
 | 
			
		||||
 | 
			
		||||
    public float avatarFriction;
 | 
			
		||||
    public float avatarStandingFriction;
 | 
			
		||||
    public float avatarDensity;
 | 
			
		||||
| 
						 | 
				
			
			@ -296,6 +298,8 @@ public struct ConfigurationParameters
 | 
			
		|||
    public float avatarCapsuleHeight;
 | 
			
		||||
	public float avatarContactProcessingThreshold;
 | 
			
		||||
 | 
			
		||||
    public float vehicleAngularDamping;
 | 
			
		||||
 | 
			
		||||
	public float maxPersistantManifoldPoolSize;
 | 
			
		||||
	public float maxCollisionAlgorithmPoolSize;
 | 
			
		||||
	public float shouldDisableContactPoolDynamicAllocation;
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +357,7 @@ public enum CollisionFlags : uint
 | 
			
		|||
    CF_CHARACTER_OBJECT              = 1 << 4,
 | 
			
		||||
    CF_DISABLE_VISUALIZE_OBJECT      = 1 << 5,
 | 
			
		||||
    CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
 | 
			
		||||
    // Following used by BulletSim to control collisions
 | 
			
		||||
    // Following used by BulletSim to control collisions and updates
 | 
			
		||||
    BS_SUBSCRIBE_COLLISION_EVENTS    = 1 << 10,
 | 
			
		||||
    BS_FLOATS_ON_WATER               = 1 << 11,
 | 
			
		||||
    BS_NONE                          = 0,
 | 
			
		||||
| 
						 | 
				
			
			@ -481,6 +485,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
 | 
			
		|||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
 | 
			
		||||
public static extern bool IsNativeShape2(IntPtr shape);
 | 
			
		||||
 | 
			
		||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
 | 
			
		||||
public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
 | 
			
		||||
 | 
			
		||||
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
 | 
			
		||||
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
 | 
			
		|||
 | 
			
		||||
            if (primShape.SculptData.Length <= 0)
 | 
			
		||||
            {
 | 
			
		||||
                // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
 | 
			
		||||
                // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
 | 
			
		||||
                // The first time will always call with unloaded SculptData if this needs to be uploaded.
 | 
			
		||||
//                m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
 | 
			
		|||
                _pbs.SculptData = new byte[asset.Data.Length];
 | 
			
		||||
                asset.Data.CopyTo(_pbs.SculptData, 0);
 | 
			
		||||
//                m_assetFailed = false;
 | 
			
		||||
 | 
			
		||||
//                m_log.DebugFormat(
 | 
			
		||||
//                    "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", 
 | 
			
		||||
//                    _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
 | 
			
		||||
 | 
			
		||||
                m_taintshape = true;
 | 
			
		||||
               _parent_scene.AddPhysicsActorTaint(this);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -217,10 +217,10 @@
 | 
			
		|||
    ; to false if you have compatibility problems.
 | 
			
		||||
    ;CacheSculptMaps = true
 | 
			
		||||
    
 | 
			
		||||
    ; Choose one of the physics engines below
 | 
			
		||||
    ; OpenDynamicsEngine is by some distance the most developed physics engine
 | 
			
		||||
    ; basicphysics effectively does not model physics at all, making all objects phantom
 | 
			
		||||
 | 
			
		||||
    ; Choose one of the physics engines below.
 | 
			
		||||
    ; OpenDynamicsEngine is by some distance the most developed physics engine.
 | 
			
		||||
    ; BulletSim is a high performance, up-and-coming physics engine.
 | 
			
		||||
    ; basicphysics effectively does not model physics at all, making all objects phantom.
 | 
			
		||||
    physics = OpenDynamicsEngine
 | 
			
		||||
    ;physics = basicphysics
 | 
			
		||||
    ;physics = POS
 | 
			
		||||
| 
						 | 
				
			
			@ -904,15 +904,18 @@
 | 
			
		|||
 | 
			
		||||
[BulletSim]
 | 
			
		||||
    ; World parameters
 | 
			
		||||
    DefaultFriction = 0.50
 | 
			
		||||
    DefaultFriction = 0.20
 | 
			
		||||
    DefaultDensity = 10.000006836
 | 
			
		||||
    DefaultRestitution = 0.0
 | 
			
		||||
    Gravity = -9.80665
 | 
			
		||||
 | 
			
		||||
    TerrainFriction = 0.50
 | 
			
		||||
    TerrainHitFriction = 0.8
 | 
			
		||||
    TerrainFriction = 0.30
 | 
			
		||||
    TerrainHitFraction = 0.8
 | 
			
		||||
    TerrainRestitution = 0
 | 
			
		||||
    TerrainCollisionMargin = 0.04
 | 
			
		||||
 | 
			
		||||
    AvatarFriction = 0.2
 | 
			
		||||
    AvatarStandingFriction = 0.99
 | 
			
		||||
    AvatarRestitution = 0.0
 | 
			
		||||
    AvatarDensity = 60.0
 | 
			
		||||
    AvatarCapsuleWidth = 0.6
 | 
			
		||||
| 
						 | 
				
			
			@ -926,27 +929,15 @@
 | 
			
		|||
    LinearDamping = 0.0
 | 
			
		||||
    AngularDamping = 0.0
 | 
			
		||||
    DeactivationTime = 0.2
 | 
			
		||||
    LinearSleepingThreshold = 0.8
 | 
			
		||||
    AngularSleepingThreshold = 1.0
 | 
			
		||||
    CcdMotionThreshold = 0.0
 | 
			
		||||
    CcdSweptSphereRadius = 0.0
 | 
			
		||||
    ContactProcessingThreshold = 0.1
 | 
			
		||||
    ; If setting a pool size, also disable dynamic allocation (default pool size is 4096 with dynamic alloc)
 | 
			
		||||
    MaxPersistantManifoldPoolSize = 0
 | 
			
		||||
    ShouldDisableContactPoolDynamicAllocation = False
 | 
			
		||||
    ShouldForceUpdateAllAabbs = False
 | 
			
		||||
    ShouldRandomizeSolverOrder = True
 | 
			
		||||
    ShouldSplitSimulationIslands = True
 | 
			
		||||
    ShouldEnableFrictionCaching = False
 | 
			
		||||
    NumberOfSolverIterations = 0   
 | 
			
		||||
    CollisionMargin = 0.04
 | 
			
		||||
 | 
			
		||||
    ; Linkset constraint parameters
 | 
			
		||||
    LinkImplementation = 1      ; 0=constraint, 1=compound
 | 
			
		||||
    LinkConstraintUseFrameOffset = False
 | 
			
		||||
    LinkConstraintEnableTransMotor = True
 | 
			
		||||
    LinkConstraintTransMotorMaxVel = 5.0
 | 
			
		||||
    LinkConstraintTransMotorMaxForce = 0.1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ; Whether to mesh sculpties
 | 
			
		||||
    MeshSculptedPrim = true
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
		Loading…
	
		Reference in New Issue