aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs9
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs145
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs430
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs411
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs173
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs136
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs219
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs137
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs138
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs67
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs72
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs527
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs6
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs25
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs54
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs103
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs490
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs240
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs393
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs730
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs97
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs350
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs404
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs741
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs121
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs230
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs381
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs998
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs1163
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs33
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs82
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs56
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs51
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt131
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs34
-rw-r--r--OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsActor.cs6
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs10
-rw-r--r--OpenSim/Region/Physics/Meshing/Meshmerizer.cs265
-rw-r--r--OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs2
-rw-r--r--OpenSim/Region/Physics/OdePlugin/ODEPrim.cs1
-rw-r--r--OpenSim/Region/Physics/OdePlugin/OdePlugin.cs2
-rw-r--r--OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs2
49 files changed, 6447 insertions, 3285 deletions
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
index 6fd6f7e..ffcb01e 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.6.*")] 58[assembly : AssemblyVersion("0.8.0.*")]
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs
index e43136a..0d17e0e 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs
@@ -118,14 +118,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
118 118
119 public override Vector3 Position { get; set; } 119 public override Vector3 Position { get; set; }
120 120
121 public override Vector3 Size 121 public override Vector3 Size { get; set; }
122 {
123 get { return _size; }
124 set {
125 _size = value;
126 _size.Z = _size.Z / 2.0f;
127 }
128 }
129 122
130 public override PrimitiveBaseShape Shape 123 public override PrimitiveBaseShape Shape
131 { 124 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
index f5b84d4..3bd81d4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody
75private sealed class BulletShapeUnman : BulletShape 75private sealed class BulletShapeUnman : BulletShape
76{ 76{
77 public IntPtr ptr; 77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) 78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -251,11 +251,21 @@ public override BulletShape CreateMeshShape(BulletWorld world,
251 BSPhysicsShapeType.SHAPE_MESH); 251 BSPhysicsShapeType.SHAPE_MESH);
252} 252}
253 253
254public override BulletShape CreateGImpactShape(BulletWorld world,
255 int indicesCount, int[] indices,
256 int verticesCount, float[] vertices)
257{
258 BulletWorldUnman worldu = world as BulletWorldUnman;
259 return new BulletShapeUnman(
260 BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
261 BSPhysicsShapeType.SHAPE_GIMPACT);
262}
263
254public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) 264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
255{ 265{
256 BulletWorldUnman worldu = world as BulletWorldUnman; 266 BulletWorldUnman worldu = world as BulletWorldUnman;
257 return new BulletShapeUnman( 267 return new BulletShapeUnman(
258 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), 268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
259 BSPhysicsShapeType.SHAPE_HULL); 269 BSPhysicsShapeType.SHAPE_HULL);
260} 270}
261 271
@@ -268,6 +278,25 @@ public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShap
268 BSPhysicsShapeType.SHAPE_HULL); 278 BSPhysicsShapeType.SHAPE_HULL);
269} 279}
270 280
281public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
282{
283 BulletWorldUnman worldu = world as BulletWorldUnman;
284 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
285 return new BulletShapeUnman(
286 BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
287 BSPhysicsShapeType.SHAPE_CONVEXHULL);
288}
289
290public override BulletShape CreateConvexHullShape(BulletWorld world,
291 int indicesCount, int[] indices,
292 int verticesCount, float[] vertices)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
297 BSPhysicsShapeType.SHAPE_CONVEXHULL);
298}
299
271public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) 300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
272{ 301{
273 BulletWorldUnman worldu = world as BulletWorldUnman; 302 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -356,7 +385,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
356{ 385{
357 BulletWorldUnman worldu = world as BulletWorldUnman; 386 BulletWorldUnman worldu = world as BulletWorldUnman;
358 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
359 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
360} 389}
361 390
362public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
@@ -567,6 +596,60 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo
567 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); 596 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
568} 597}
569 598
599public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
600{
601 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
602 return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
603}
604
605public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
606{
607 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
608 return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
609}
610
611public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
612{
613 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
614 return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
615}
616
617public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
618{
619 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
620 return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
621}
622
623public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
624{
625 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
626 return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
627}
628
629public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
630{
631 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
632 return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
633}
634
635public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
636{
637 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
638 return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
639}
640
641public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
642{
643 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
644 return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
645}
646
647public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
648{
649 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
650 return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
651}
652
570public override bool CalculateTransforms(BulletConstraint constrain) 653public override bool CalculateTransforms(BulletConstraint constrain)
571{ 654{
572 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; 655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -642,6 +725,13 @@ public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
642 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); 725 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
643} 726}
644 727
728public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
729{
730 BulletWorldUnman worldu = world as BulletWorldUnman;
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
733}
734
645public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) 735public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
646{ 736{
647 BulletWorldUnman worldu = world as BulletWorldUnman; 737 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -1407,6 +1497,11 @@ public static extern IntPtr CreateMeshShape2(IntPtr world,
1407 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); 1497 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1408 1498
1409[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern IntPtr CreateGImpactShape2(IntPtr world,
1501 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1502 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1503
1504[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1410public static extern IntPtr CreateHullShape2(IntPtr world, 1505public static extern IntPtr CreateHullShape2(IntPtr world,
1411 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); 1506 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1412 1507
@@ -1414,6 +1509,14 @@ public static extern IntPtr CreateHullShape2(IntPtr world,
1414public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); 1509public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1415 1510
1416[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern IntPtr CreateConvexHullShape2(IntPtr world,
1516 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1517 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1518
1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1417public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); 1520public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1418 1521
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1522[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1476,7 +1579,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1476public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1579public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1477 1580
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1582public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1480 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 1583 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1481 float scaleFactor, float collisionMargin); 1584 float scaleFactor, float collisionMargin);
1482 1585
@@ -1559,6 +1662,33 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl
1559public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); 1662public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1560 1663
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1664[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1665public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
1666
1667[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1668public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
1669
1670[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1671public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
1690
1691[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern bool CalculateTransforms2(IntPtr constrain); 1692public static extern bool CalculateTransforms2(IntPtr constrain);
1563 1693
1564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1694[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1590,6 +1720,9 @@ public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1590public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 1720public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1591 1721
1592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1593public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); 1726public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1594 1727
1595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
index f6b4359..17ebed2 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -81,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody
81private sealed class BulletShapeXNA : BulletShape 81private sealed class BulletShapeXNA : BulletShape
82{ 82{
83 public CollisionShape shape; 83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) 84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base() 85 : base()
86 { 86 {
87 shape = xx; 87 shape = xx;
88 type = typ; 88 shapeType = typ;
89 } 89 }
90 public override bool HasPhysicalShape 90 public override bool HasPhysicalShape
91 { 91 {
@@ -97,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape
97 } 97 }
98 public override BulletShape Clone() 98 public override BulletShape Clone()
99 { 99 {
100 return new BulletShapeXNA(shape, type); 100 return new BulletShapeXNA(shape, shapeType);
101 } 101 }
102 public override bool ReferenceSame(BulletShape other) 102 public override bool ReferenceSame(BulletShape other)
103 { 103 {
@@ -137,8 +137,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
137 internal int LastEntityProperty = 0; 137 internal int LastEntityProperty = 0;
138 138
139 internal EntityProperties[] UpdatedObjects; 139 internal EntityProperties[] UpdatedObjects;
140 internal Dictionary<uint, GhostObject> specialCollisionObjects; 140 internal Dictionary<uint, GhostObject> specialCollisionObjects;
141 141
142 private static int m_collisionsThisFrame; 142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; } 143 private BSScene PhysicsScene { get; set; }
144 144
@@ -151,7 +151,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
151 } 151 }
152 152
153 /// <summary> 153 /// <summary>
154 /// 154 ///
155 /// </summary> 155 /// </summary>
156 /// <param name="p"></param> 156 /// <param name="p"></param>
157 /// <param name="p_2"></param> 157 /// <param name="p_2"></param>
@@ -169,12 +169,25 @@ private sealed class BulletConstraintXNA : BulletConstraint
169 return true; 169 return true;
170 } 170 }
171 171
172 public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
176 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
177 if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
178 {
179 world.RemoveCollisionObject(collisionObject);
180 world.AddCollisionObject(collisionObject);
181 }
182 return true;
183 }
184
172 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) 185 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
173 { 186 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 187 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; 188 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
176 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); 189 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
177 190
178 return true; 191 return true;
179 192
180 } 193 }
@@ -300,7 +313,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
300 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { 313 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
301 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 314 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
302 return world.GetForceUpdateAllAabbs(); 315 return world.GetForceUpdateAllAabbs();
303 316
304 } 317 }
305 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) 318 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
306 { 319 {
@@ -404,7 +417,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
404 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); 417 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
405 mat._origin = vposition; 418 mat._origin = vposition;
406 collisionObject.SetWorldTransform(mat); 419 collisionObject.SetWorldTransform(mat);
407 420
408 } 421 }
409 422
410 public override Vector3 GetPosition(BulletBody pCollisionObject) 423 public override Vector3 GetPosition(BulletBody pCollisionObject)
@@ -457,7 +470,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
457 { 470 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 471 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
459 collisionObject.Activate(pforceactivation); 472 collisionObject.Activate(pforceactivation);
460 473
461 } 474 }
462 475
463 public override Quaternion GetOrientation(BulletBody pCollisionObject) 476 public override Quaternion GetOrientation(BulletBody pCollisionObject)
@@ -486,7 +499,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
486 { 499 {
487 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 500 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
488 return collisionObject.GetCcdSweptSphereRadius(); 501 return collisionObject.GetCcdSweptSphereRadius();
489 502
490 } 503 }
491 504
492 public override IntPtr GetUserPointer(BulletBody pCollisionObject) 505 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
@@ -559,8 +572,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
559 } 572 }
560 573
561 574
562 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 575 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
563 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 576 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
564 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 577 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
565 578
566 { 579 {
@@ -604,7 +617,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
604 } 617 }
605 618
606 /// <summary> 619 /// <summary>
607 /// 620 ///
608 /// </summary> 621 /// </summary>
609 /// <param name="pWorld"></param> 622 /// <param name="pWorld"></param>
610 /// <param name="pBody1"></param> 623 /// <param name="pBody1"></param>
@@ -752,6 +765,214 @@ private sealed class BulletConstraintXNA : BulletConstraint
752 constraint.SetBreakingImpulseThreshold(threshold); 765 constraint.SetBreakingImpulseThreshold(threshold);
753 return true; 766 return true;
754 } 767 }
768 public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
769 {
770 HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
771 if (softness == HINGE_NOT_SPECIFIED)
772 constraint.SetLimit(low, high);
773 else
774 constraint.SetLimit(low, high, softness, bias, relaxation);
775 return true;
776 }
777 public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
778 {
779 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
780 constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
781 return true;
782 }
783
784 public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
785 {
786 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
787 if (index == SPRING_NOT_SPECIFIED)
788 {
789 constraint.SetEquilibriumPoint();
790 }
791 else
792 {
793 if (equilibriumPoint == SPRING_NOT_SPECIFIED)
794 constraint.SetEquilibriumPoint(index);
795 else
796 constraint.SetEquilibriumPoint(index, equilibriumPoint);
797 }
798 return true;
799 }
800
801 public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
802 {
803 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
804 constraint.SetStiffness(index, stiffness);
805 return true;
806 }
807
808 public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
809 {
810 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
811 constraint.SetDamping(index, damping);
812 return true;
813 }
814
815 public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
816 {
817 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
818 switch (lowerUpper)
819 {
820 case SLIDER_LOWER_LIMIT:
821 switch (linAng)
822 {
823 case SLIDER_LINEAR:
824 constraint.SetLowerLinLimit(val);
825 break;
826 case SLIDER_ANGULAR:
827 constraint.SetLowerAngLimit(val);
828 break;
829 }
830 break;
831 case SLIDER_UPPER_LIMIT:
832 switch (linAng)
833 {
834 case SLIDER_LINEAR:
835 constraint.SetUpperLinLimit(val);
836 break;
837 case SLIDER_ANGULAR:
838 constraint.SetUpperAngLimit(val);
839 break;
840 }
841 break;
842 }
843 return true;
844 }
845 public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
846 {
847 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
848 switch (softRestDamp)
849 {
850 case SLIDER_SET_SOFTNESS:
851 switch (dirLimOrtho)
852 {
853 case SLIDER_SET_DIRECTION:
854 switch (linAng)
855 {
856 case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
857 case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
858 }
859 break;
860 case SLIDER_SET_LIMIT:
861 switch (linAng)
862 {
863 case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
864 case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
865 }
866 break;
867 case SLIDER_SET_ORTHO:
868 switch (linAng)
869 {
870 case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
871 case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
872 }
873 break;
874 }
875 break;
876 case SLIDER_SET_RESTITUTION:
877 switch (dirLimOrtho)
878 {
879 case SLIDER_SET_DIRECTION:
880 switch (linAng)
881 {
882 case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
883 case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
884 }
885 break;
886 case SLIDER_SET_LIMIT:
887 switch (linAng)
888 {
889 case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
890 case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
891 }
892 break;
893 case SLIDER_SET_ORTHO:
894 switch (linAng)
895 {
896 case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
897 case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
898 }
899 break;
900 }
901 break;
902 case SLIDER_SET_DAMPING:
903 switch (dirLimOrtho)
904 {
905 case SLIDER_SET_DIRECTION:
906 switch (linAng)
907 {
908 case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
909 case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
910 }
911 break;
912 case SLIDER_SET_LIMIT:
913 switch (linAng)
914 {
915 case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
916 case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
917 }
918 break;
919 case SLIDER_SET_ORTHO:
920 switch (linAng)
921 {
922 case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
923 case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
924 }
925 break;
926 }
927 break;
928 }
929 return true;
930 }
931 public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
932 {
933 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
934 switch (linAng)
935 {
936 case SLIDER_LINEAR:
937 constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
938 break;
939 case SLIDER_ANGULAR:
940 constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
941 break;
942 }
943 return true;
944 }
945 public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
946 {
947 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
948 switch (forceVel)
949 {
950 case SLIDER_MOTOR_VELOCITY:
951 switch (linAng)
952 {
953 case SLIDER_LINEAR:
954 constraint.SetTargetLinMotorVelocity(val);
955 break;
956 case SLIDER_ANGULAR:
957 constraint.SetTargetAngMotorVelocity(val);
958 break;
959 }
960 break;
961 case SLIDER_MAX_MOTOR_FORCE:
962 switch (linAng)
963 {
964 case SLIDER_LINEAR:
965 constraint.SetMaxLinMotorForce(val);
966 break;
967 case SLIDER_ANGULAR:
968 constraint.SetMaxAngMotorForce(val);
969 break;
970 }
971 break;
972 }
973 return true;
974 }
975
755 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); 976 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
756 public override void SetAngularDamping(BulletBody pBody, float angularDamping) 977 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
757 { 978 {
@@ -824,7 +1045,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
824 { 1045 {
825 RigidBody body = (pBody as BulletBodyXNA).rigidBody; 1046 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
826 float angularDamping = body.GetAngularDamping(); 1047 float angularDamping = body.GetAngularDamping();
827 body.SetDamping(lin_damping, angularDamping); 1048 body.SetDamping(lin_damping, angularDamping);
828 } 1049 }
829 1050
830 public override float GetLinearDamping(BulletBody pBody) 1051 public override float GetLinearDamping(BulletBody pBody)
@@ -907,7 +1128,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
907 RigidBody bo = co as RigidBody; 1128 RigidBody bo = co as RigidBody;
908 if (bo == null) 1129 if (bo == null)
909 { 1130 {
910 1131
911 if (world.IsInWorld(co)) 1132 if (world.IsInWorld(co))
912 { 1133 {
913 world.RemoveCollisionObject(co); 1134 world.RemoveCollisionObject(co);
@@ -915,7 +1136,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
915 } 1136 }
916 else 1137 else
917 { 1138 {
918 1139
919 if (world.IsInWorld(bo)) 1140 if (world.IsInWorld(bo))
920 { 1141 {
921 world.RemoveRigidBody(bo); 1142 world.RemoveRigidBody(bo);
@@ -947,7 +1168,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
947 1168
948 // TODO: Turn this from a reference copy to a Value Copy. 1169 // TODO: Turn this from a reference copy to a Value Copy.
949 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); 1170 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
950 1171
951 return shape2; 1172 return shape2;
952 } 1173 }
953 1174
@@ -957,7 +1178,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
957 return false; 1178 return false;
958 } 1179 }
959 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); 1180 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
960 1181
961 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 1182 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
962 { 1183 {
963 CollisionWorld world = (pWorld as BulletWorldXNA).world; 1184 CollisionWorld world = (pWorld as BulletWorldXNA).world;
@@ -993,11 +1214,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
993 m_startWorldTransform = IndexedMatrix.Identity; 1214 m_startWorldTransform = IndexedMatrix.Identity;
994 */ 1215 */
995 body.SetUserPointer(pLocalID); 1216 body.SetUserPointer(pLocalID);
996 1217
997 return new BulletBodyXNA(pLocalID, body); 1218 return new BulletBodyXNA(pLocalID, body);
998 } 1219 }
999 1220
1000 1221
1001 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) 1222 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1002 { 1223 {
1003 1224
@@ -1025,7 +1246,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1025 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) 1246 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1026 { 1247 {
1027 1248
1028 /* TODO */ 1249 /* TODO */
1029 return Vector3.Zero; 1250 return Vector3.Zero;
1030 } 1251 }
1031 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } 1252 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
@@ -1035,7 +1256,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1035 { 1256 {
1036 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; 1257 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1037 return collisionObject.IsStaticObject(); 1258 return collisionObject.IsStaticObject();
1038 1259
1039 } 1260 }
1040 public override bool IsKinematicObject(BulletBody pCollisionObject) 1261 public override bool IsKinematicObject(BulletBody pCollisionObject)
1041 { 1262 {
@@ -1098,10 +1319,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1098 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); 1319 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1099 } 1320 }
1100 1321
1101 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, 1322 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1102 ConfigurationParameters[] o, 1323 ConfigurationParameters[] o,
1103 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, 1324 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1104 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, 1325 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1105 object mDebugLogCallbackHandle) 1326 object mDebugLogCallbackHandle)
1106 { 1327 {
1107 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); 1328 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
@@ -1138,9 +1359,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
1138 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; 1359 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1139 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; 1360 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1140 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; 1361 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1141 1362
1142 p.vehicleAngularDamping = BSParam.VehicleAngularDamping; 1363 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1143 1364
1144 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; 1365 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1145 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; 1366 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1146 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; 1367 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
@@ -1160,7 +1381,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1160 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; 1381 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1161 p.physicsLoggingFrames = o[0].physicsLoggingFrames; 1382 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1162 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); 1383 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1163 1384
1164 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); 1385 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1165 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); 1386 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1166 1387
@@ -1221,6 +1442,50 @@ private sealed class BulletConstraintXNA : BulletConstraint
1221 //BSParam.TerrainImplementation = 0; 1442 //BSParam.TerrainImplementation = 0;
1222 world.SetGravity(new IndexedVector3(0,0,p.gravity)); 1443 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1223 1444
1445 // Turn off Pooling since globals and pooling are bad for threading.
1446 BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false);
1447 BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false);
1448 BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false);
1449 BulletGlobals.CastResultPool.SetPoolingEnabled(false);
1450 BulletGlobals.SphereShapePool.SetPoolingEnabled(false);
1451 BulletGlobals.DbvtNodePool.SetPoolingEnabled(false);
1452 BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false);
1453 BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false);
1454 BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false);
1455 BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false);
1456 BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false);
1457 BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false);
1458 BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false);
1459 BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false);
1460 BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false);
1461 BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false);
1462
1463 BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1464 BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false);
1465 BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false);
1466 BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false);
1467 BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false);
1468 BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1469 BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false);
1470 BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false);
1471 BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false);
1472 BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false);
1473 BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false);
1474 BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false);
1475 BulletGlobals.GJKPool.SetPoolingEnabled(false);
1476 BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false);
1477 BulletGlobals.TriangleShapePool.SetPoolingEnabled(false);
1478 BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false);
1479 BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false);
1480 BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false);
1481 BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false);
1482 BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false);
1483 BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false);
1484 BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false);
1485 BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false);
1486 BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false);
1487 BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false);
1488
1224 return world; 1489 return world;
1225 } 1490 }
1226 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL 1491 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
@@ -1263,7 +1528,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1263 } 1528 }
1264 } 1529 }
1265 return ret; 1530 return ret;
1266 1531
1267 } 1532 }
1268 1533
1269 public override float GetAngularMotionDisc(BulletShape pShape) 1534 public override float GetAngularMotionDisc(BulletShape pShape)
@@ -1353,10 +1618,10 @@ private sealed class BulletConstraintXNA : BulletConstraint
1353 CollisionShape shape = (pShape as BulletShapeXNA).shape; 1618 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1354 gObj.SetCollisionShape(shape); 1619 gObj.SetCollisionShape(shape);
1355 gObj.SetUserPointer(pLocalID); 1620 gObj.SetUserPointer(pLocalID);
1356 1621
1357 if (specialCollisionObjects.ContainsKey(pLocalID)) 1622 if (specialCollisionObjects.ContainsKey(pLocalID))
1358 specialCollisionObjects[pLocalID] = gObj; 1623 specialCollisionObjects[pLocalID] = gObj;
1359 else 1624 else
1360 specialCollisionObjects.Add(pLocalID, gObj); 1625 specialCollisionObjects.Add(pLocalID, gObj);
1361 1626
1362 // TODO: Add to Special CollisionObjects! 1627 // TODO: Add to Special CollisionObjects!
@@ -1447,8 +1712,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1447 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); 1712 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1448 } 1713 }
1449 1714
1450 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { 1715 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1451 1716
1452 if (cShape == null) 1717 if (cShape == null)
1453 return null; 1718 return null;
1454 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; 1719 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
@@ -1456,7 +1721,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1456 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); 1721 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1457 1722
1458 1723
1459 return retShape; 1724 return retShape;
1460 } 1725 }
1461 1726
1462 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) 1727 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
@@ -1475,7 +1740,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1475 ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 1740 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1476 break; 1741 break;
1477 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: 1742 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1478 ret = BSPhysicsShapeType.SHAPE_MESH; 1743 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1479 break; 1744 break;
1480 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: 1745 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1481 ret = BSPhysicsShapeType.SHAPE_HULL; 1746 ret = BSPhysicsShapeType.SHAPE_HULL;
@@ -1503,7 +1768,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1503 ret = BSPhysicsShapeType.SHAPE_CONE; 1768 ret = BSPhysicsShapeType.SHAPE_CONE;
1504 break; 1769 break;
1505 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: 1770 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1506 ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 1771 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1507 break; 1772 break;
1508 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: 1773 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1509 ret = BSPhysicsShapeType.SHAPE_CYLINDER; 1774 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
@@ -1547,7 +1812,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1547 break; 1812 break;
1548 ///Used for GIMPACT Trimesh integration 1813 ///Used for GIMPACT Trimesh integration
1549 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: 1814 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1550 ret = BSPhysicsShapeType.SHAPE_MESH; 1815 ret = BSPhysicsShapeType.SHAPE_GIMPACT;
1551 break; 1816 break;
1552 ///Multimaterial mesh 1817 ///Multimaterial mesh
1553 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: 1818 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
@@ -1598,8 +1863,8 @@ private sealed class BulletConstraintXNA : BulletConstraint
1598 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); 1863 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1599 } 1864 }
1600 1865
1601 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, 1866 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1602 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, 1867 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1603 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) 1868 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1604 1869
1605 { 1870 {
@@ -1745,7 +2010,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1745 { 2010 {
1746 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; 2011 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1747 CompoundShape compoundshape = new CompoundShape(false); 2012 CompoundShape compoundshape = new CompoundShape(false);
1748 2013
1749 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); 2014 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1750 int ii = 1; 2015 int ii = 1;
1751 2016
@@ -1761,7 +2026,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1761 int ender = ((ii + 4) + (vertexCount*3)); 2026 int ender = ((ii + 4) + (vertexCount*3));
1762 for (int iii = ii + 4; iii < ender; iii+=3) 2027 for (int iii = ii + 4; iii < ender; iii+=3)
1763 { 2028 {
1764 2029
1765 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); 2030 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1766 } 2031 }
1767 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); 2032 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
@@ -1769,7 +2034,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1769 compoundshape.AddChildShape(ref childTrans, convexShape); 2034 compoundshape.AddChildShape(ref childTrans, convexShape);
1770 ii += (vertexCount*3 + 4); 2035 ii += (vertexCount*3 + 4);
1771 } 2036 }
1772 2037
1773 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); 2038 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1774 } 2039 }
1775 2040
@@ -1778,16 +2043,26 @@ private sealed class BulletConstraintXNA : BulletConstraint
1778 /* TODO */ return null; 2043 /* TODO */ return null;
1779 } 2044 }
1780 2045
2046 public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
2047 {
2048 /* TODO */ return null;
2049 }
2050
2051 public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2052 {
2053 /* TODO */ return null;
2054 }
2055
1781 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) 2056 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1782 { 2057 {
1783 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); 2058 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1784 2059
1785 for (int iter = 0; iter < pVerticesCount; iter++) 2060 for (int iter = 0; iter < pVerticesCount; iter++)
1786 { 2061 {
1787 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; 2062 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1788 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; 2063 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1789 } 2064 }
1790 2065
1791 ObjectArray<int> indicesarr = new ObjectArray<int>(indices); 2066 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1792 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); 2067 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1793 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); 2068 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
@@ -1801,7 +2076,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1801 mesh.m_vertexStride = 3; 2076 mesh.m_vertexStride = 3;
1802 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 2077 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1803 mesh.m_triangleIndexStride = 3; 2078 mesh.m_triangleIndexStride = 3;
1804 2079
1805 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 2080 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1806 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 2081 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1807 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); 2082 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
@@ -1810,9 +2085,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
1810 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); 2085 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1811 2086
1812 } 2087 }
2088 public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2089 {
2090 // TODO:
2091 return null;
2092 }
1813 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) 2093 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1814 { 2094 {
1815 2095
1816 String fileName = "objTest3.raw"; 2096 String fileName = "objTest3.raw";
1817 String completePath = System.IO.Path.Combine(Util.configDir(), fileName); 2097 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1818 StreamWriter sw = new StreamWriter(completePath); 2098 StreamWriter sw = new StreamWriter(completePath);
@@ -1838,7 +2118,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1838 string s = vertices[indices[i * 3]].ToString("0.0000"); 2118 string s = vertices[indices[i * 3]].ToString("0.0000");
1839 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); 2119 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1840 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); 2120 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1841 2121
1842 sw.Write(s + "\n"); 2122 sw.Write(s + "\n");
1843 } 2123 }
1844 2124
@@ -1860,7 +2140,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1860 mesh.m_vertexStride = 3; 2140 mesh.m_vertexStride = 3;
1861 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; 2141 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1862 mesh.m_triangleIndexStride = 3; 2142 mesh.m_triangleIndexStride = 3;
1863 2143
1864 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); 2144 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1865 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); 2145 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1866 2146
@@ -1891,7 +2171,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1891 sw.Close(); 2171 sw.Close();
1892 } 2172 }
1893 2173
1894 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 2174 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1895 float scaleFactor, float collisionMargin) 2175 float scaleFactor, float collisionMargin)
1896 { 2176 {
1897 const int upAxis = 2; 2177 const int upAxis = 2;
@@ -1899,7 +2179,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
1899 heightMap, scaleFactor, 2179 heightMap, scaleFactor,
1900 minHeight, maxHeight, upAxis, 2180 minHeight, maxHeight, upAxis,
1901 false); 2181 false);
1902 terrainShape.SetMargin(collisionMargin + 0.5f); 2182 terrainShape.SetMargin(collisionMargin);
1903 terrainShape.SetUseDiamondSubdivision(true); 2183 terrainShape.SetUseDiamondSubdivision(true);
1904 terrainShape.SetUserPointer(id); 2184 terrainShape.SetUserPointer(id);
1905 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); 2185 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
@@ -1933,14 +2213,14 @@ private sealed class BulletConstraintXNA : BulletConstraint
1933 /* TODO */ 2213 /* TODO */
1934 updatedEntityCount = 0; 2214 updatedEntityCount = 0;
1935 collidersCount = 0; 2215 collidersCount = 0;
1936 2216
1937 2217
1938 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); 2218 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
1939 2219
1940 return ret; 2220 return ret;
1941 } 2221 }
1942 2222
1943 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, 2223 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1944 out int updatedEntityCount, out EntityProperties[] updatedEntities, 2224 out int updatedEntityCount, out EntityProperties[] updatedEntities,
1945 out int collidersCount, out CollisionDesc[] colliders) 2225 out int collidersCount, out CollisionDesc[] colliders)
1946 { 2226 {
@@ -1949,24 +2229,24 @@ private sealed class BulletConstraintXNA : BulletConstraint
1949 return epic; 2229 return epic;
1950 } 2230 }
1951 2231
1952 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, 2232 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
1953 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) 2233 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
1954 { 2234 {
1955 int numSimSteps = 0; 2235 int numSimSteps = 0;
1956 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); 2236 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
1957 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); 2237 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
1958 LastEntityProperty=0; 2238 LastEntityProperty=0;
1959 2239
1960 2240
1961 2241
1962 2242
1963 2243
1964 2244
1965 LastCollisionDesc=0; 2245 LastCollisionDesc=0;
1966 2246
1967 updatedEntityCount = 0; 2247 updatedEntityCount = 0;
1968 collidersCount = 0; 2248 collidersCount = 0;
1969 2249
1970 2250
1971 if (pWorld is BulletWorldXNA) 2251 if (pWorld is BulletWorldXNA)
1972 { 2252 {
@@ -2023,7 +2303,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2023 2303
2024 collidersCount = LastCollisionDesc; 2304 collidersCount = LastCollisionDesc;
2025 colliders = UpdatedCollisions; 2305 colliders = UpdatedCollisions;
2026 2306
2027 2307
2028 } 2308 }
2029 else 2309 else
@@ -2031,15 +2311,15 @@ private sealed class BulletConstraintXNA : BulletConstraint
2031 //if (updatedEntities is null) 2311 //if (updatedEntities is null)
2032 //updatedEntities = new List<BulletXNA.EntityProperties>(); 2312 //updatedEntities = new List<BulletXNA.EntityProperties>();
2033 //updatedEntityCount = 0; 2313 //updatedEntityCount = 0;
2034 2314
2035 2315
2036 //collidersCount = 0; 2316 //collidersCount = 0;
2037 2317
2038 updatedEntities = new EntityProperties[0]; 2318 updatedEntities = new EntityProperties[0];
2039 2319
2040 2320
2041 colliders = new CollisionDesc[0]; 2321 colliders = new CollisionDesc[0];
2042 2322
2043 } 2323 }
2044 return numSimSteps; 2324 return numSimSteps;
2045 } 2325 }
@@ -2047,7 +2327,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2047 { 2327 {
2048 IOverlappingPairCache cache = obj.GetOverlappingPairCache(); 2328 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2049 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); 2329 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2050 2330
2051 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; 2331 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2052 PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); 2332 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2053 BroadphasePair collisionPair; 2333 BroadphasePair collisionPair;
@@ -2059,7 +2339,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2059 ManifoldPoint pt; 2339 ManifoldPoint pt;
2060 2340
2061 int numPairs = pairs.Count; 2341 int numPairs = pairs.Count;
2062 2342
2063 for (int i = 0; i < numPairs; i++) 2343 for (int i = 0; i < numPairs; i++)
2064 { 2344 {
2065 manifoldArray.Clear(); 2345 manifoldArray.Clear();
@@ -2068,7 +2348,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2068 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); 2348 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2069 if (collisionPair == null) 2349 if (collisionPair == null)
2070 continue; 2350 continue;
2071 2351
2072 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); 2352 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2073 for (int j = 0; j < manifoldArray.Count; j++) 2353 for (int j = 0; j < manifoldArray.Count; j++)
2074 { 2354 {
@@ -2091,7 +2371,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2091 } 2371 }
2092 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) 2372 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2093 { 2373 {
2094 2374
2095 IndexedVector3 contactNormal = norm; 2375 IndexedVector3 contactNormal = norm;
2096 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && 2376 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2097 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) 2377 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
@@ -2161,11 +2441,11 @@ private sealed class BulletConstraintXNA : BulletConstraint
2161 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) 2441 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2162 { 2442 {
2163 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; 2443 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2164 2444
2165 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); 2445 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2166 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); 2446 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2167 using ( 2447 using (
2168 ClosestNotMeRayResultCallback rayCallback = 2448 ClosestNotMeRayResultCallback rayCallback =
2169 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) 2449 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2170 ) 2450 )
2171 { 2451 {
@@ -2181,9 +2461,9 @@ private sealed class BulletConstraintXNA : BulletConstraint
2181 return false; 2461 return false;
2182 } 2462 }
2183} 2463}
2184
2185 2464
2186 2465
2466
2187 2467
2188 public class SimMotionState : DefaultMotionState 2468 public class SimMotionState : DefaultMotionState
2189 { 2469 {
@@ -2276,12 +2556,12 @@ private sealed class BulletConstraintXNA : BulletConstraint
2276 m_lastProperties = m_properties; 2556 m_lastProperties = m_properties;
2277 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) 2557 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2278 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); 2558 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2279 2559
2280 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; 2560 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2281 } 2561 }
2282 2562
2283 2563
2284 2564
2285 2565
2286 } 2566 }
2287 public override void SetRigidBody(RigidBody body) 2567 public override void SetRigidBody(RigidBody body)
@@ -2304,7 +2584,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
2304 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && 2584 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2305 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); 2585 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2306 } 2586 }
2307 2587
2308 } 2588 }
2309} 2589}
2310 2590
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
new file mode 100755
index 0000000..1bcf879
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
@@ -0,0 +1,411 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorAvatarMove : BSActor
40{
41 BSVMotor m_velocityMotor;
42
43 // Set to true if we think we're going up stairs.
44 // This state is remembered because collisions will turn on and off as we go up stairs.
45 int m_walkingUpStairs;
46 // The amount the step up is applying. Used to smooth stair walking.
47 float m_lastStepUp;
48
49 // Jumping happens over several frames. If use applies up force while colliding, start the
50 // jump and allow the jump to continue for this number of frames.
51 int m_jumpFrames = 0;
52 float m_jumpVelocity = 0f;
53
54 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
55 : base(physicsScene, pObj, actorName)
56 {
57 m_velocityMotor = null;
58 m_walkingUpStairs = 0;
59 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
60 }
61
62 // BSActor.isActive
63 public override bool isActive
64 {
65 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
66 }
67
68 // Release any connections and resources used by the actor.
69 // BSActor.Dispose()
70 public override void Dispose()
71 {
72 base.SetEnabled(false);
73 // Now that turned off, remove any state we have in the scene.
74 Refresh();
75 }
76
77 // Called when physical parameters (properties set in Bullet) need to be re-applied.
78 // Called at taint-time.
79 // BSActor.Refresh()
80 public override void Refresh()
81 {
82 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
83
84 // If the object is physically active, add the hoverer prestep action
85 if (isActive)
86 {
87 ActivateAvatarMove();
88 }
89 else
90 {
91 DeactivateAvatarMove();
92 }
93 }
94
95 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
96 // Register a prestep action to restore physical requirements before the next simulation step.
97 // Called at taint-time.
98 // BSActor.RemoveDependencies()
99 public override void RemoveDependencies()
100 {
101 // Nothing to do for the hoverer since it is all software at pre-step action time.
102 }
103
104 // Usually called when target velocity changes to set the current velocity and the target
105 // into the movement motor.
106 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
107 {
108 m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
109 {
110 if (m_velocityMotor != null)
111 {
112 m_velocityMotor.Reset();
113 m_velocityMotor.SetTarget(targ);
114 m_velocityMotor.SetCurrent(vel);
115 m_velocityMotor.Enabled = true;
116 }
117 });
118 }
119
120 // If a hover motor has not been created, create one and start the hovering.
121 private void ActivateAvatarMove()
122 {
123 if (m_velocityMotor == null)
124 {
125 // Infinite decay and timescale values so motor only changes current to target values.
126 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
127 0.2f, // time scale
128 BSMotor.Infinite, // decay time scale
129 1f // efficiency
130 );
131 m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
132 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
133 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
134
135 m_physicsScene.BeforeStep += Mover;
136 m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
137
138 m_walkingUpStairs = 0;
139 }
140 }
141
142 private void DeactivateAvatarMove()
143 {
144 if (m_velocityMotor != null)
145 {
146 m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
147 m_physicsScene.BeforeStep -= Mover;
148 m_velocityMotor = null;
149 }
150 }
151
152 // Called just before the simulation step. Update the vertical position for hoverness.
153 private void Mover(float timeStep)
154 {
155 // Don't do movement while the object is selected.
156 if (!isActive)
157 return;
158
159 // TODO: Decide if the step parameters should be changed depending on the avatar's
160 // state (flying, colliding, ...). There is code in ODE to do this.
161
162 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
163 // specified for the avatar is the one that should be used. For falling, if the avatar
164 // is not flying and is not colliding then it is presumed to be falling and the Z
165 // component is not fooled with (thus allowing gravity to do its thing).
166 // When the avatar is standing, though, the user has specified a velocity of zero and
167 // the avatar should be standing. But if the avatar is pushed by something in the world
168 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
169 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
170 // errors can creap in and the avatar will slowly float off in some direction.
171 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
172 // from real pushing.
173 // The code below uses whether the collider is static or moving to decide whether to zero motion.
174
175 m_velocityMotor.Step(timeStep);
176 m_controllingPrim.IsStationary = false;
177
178 // If we're not supposed to be moving, make sure things are zero.
179 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
180 {
181 // The avatar shouldn't be moving
182 m_velocityMotor.Zero();
183
184 if (m_controllingPrim.IsColliding)
185 {
186 // If we are colliding with a stationary object, presume we're standing and don't move around
187 if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect)
188 {
189 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
190 m_controllingPrim.IsStationary = true;
191 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
192 }
193
194 // Standing has more friction on the ground
195 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
196 {
197 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
198 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
199 }
200 }
201 else
202 {
203 if (m_controllingPrim.Flying)
204 {
205 // Flying and not colliding and velocity nearly zero.
206 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
207 }
208 }
209
210 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
211 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
212 }
213 else
214 {
215 // Supposed to be moving.
216 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
217
218 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
219 {
220 // Probably starting to walk. Set friction to moving friction.
221 m_controllingPrim.Friction = BSParam.AvatarFriction;
222 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
223 }
224
225 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
226 {
227 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
228 }
229
230
231 // Colliding and not flying with an upward force. The avatar must be trying to jump.
232 if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0)
233 {
234 // We allow the upward force to happen for this many frames.
235 m_jumpFrames = BSParam.AvatarJumpFrames;
236 m_jumpVelocity = stepVelocity.Z;
237 }
238
239 // The case where the avatar is not colliding and is not flying is special.
240 // The avatar is either falling or jumping and the user can be applying force to the avatar
241 // (force in some direction or force up or down).
242 // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity.
243 // If the user is trying to apply upward force but we're not colliding, assume the avatar
244 // is trying to jump and don't apply the upward force if not touching the ground any more.
245 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
246 {
247 // If upward velocity is being applied, this must be a jump and only allow that to go on so long
248 if (m_jumpFrames > 0)
249 {
250 // Since not touching the ground, only apply upward force for so long.
251 m_jumpFrames--;
252 stepVelocity.Z = m_jumpVelocity;
253 }
254 else
255 {
256 // Since we're not affected by anything, whatever vertical motion the avatar has, continue that.
257 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
258 }
259 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
260 }
261
262 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
263 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
264
265 // Add special movement force to allow avatars to walk up stepped surfaces.
266 moveForce += WalkUpStairs();
267
268 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
269 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
270 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
271 }
272 }
273
274 // Called just as the property update is received from the physics engine.
275 // Do any mode necessary for avatar movement.
276 private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
277 {
278 // Don't change position if standing on a stationary object.
279 if (m_controllingPrim.IsStationary)
280 {
281 entprop.Position = m_controllingPrim.RawPosition;
282 entprop.Velocity = OMV.Vector3.Zero;
283 m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
284 }
285
286 }
287
288 // Decide if the character is colliding with a low object and compute a force to pop the
289 // avatar up so it can walk up and over the low objects.
290 private OMV.Vector3 WalkUpStairs()
291 {
292 OMV.Vector3 ret = OMV.Vector3.Zero;
293
294 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
295 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
296 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
297
298 // Check for stairs climbing if colliding, not flying and moving forward
299 if ( m_controllingPrim.IsColliding
300 && !m_controllingPrim.Flying
301 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
302 {
303 // The range near the character's feet where we will consider stairs
304 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
305 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
306 // from the height. Revisit size and this computation when height is scaled properly.
307 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f;
308 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
309
310 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
311 // Find the highest 'good' collision.
312 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
313 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
314 {
315 // Don't care about collisions with the terrain
316 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
317 {
318 BSPhysObject collisionObject;
319 if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject))
320 {
321 if (!collisionObject.IsVolumeDetect)
322 {
323 OMV.Vector3 touchPosition = kvp.Value.Position;
324 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
325 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
326 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
327 {
328 // This contact is within the 'near the feet' range.
329 // The normal should be our contact point to the object so it is pointing away
330 // thus the difference between our facing orientation and the normal should be small.
331 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
332 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
333 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
334 if (diff < BSParam.AvatarStepApproachFactor)
335 {
336 if (highestTouchPosition.Z < touchPosition.Z)
337 highestTouchPosition = touchPosition;
338 }
339 }
340 }
341 }
342 }
343 }
344 m_walkingUpStairs = 0;
345 // If there is a good step sensing, move the avatar over the step.
346 if (highestTouchPosition != OMV.Vector3.Zero)
347 {
348 // Remember that we are going up stairs. This is needed because collisions
349 // will stop when we move up so this smoothes out that effect.
350 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
351
352 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
353 ret = ComputeStairCorrection(m_lastStepUp);
354 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
355 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
356 }
357 }
358 else
359 {
360 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
361 // we are bouncing up the stairs.
362 if (m_walkingUpStairs > 0)
363 {
364 m_walkingUpStairs--;
365 ret = ComputeStairCorrection(m_lastStepUp);
366 }
367 }
368
369 return ret;
370 }
371
372 private OMV.Vector3 ComputeStairCorrection(float stepUp)
373 {
374 OMV.Vector3 ret = OMV.Vector3.Zero;
375 OMV.Vector3 displacement = OMV.Vector3.Zero;
376
377 if (stepUp > 0f)
378 {
379 // Found the stairs contact point. Push up a little to raise the character.
380 if (BSParam.AvatarStepForceFactor > 0f)
381 {
382 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
383 ret = new OMV.Vector3(0f, 0f, upForce);
384 }
385
386 // Also move the avatar up for the new height
387 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
388 {
389 // Move the avatar up related to the height of the collision
390 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
391 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
392 }
393 else
394 {
395 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
396 {
397 // Move the avatar up about the specified step height
398 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
399 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
400 }
401 }
402 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}",
403 m_controllingPrim.LocalID, displacement, ret);
404
405 }
406 return ret;
407 }
408}
409}
410
411
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
new file mode 100755
index 0000000..8a79809
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs
@@ -0,0 +1,173 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorHover : BSActor
40{
41 private BSFMotor m_hoverMotor;
42
43 public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_hoverMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, turn me off
71 if (!m_controllingPrim.HoverActive)
72 {
73 SetEnabled(false);
74 }
75
76 // If the object is physically active, add the hoverer prestep action
77 if (isActive)
78 {
79 ActivateHover();
80 }
81 else
82 {
83 DeactivateHover();
84 }
85 }
86
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time.
90 // BSActor.RemoveDependencies()
91 public override void RemoveDependencies()
92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 }
95
96 // If a hover motor has not been created, create one and start the hovering.
97 private void ActivateHover()
98 {
99 if (m_hoverMotor == null)
100 {
101 // Turning the target on
102 m_hoverMotor = new BSFMotor("BSActorHover",
103 m_controllingPrim.HoverTau, // timeScale
104 BSMotor.Infinite, // decay time scale
105 1f // efficiency
106 );
107 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
108 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
109 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
110
111 m_physicsScene.BeforeStep += Hoverer;
112 }
113 }
114
115 private void DeactivateHover()
116 {
117 if (m_hoverMotor != null)
118 {
119 m_physicsScene.BeforeStep -= Hoverer;
120 m_hoverMotor = null;
121 }
122 }
123
124 // Called just before the simulation step. Update the vertical position for hoverness.
125 private void Hoverer(float timeStep)
126 {
127 // Don't do hovering while the object is selected.
128 if (!isActive)
129 return;
130
131 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
132 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
133 float targetHeight = m_hoverMotor.Step(timeStep);
134
135 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
136 // Compute the amount of force to push us there.
137 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
138 // Undo anything the object thinks it's doing at the moment
139 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
140
141 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
142 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
143 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
144 }
145
146 // Based on current position, determine what we should be hovering at now.
147 // Must recompute often. What if we walked offa cliff>
148 private float ComputeCurrentHoverHeight()
149 {
150 float ret = m_controllingPrim.HoverHeight;
151 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
152
153 switch (m_controllingPrim.HoverType)
154 {
155 case PIDHoverType.Ground:
156 ret = groundHeight + m_controllingPrim.HoverHeight;
157 break;
158 case PIDHoverType.GroundAndWater:
159 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
160 if (groundHeight > waterHeight)
161 {
162 ret = groundHeight + m_controllingPrim.HoverHeight;
163 }
164 else
165 {
166 ret = waterHeight + m_controllingPrim.HoverHeight;
167 }
168 break;
169 }
170 return ret;
171 }
172}
173}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
index 7219617..8b0fdeb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
@@ -36,11 +36,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSActorLockAxis : BSActor 37public class BSActorLockAxis : BSActor
38{ 38{
39 bool TryExperimentalLockAxisCode = true;
40 BSConstraint LockAxisConstraint = null; 39 BSConstraint LockAxisConstraint = null;
41 40
42 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) 41 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
43 : base(physicsScene, pObj,actorName) 42 : base(physicsScene, pObj, actorName)
44 { 43 {
45 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); 44 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
46 LockAxisConstraint = null; 45 LockAxisConstraint = null;
@@ -64,23 +63,18 @@ public class BSActorLockAxis : BSActor
64 // BSActor.Refresh() 63 // BSActor.Refresh()
65 public override void Refresh() 64 public override void Refresh()
66 { 65 {
67 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", 66 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}",
68 m_controllingPrim.LocalID, m_controllingPrim.LockedAxis, Enabled, m_controllingPrim.IsPhysicallyActive); 67 m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive);
69 // If all the axis are free, we don't need to exist 68 // If all the axis are free, we don't need to exist
70 if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) 69 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree)
71 { 70 {
72 m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,allAxisFree,removing={1}", m_controllingPrim.LocalID, ActorName); 71 Enabled = false;
73 m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
74 return;
75 } 72 }
73
76 // If the object is physically active, add the axis locking constraint 74 // If the object is physically active, add the axis locking constraint
77 if (Enabled 75 if (isActive)
78 && m_controllingPrim.IsPhysicallyActive
79 && TryExperimentalLockAxisCode
80 && m_controllingPrim.LockedAxis != m_controllingPrim.LockedAxisFree)
81 { 76 {
82 if (LockAxisConstraint == null) 77 AddAxisLockConstraint();
83 AddAxisLockConstraint();
84 } 78 }
85 else 79 else
86 { 80 {
@@ -91,15 +85,15 @@ public class BSActorLockAxis : BSActor
91 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 85 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
92 // Register a prestep action to restore physical requirements before the next simulation step. 86 // Register a prestep action to restore physical requirements before the next simulation step.
93 // Called at taint-time. 87 // Called at taint-time.
94 // BSActor.RemoveBodyDependencies() 88 // BSActor.RemoveDependencies()
95 public override void RemoveBodyDependencies() 89 public override void RemoveDependencies()
96 { 90 {
97 if (LockAxisConstraint != null) 91 if (LockAxisConstraint != null)
98 { 92 {
99 // If a constraint is set up, remove it from the physical scene 93 // If a constraint is set up, remove it from the physical scene
100 RemoveAxisLockConstraint(); 94 RemoveAxisLockConstraint();
101 // Schedule a call before the next simulation step to restore the constraint. 95 // Schedule a call before the next simulation step to restore the constraint.
102 m_physicsScene.PostTaintObject(m_controllingPrim.LockedAxisActorName, m_controllingPrim.LocalID, delegate() 96 m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate()
103 { 97 {
104 Refresh(); 98 Refresh();
105 }); 99 });
@@ -108,58 +102,76 @@ public class BSActorLockAxis : BSActor
108 102
109 private void AddAxisLockConstraint() 103 private void AddAxisLockConstraint()
110 { 104 {
111 // Lock that axis by creating a 6DOF constraint that has one end in the world and 105 if (LockAxisConstraint == null)
112 // the other in the object. 106 {
113 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 107 // Lock that axis by creating a 6DOF constraint that has one end in the world and
114 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 108 // the other in the object.
115 109 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
116 // Remove any existing axis constraint (just to be sure) 110 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
117 RemoveAxisLockConstraint();
118 111
119 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, 112 // Remove any existing axis constraint (just to be sure)
120 OMV.Vector3.Zero, OMV.Quaternion.Identity, 113 RemoveAxisLockConstraint();
121 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
122 LockAxisConstraint = axisConstrainer;
123 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
124 114
125 // The constraint is tied to the world and oriented to the prim. 115 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
116 OMV.Vector3.Zero, OMV.Quaternion.Identity,
117 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
118 LockAxisConstraint = axisConstrainer;
119 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
126 120
127 // Free to move linearly in the region 121 // The constraint is tied to the world and oriented to the prim.
128 OMV.Vector3 linearLow = OMV.Vector3.Zero;
129 OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
130 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
131 122
132 // Angular with some axis locked 123 // Free to move linearly in the region
133 float fPI = (float)Math.PI; 124 OMV.Vector3 linearLow = OMV.Vector3.Zero;
134 OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI); 125 OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
135 OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI); 126 if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis)
136 if (m_controllingPrim.LockedAxis.X != 1f) 127 {
137 { 128 linearLow.X = m_controllingPrim.RawPosition.X;
138 angularLow.X = 0f; 129 linearHigh.X = m_controllingPrim.RawPosition.X;
139 angularHigh.X = 0f; 130 }
140 } 131 if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis)
141 if (m_controllingPrim.LockedAxis.Y != 1f) 132 {
142 { 133 linearLow.Y = m_controllingPrim.RawPosition.Y;
143 angularLow.Y = 0f; 134 linearHigh.Y = m_controllingPrim.RawPosition.Y;
144 angularHigh.Y = 0f; 135 }
145 } 136 if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis)
146 if (m_controllingPrim.LockedAxis.Z != 1f) 137 {
147 { 138 linearLow.Z = m_controllingPrim.RawPosition.Z;
148 angularLow.Z = 0f; 139 linearHigh.Z = m_controllingPrim.RawPosition.Z;
149 angularHigh.Z = 0f; 140 }
150 } 141 axisConstrainer.SetLinearLimits(linearLow, linearHigh);
151 if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh)) 142
152 { 143 // Angular with some axis locked
153 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID); 144 float fPI = (float)Math.PI;
154 } 145 OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
146 OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
147 if (m_controllingPrim.LockedAngularAxis.X != BSPhysObject.FreeAxis)
148 {
149 angularLow.X = 0f;
150 angularHigh.X = 0f;
151 }
152 if (m_controllingPrim.LockedAngularAxis.Y != BSPhysObject.FreeAxis)
153 {
154 angularLow.Y = 0f;
155 angularHigh.Y = 0f;
156 }
157 if (m_controllingPrim.LockedAngularAxis.Z != BSPhysObject.FreeAxis)
158 {
159 angularLow.Z = 0f;
160 angularHigh.Z = 0f;
161 }
162 if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
163 {
164 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
165 }
155 166
156 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", 167 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
157 m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); 168 m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);
158 169
159 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. 170 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
160 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); 171 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
161 172
162 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); 173 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
174 }
163 } 175 }
164 176
165 private void RemoveAxisLockConstraint() 177 private void RemoveAxisLockConstraint()
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..bdf4bc0
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs
@@ -0,0 +1,219 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 // MoveToTarget only works on physical prims
54 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
55 }
56
57 // Release any connections and resources used by the actor.
58 // BSActor.Dispose()
59 public override void Dispose()
60 {
61 Enabled = false;
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
70 m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
71 m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
72
73 // If not active any more...
74 if (!m_controllingPrim.MoveToTargetActive)
75 {
76 Enabled = false;
77 }
78
79 if (isActive)
80 {
81 ActivateMoveToTarget();
82 }
83 else
84 {
85 DeactivateMoveToTarget();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateMoveToTarget()
100 {
101 if (m_targetMotor == null)
102 {
103 // We're taking over after this.
104 m_controllingPrim.ZeroMotion(true);
105
106 /* Someday use the PID controller
107 m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString());
108 m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau;
109 m_targetMotor.Efficiency = 1f;
110 */
111 m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(),
112 m_controllingPrim.MoveToTargetTau, // timeScale
113 BSMotor.Infinite, // decay time scale
114 1f // efficiency
115 );
116 m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
117 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
118 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
119
120 // m_physicsScene.BeforeStep += Mover;
121 m_physicsScene.BeforeStep += Mover2;
122 }
123 else
124 {
125 // If already allocated, make sure the target and other paramters are current
126 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
127 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
128 }
129 }
130
131 private void DeactivateMoveToTarget()
132 {
133 if (m_targetMotor != null)
134 {
135 // m_physicsScene.BeforeStep -= Mover;
136 m_physicsScene.BeforeStep -= Mover2;
137 m_targetMotor = null;
138 }
139 }
140
141 // Origional mover that set the objects position to move to the target.
142 // The problem was that gravity would keep trying to push the object down so
143 // the overall downward velocity would increase to infinity.
144 // Called just before the simulation step.
145 private void Mover(float timeStep)
146 {
147 // Don't do hovering while the object is selected.
148 if (!isActive)
149 return;
150
151 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
152
153 // 'movePosition' is where we'd like the prim to be at this moment.
154 OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
155
156 // If we are very close to our target, turn off the movement motor.
157 if (m_targetMotor.ErrorIsZero())
158 {
159 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
160 m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
161 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
162 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
163 // Setting the position does not cause the physics engine to generate a property update. Force it.
164 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
165 }
166 else
167 {
168 m_controllingPrim.ForcePosition = movePosition;
169 // Setting the position does not cause the physics engine to generate a property update. Force it.
170 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
171 }
172 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}",
173 m_controllingPrim.LocalID, origPosition, movePosition);
174 }
175
176 // Version of mover that applies forces to move the physical object to the target.
177 // Also overcomes gravity so the object doesn't just drop to the ground.
178 // Called just before the simulation step.
179 private void Mover2(float timeStep)
180 {
181 // Don't do hovering while the object is selected.
182 if (!isActive)
183 return;
184
185 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
186 OMV.Vector3 addedForce = OMV.Vector3.Zero;
187
188 // CorrectionVector is the movement vector required this step
189 OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition);
190
191 // If we are very close to our target, turn off the movement motor.
192 if (m_targetMotor.ErrorIsZero())
193 {
194 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}",
195 m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
196 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
197 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
198 // Setting the position does not cause the physics engine to generate a property update. Force it.
199 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
200 }
201 else
202 {
203 // First force to move us there -- the motor return a timestep scaled value.
204 addedForce = correctionVector / timeStep;
205 // Remove the existing velocity (only the moveToTarget force counts)
206 addedForce -= m_controllingPrim.RawVelocity;
207 // Overcome gravity.
208 addedForce -= m_controllingPrim.Gravity;
209
210 // Add enough force to overcome the mass of the object
211 addedForce *= m_controllingPrim.Mass;
212
213 m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */);
214 }
215 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}",
216 m_controllingPrim.LocalID, origPosition, addedForce);
217 }
218}
219}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
new file mode 100755
index 0000000..96fa0b6
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs
@@ -0,0 +1,137 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetForce : BSActor
40{
41 BSFMotor m_forceMotor;
42
43 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_forceMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetForce();
82 }
83 else
84 {
85 DeactivateSetForce();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetForce()
100 {
101 if (m_forceMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetForce()
111 {
112 if (m_forceMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_forceMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
new file mode 100755
index 0000000..65098e1
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetTorque : BSActor
40{
41 BSFMotor m_torqueMotor;
42
43 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_torqueMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetTorque();
82 }
83 else
84 {
85 DeactivateSetTorque();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetTorque()
100 {
101 if (m_torqueMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetTorque()
111 {
112 if (m_torqueMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_torqueMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
138
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
index 5a19ba4..e0ccc50 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
@@ -32,56 +32,79 @@ namespace OpenSim.Region.Physics.BulletSPlugin
32{ 32{
33public class BSActorCollection 33public class BSActorCollection
34{ 34{
35 private BSScene PhysicsScene { get; set; } 35 private BSScene m_physicsScene { get; set; }
36 private Dictionary<string, BSActor> m_actors; 36 private Dictionary<string, BSActor> m_actors;
37 37
38 public BSActorCollection(BSScene physicsScene) 38 public BSActorCollection(BSScene physicsScene)
39 { 39 {
40 PhysicsScene = physicsScene; 40 m_physicsScene = physicsScene;
41 m_actors = new Dictionary<string, BSActor>(); 41 m_actors = new Dictionary<string, BSActor>();
42 } 42 }
43 public void Add(string name, BSActor actor) 43 public void Add(string name, BSActor actor)
44 { 44 {
45 m_actors[name] = actor; 45 lock (m_actors)
46 {
47 if (!m_actors.ContainsKey(name))
48 {
49 m_actors[name] = actor;
50 }
51 }
46 } 52 }
47 public bool RemoveAndRelease(string name) 53 public bool RemoveAndRelease(string name)
48 { 54 {
49 bool ret = false; 55 bool ret = false;
50 if (m_actors.ContainsKey(name)) 56 lock (m_actors)
51 { 57 {
52 BSActor beingRemoved = m_actors[name]; 58 if (m_actors.ContainsKey(name))
53 beingRemoved.Dispose(); 59 {
54 m_actors.Remove(name); 60 BSActor beingRemoved = m_actors[name];
55 ret = true; 61 m_actors.Remove(name);
62 beingRemoved.Dispose();
63 ret = true;
64 }
56 } 65 }
57 return ret; 66 return ret;
58 } 67 }
59 public void Clear() 68 public void Clear()
60 { 69 {
61 Release(); 70 lock (m_actors)
62 m_actors.Clear(); 71 {
72 ForEachActor(a => a.Dispose());
73 m_actors.Clear();
74 }
75 }
76 public void Dispose()
77 {
78 Clear();
63 } 79 }
64 public bool HasActor(string name) 80 public bool HasActor(string name)
65 { 81 {
66 return m_actors.ContainsKey(name); 82 return m_actors.ContainsKey(name);
67 } 83 }
84 public bool TryGetActor(string actorName, out BSActor theActor)
85 {
86 return m_actors.TryGetValue(actorName, out theActor);
87 }
68 public void ForEachActor(Action<BSActor> act) 88 public void ForEachActor(Action<BSActor> act)
69 { 89 {
70 foreach (KeyValuePair<string, BSActor> kvp in m_actors) 90 lock (m_actors)
71 act(kvp.Value); 91 {
92 foreach (KeyValuePair<string, BSActor> kvp in m_actors)
93 act(kvp.Value);
94 }
72 } 95 }
73 96
74 public void Release() 97 public void Enable(bool enabl)
75 { 98 {
76 ForEachActor(a => a.Dispose()); 99 ForEachActor(a => a.SetEnabled(enabl));
77 } 100 }
78 public void Refresh() 101 public void Refresh()
79 { 102 {
80 ForEachActor(a => a.Refresh()); 103 ForEachActor(a => a.Refresh());
81 } 104 }
82 public void RemoveBodyDependencies() 105 public void RemoveDependencies()
83 { 106 {
84 ForEachActor(a => a.RemoveBodyDependencies()); 107 ForEachActor(a => a.RemoveDependencies());
85 } 108 }
86} 109}
87 110
@@ -90,7 +113,7 @@ public class BSActorCollection
90/// Each physical object can have 'actors' who are pushing the object around. 113/// Each physical object can have 'actors' who are pushing the object around.
91/// This can be used for hover, locking axis, making vehicles, etc. 114/// This can be used for hover, locking axis, making vehicles, etc.
92/// Each physical object can have multiple actors acting on it. 115/// Each physical object can have multiple actors acting on it.
93/// 116///
94/// An actor usually registers itself with physics scene events (pre-step action) 117/// An actor usually registers itself with physics scene events (pre-step action)
95/// and modifies the parameters on the host physical object. 118/// and modifies the parameters on the host physical object.
96/// </summary> 119/// </summary>
@@ -98,7 +121,7 @@ public abstract class BSActor
98{ 121{
99 protected BSScene m_physicsScene { get; private set; } 122 protected BSScene m_physicsScene { get; private set; }
100 protected BSPhysObject m_controllingPrim { get; private set; } 123 protected BSPhysObject m_controllingPrim { get; private set; }
101 protected bool Enabled { get; set; } 124 public virtual bool Enabled { get; set; }
102 public string ActorName { get; private set; } 125 public string ActorName { get; private set; }
103 126
104 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) 127 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
@@ -114,8 +137,10 @@ public abstract class BSActor
114 { 137 {
115 get { return Enabled; } 138 get { return Enabled; }
116 } 139 }
117 // Turn the actor on an off. 140
118 public virtual void Enable(bool setEnabled) 141 // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
142 // Anyone else should assign true/false to 'Enabled'.
143 public void SetEnabled(bool setEnabled)
119 { 144 {
120 Enabled = setEnabled; 145 Enabled = setEnabled;
121 } 146 }
@@ -125,7 +150,7 @@ public abstract class BSActor
125 public abstract void Refresh(); 150 public abstract void Refresh();
126 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). 151 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
127 // Register a prestep action to restore physical requirements before the next simulation step. 152 // Register a prestep action to restore physical requirements before the next simulation step.
128 public abstract void RemoveBodyDependencies(); 153 public abstract void RemoveDependencies();
129 154
130} 155}
131} 156}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
index d0d9f34..be6f152 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -43,7 +43,9 @@ public enum ConstraintType : int
43 SLIDER_CONSTRAINT_TYPE, 43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE, 44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE, 45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_CONSTRAINT_TYPE 46 MAX_CONSTRAINT_TYPE, // last type defined by Bullet
47 //
48 FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
47} 49}
48 50
49// =============================================================================== 51// ===============================================================================
@@ -70,6 +72,8 @@ public enum BSPhysicsShapeType
70 SHAPE_COMPOUND = 22, 72 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23, 73 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24, 74 SHAPE_AVATAR = 24,
75 SHAPE_CONVEXHULL= 25,
76 SHAPE_GIMPACT = 26,
73}; 77};
74 78
75// The native shapes have predefined shape hash keys 79// The native shapes have predefined shape hash keys
@@ -245,7 +249,7 @@ public enum CollisionFlags : uint
245 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking 249 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
246 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape 250 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
247 BS_NONE = 0, 251 BS_NONE = 0,
248 BS_ALL = 0xFFFFFFFF 252 BS_ALL = 0x7FFF // collision flags are a signed short
249}; 253};
250 254
251// Values f collisions groups and masks 255// Values f collisions groups and masks
@@ -261,14 +265,14 @@ public enum CollisionFilterGroups : uint
261 BDebrisGroup = 1 << 3, // 0008 265 BDebrisGroup = 1 << 3, // 0008
262 BSensorTrigger = 1 << 4, // 0010 266 BSensorTrigger = 1 << 4, // 0010
263 BCharacterGroup = 1 << 5, // 0020 267 BCharacterGroup = 1 << 5, // 0020
264 BAllGroup = 0x000FFFFF, 268 BAllGroup = 0x0007FFF, // collision flags are a signed short
265 // Filter groups defined by BulletSim 269 // Filter groups defined by BulletSim
266 BGroundPlaneGroup = 1 << 10, // 0400 270 BGroundPlaneGroup = 1 << 8, // 0400
267 BTerrainGroup = 1 << 11, // 0800 271 BTerrainGroup = 1 << 9, // 0800
268 BRaycastGroup = 1 << 12, // 1000 272 BRaycastGroup = 1 << 10, // 1000
269 BSolidGroup = 1 << 13, // 2000 273 BSolidGroup = 1 << 11, // 2000
270 // BLinksetGroup = xx // a linkset proper is either static or dynamic 274 // BLinksetGroup = xx // a linkset proper is either static or dynamic
271 BLinksetChildGroup = 1 << 14, // 4000 275 BLinksetChildGroup = 1 << 12, // 4000
272}; 276};
273 277
274// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 278// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -288,7 +292,7 @@ public enum ConstraintParamAxis : int
288 AXIS_ANGULAR_X, 292 AXIS_ANGULAR_X,
289 AXIS_ANGULAR_Y, 293 AXIS_ANGULAR_Y,
290 AXIS_ANGULAR_Z, 294 AXIS_ANGULAR_Z,
291 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls 295 AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
292 AXIS_ANGULAR_ALL, 296 AXIS_ANGULAR_ALL,
293 AXIS_ALL 297 AXIS_ALL
294}; 298};
@@ -297,7 +301,7 @@ public abstract class BSAPITemplate
297{ 301{
298// Returns the name of the underlying Bullet engine 302// Returns the name of the underlying Bullet engine
299public abstract string BulletEngineName { get; } 303public abstract string BulletEngineName { get; }
300public abstract string BulletEngineVersion { get; protected set;} 304public abstract string BulletEngineVersion { get; protected set;}
301 305
302// Initialization and simulation 306// Initialization and simulation
303public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 307public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -320,11 +324,21 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
320 int indicesCount, int[] indices, 324 int indicesCount, int[] indices,
321 int verticesCount, float[] vertices ); 325 int verticesCount, float[] vertices );
322 326
327public abstract BulletShape CreateGImpactShape(BulletWorld world,
328 int indicesCount, int[] indices,
329 int verticesCount, float[] vertices );
330
323public abstract BulletShape CreateHullShape(BulletWorld world, 331public abstract BulletShape CreateHullShape(BulletWorld world,
324 int hullCount, float[] hulls); 332 int hullCount, float[] hulls);
325 333
326public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); 334public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
327 335
336public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
337
338public abstract BulletShape CreateConvexHullShape(BulletWorld world,
339 int indicesCount, int[] indices,
340 int verticesCount, float[] vertices );
341
328public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); 342public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
329 343
330public abstract bool IsNativeShape(BulletShape shape); 344public abstract bool IsNativeShape(BulletShape shape);
@@ -366,7 +380,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
366// ===================================================================================== 380// =====================================================================================
367public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); 381public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
368 382
369public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 383public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
370 float scaleFactor, float collisionMargin); 384 float scaleFactor, float collisionMargin);
371 385
372// ===================================================================================== 386// =====================================================================================
@@ -381,7 +395,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 395 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
382 396
383public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, 397public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
384 Vector3 frameInBloc, Quaternion frameInBrot, 398 Vector3 frameInBloc, Quaternion frameInBrot,
385 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); 399 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
386 400
387public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 401public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
@@ -429,6 +443,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e
429 443
430public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); 444public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
431 445
446public const int HINGE_NOT_SPECIFIED = -1;
447public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
448
449public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
450
451public const int SPRING_NOT_SPECIFIED = -1;
452public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
453
454public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
455
456public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
457
458public const int SLIDER_LOWER_LIMIT = 0;
459public const int SLIDER_UPPER_LIMIT = 1;
460public const int SLIDER_LINEAR = 2;
461public const int SLIDER_ANGULAR = 3;
462public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
463
464public const int SLIDER_SET_SOFTNESS = 4;
465public const int SLIDER_SET_RESTITUTION = 5;
466public const int SLIDER_SET_DAMPING = 6;
467public const int SLIDER_SET_DIRECTION = 7;
468public const int SLIDER_SET_LIMIT = 8;
469public const int SLIDER_SET_ORTHO = 9;
470public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
471
472public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
473
474public const int SLIDER_MOTOR_VELOCITY = 10;
475public const int SLIDER_MAX_MOTOR_FORCE = 11;
476public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
477
432public abstract bool CalculateTransforms(BulletConstraint constrain); 478public abstract bool CalculateTransforms(BulletConstraint constrain);
433 479
434public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); 480public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
@@ -452,6 +498,8 @@ public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
452 498
453public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); 499public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
454 500
501public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
502
455public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); 503public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
456 504
457public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); 505public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 25be416..fc18960 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -43,15 +43,10 @@ public sealed class BSCharacter : BSPhysObject
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private bool _grabbed; 44 private bool _grabbed;
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass; 46 private float _mass;
48 private float _avatarVolume; 47 private float _avatarVolume;
49 private OMV.Vector3 _force;
50 private OMV.Vector3 _velocity;
51 private OMV.Vector3 _torque;
52 private float _collisionScore; 48 private float _collisionScore;
53 private OMV.Vector3 _acceleration; 49 private OMV.Vector3 _acceleration;
54 private OMV.Quaternion _orientation;
55 private int _physicsActorType; 50 private int _physicsActorType;
56 private bool _isPhysical; 51 private bool _isPhysical;
57 private bool _flying; 52 private bool _flying;
@@ -61,31 +56,26 @@ public sealed class BSCharacter : BSPhysObject
61 private OMV.Vector3 _rotationalVelocity; 56 private OMV.Vector3 _rotationalVelocity;
62 private bool _kinematic; 57 private bool _kinematic;
63 private float _buoyancy; 58 private float _buoyancy;
64 private bool _isStationaryStanding; // true is standing on a stationary object
65 59
66 private BSVMotor _velocityMotor; 60 private BSActorAvatarMove m_moveActor;
61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
67 62
68 private OMV.Vector3 _PIDTarget; 63 private OMV.Vector3 _PIDTarget;
69 private bool _usePID; 64 private bool _usePID;
70 private float _PIDTau; 65 private float _PIDTau;
71 private bool _useHoverPID;
72 private float _PIDHoverHeight;
73 private PIDHoverType _PIDHoverType;
74 private float _PIDHoverTao;
75 66
76 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 67 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
77 : base(parent_scene, localID, avName, "BSCharacter") 68 : base(parent_scene, localID, avName, "BSCharacter")
78 { 69 {
79 _physicsActorType = (int)ActorTypes.Agent; 70 _physicsActorType = (int)ActorTypes.Agent;
80 _position = pos; 71 RawPosition = pos;
81 72
82 _flying = isFlying; 73 _flying = isFlying;
83 _orientation = OMV.Quaternion.Identity; 74 RawOrientation = OMV.Quaternion.Identity;
84 _velocity = OMV.Vector3.Zero; 75 RawVelocity = OMV.Vector3.Zero;
85 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 76 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
86 Friction = BSParam.AvatarStandingFriction; 77 Friction = BSParam.AvatarStandingFriction;
87 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; 78 Density = BSParam.AvatarDensity;
88 _isStationaryStanding = false;
89 79
90 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 80 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
91 // replace with the default values. 81 // replace with the default values.
@@ -99,19 +89,26 @@ public sealed class BSCharacter : BSPhysObject
99 // set _avatarVolume and _mass based on capsule size, _density and Scale 89 // set _avatarVolume and _mass based on capsule size, _density and Scale
100 ComputeAvatarVolumeAndMass(); 90 ComputeAvatarVolumeAndMass();
101 91
102 SetupMovementMotor(); 92 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}",
103 93 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos);
104 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
105 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
106 94
107 // do actual creation in taint time 95 // do actual creation in taint time
108 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 96 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
109 { 97 {
110 DetailLog("{0},BSCharacter.create,taint", LocalID); 98 DetailLog("{0},BSCharacter.create,taint", LocalID);
111 // New body and shape into PhysBody and PhysShape 99 // New body and shape into PhysBody and PhysShape
112 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 100 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
101
102 // The avatar's movement is controlled by this motor that speeds up and slows down
103 // the avatar seeking to reach the motor's target speed.
104 // This motor runs as a prestep action for the avatar so it will keep the avatar
105 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
106 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
107 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
113 108
114 SetPhysicalProperties(); 109 SetPhysicalProperties();
110
111 IsInitialized = true;
115 }); 112 });
116 return; 113 return;
117 } 114 }
@@ -119,219 +116,68 @@ public sealed class BSCharacter : BSPhysObject
119 // called when this character is being destroyed and the resources should be released 116 // called when this character is being destroyed and the resources should be released
120 public override void Destroy() 117 public override void Destroy()
121 { 118 {
119 IsInitialized = false;
120
122 base.Destroy(); 121 base.Destroy();
123 122
124 DetailLog("{0},BSCharacter.Destroy", LocalID); 123 DetailLog("{0},BSCharacter.Destroy", LocalID);
125 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
126 { 125 {
127 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); 126 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
128 PhysBody.Clear(); 127 PhysBody.Clear();
129 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); 128 PhysShape.Dereference(PhysScene);
130 PhysShape.Clear(); 129 PhysShape = new BSShapeNull();
131 }); 130 });
132 } 131 }
133 132
134 private void SetPhysicalProperties() 133 private void SetPhysicalProperties()
135 { 134 {
136 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 135 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
137 136
138 ZeroMotion(true); 137 ZeroMotion(true);
139 ForcePosition = _position; 138 ForcePosition = RawPosition;
140 139
141 // Set the velocity 140 // Set the velocity
142 _velocityMotor.Reset(); 141 if (m_moveActor != null)
143 _velocityMotor.SetTarget(_velocity); 142 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
144 _velocityMotor.SetCurrent(_velocity); 143
145 ForceVelocity = _velocity; 144 ForceVelocity = RawVelocity;
146 145
147 // This will enable or disable the flying buoyancy of the avatar. 146 // This will enable or disable the flying buoyancy of the avatar.
148 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 147 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
149 Flying = _flying; 148 Flying = _flying;
150 149
151 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 150 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
152 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 151 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
153 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 152 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
154 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 153 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
155 if (BSParam.CcdMotionThreshold > 0f) 154 if (BSParam.CcdMotionThreshold > 0f)
156 { 155 {
157 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 156 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
158 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 157 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
159 } 158 }
160 159
161 UpdatePhysicalMassProperties(RawMass, false); 160 UpdatePhysicalMassProperties(RawMass, false);
162 161
163 // Make so capsule does not fall over 162 // Make so capsule does not fall over
164 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 163 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
164
165 // The avatar mover sets some parameters.
166 PhysicalActors.Refresh();
165 167
166 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 168 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
167 169
168 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 170 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
169 171
170 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 172 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
171 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 173 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
172 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 174 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
173 175
174 // Do this after the object has been added to the world 176 // Do this after the object has been added to the world
175 PhysBody.collisionType = CollisionType.Avatar; 177 PhysBody.collisionType = CollisionType.Avatar;
176 PhysBody.ApplyCollisionMask(PhysicsScene); 178 PhysBody.ApplyCollisionMask(PhysScene);
177 }
178
179 // The avatar's movement is controlled by this motor that speeds up and slows down
180 // the avatar seeking to reach the motor's target speed.
181 // This motor runs as a prestep action for the avatar so it will keep the avatar
182 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
183 private void SetupMovementMotor()
184 {
185 // Infinite decay and timescale values so motor only changes current to target values.
186 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
187 0.2f, // time scale
188 BSMotor.Infinite, // decay time scale
189 BSMotor.InfiniteVector, // friction timescale
190 1f // efficiency
191 );
192 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
193
194 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
195 {
196 // TODO: Decide if the step parameters should be changed depending on the avatar's
197 // state (flying, colliding, ...). There is code in ODE to do this.
198
199 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
200 // specified for the avatar is the one that should be used. For falling, if the avatar
201 // is not flying and is not colliding then it is presumed to be falling and the Z
202 // component is not fooled with (thus allowing gravity to do its thing).
203 // When the avatar is standing, though, the user has specified a velocity of zero and
204 // the avatar should be standing. But if the avatar is pushed by something in the world
205 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
206 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
207 // errors can creap in and the avatar will slowly float off in some direction.
208 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
209 // from real pushing.
210 // The code below uses whether the collider is static or moving to decide whether to zero motion.
211
212 _velocityMotor.Step(timeStep);
213 _isStationaryStanding = false;
214
215 // If we're not supposed to be moving, make sure things are zero.
216 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
217 {
218 // The avatar shouldn't be moving
219 _velocityMotor.Zero();
220
221 if (IsColliding)
222 {
223 // If we are colliding with a stationary object, presume we're standing and don't move around
224 if (!ColliderIsMoving)
225 {
226 DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
227 _isStationaryStanding = true;
228 ZeroMotion(true /* inTaintTime */);
229 }
230
231 // Standing has more friction on the ground
232 if (Friction != BSParam.AvatarStandingFriction)
233 {
234 Friction = BSParam.AvatarStandingFriction;
235 PhysicsScene.PE.SetFriction(PhysBody, Friction);
236 }
237 }
238 else
239 {
240 if (Flying)
241 {
242 // Flying and not collising and velocity nearly zero.
243 ZeroMotion(true /* inTaintTime */);
244 }
245 }
246
247 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
248 }
249 else
250 {
251 // Supposed to be moving.
252 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
253
254 if (Friction != BSParam.AvatarFriction)
255 {
256 // Probably starting up walking. Set friction to moving friction.
257 Friction = BSParam.AvatarFriction;
258 PhysicsScene.PE.SetFriction(PhysBody, Friction);
259 }
260
261 // If falling, we keep the world's downward vector no matter what the other axis specify.
262 // The check for _velocity.Z < 0 makes jumping work (temporary upward force).
263 if (!Flying && !IsColliding)
264 {
265 if (_velocity.Z < 0)
266 stepVelocity.Z = _velocity.Z;
267 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
268 }
269
270 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
271 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
272
273 // Should we check for move force being small and forcing velocity to zero?
274
275 // Add special movement force to allow avatars to walk up stepped surfaces.
276 moveForce += WalkUpStairs();
277
278 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
279 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
280 }
281 });
282 } 179 }
283 180
284 // Decide if the character is colliding with a low object and compute a force to pop the
285 // avatar up so it can walk up and over the low objects.
286 private OMV.Vector3 WalkUpStairs()
287 {
288 OMV.Vector3 ret = OMV.Vector3.Zero;
289
290 // This test is done if moving forward, not flying and is colliding with something.
291 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
292 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
293 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
294 {
295 // The range near the character's feet where we will consider stairs
296 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
297 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
298
299 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
300 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
301 {
302 // Don't care about collisions with the terrain
303 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
304 {
305 OMV.Vector3 touchPosition = kvp.Value.Position;
306 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
307 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
308 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
309 {
310 // This contact is within the 'near the feet' range.
311 // The normal should be our contact point to the object so it is pointing away
312 // thus the difference between our facing orientation and the normal should be small.
313 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
314 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
315 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
316 if (diff < BSParam.AvatarStepApproachFactor)
317 {
318 // Found the stairs contact point. Push up a little to raise the character.
319 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
320 ret = new OMV.Vector3(0f, 0f, upForce);
321
322 // Also move the avatar up for the new height
323 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
324 ForcePosition = RawPosition + displacement;
325 }
326 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
327 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
328 }
329 }
330 }
331 }
332
333 return ret;
334 }
335 181
336 public override void RequestPhysicsterseUpdate() 182 public override void RequestPhysicsterseUpdate()
337 { 183 {
@@ -348,6 +194,10 @@ public sealed class BSCharacter : BSPhysObject
348 } 194 }
349 195
350 set { 196 set {
197 // This is how much the avatar size is changing. Positive means getting bigger.
198 // The avatar altitude must be adjusted for this change.
199 float heightChange = value.Z - _size.Z;
200
351 _size = value; 201 _size = value;
352 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 202 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
353 // replace with the default values. 203 // replace with the default values.
@@ -359,14 +209,18 @@ public sealed class BSCharacter : BSPhysObject
359 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 209 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
360 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 210 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
361 211
362 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 212 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
363 { 213 {
364 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 214 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
365 { 215 {
366 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 216 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
367 UpdatePhysicalMassProperties(RawMass, true); 217 UpdatePhysicalMassProperties(RawMass, true);
218
219 // Adjust the avatar's position to account for the increase/decrease in size
220 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
221
368 // Make sure this change appears as a property update event 222 // Make sure this change appears as a property update event
369 PhysicsScene.PE.PushUpdate(PhysBody); 223 PhysScene.PE.PushUpdate(PhysBody);
370 } 224 }
371 }); 225 });
372 226
@@ -377,11 +231,6 @@ public sealed class BSCharacter : BSPhysObject
377 { 231 {
378 set { BaseShape = value; } 232 set { BaseShape = value; }
379 } 233 }
380 // I want the physics engine to make an avatar capsule
381 public override BSPhysicsShapeType PreferredPhysicalShape
382 {
383 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
384 }
385 234
386 public override bool Grabbed { 235 public override bool Grabbed {
387 set { _grabbed = value; } 236 set { _grabbed = value; }
@@ -403,29 +252,29 @@ public sealed class BSCharacter : BSPhysObject
403 // Called at taint time! 252 // Called at taint time!
404 public override void ZeroMotion(bool inTaintTime) 253 public override void ZeroMotion(bool inTaintTime)
405 { 254 {
406 _velocity = OMV.Vector3.Zero; 255 RawVelocity = OMV.Vector3.Zero;
407 _acceleration = OMV.Vector3.Zero; 256 _acceleration = OMV.Vector3.Zero;
408 _rotationalVelocity = OMV.Vector3.Zero; 257 _rotationalVelocity = OMV.Vector3.Zero;
409 258
410 // Zero some other properties directly into the physics engine 259 // Zero some other properties directly into the physics engine
411 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 260 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
412 { 261 {
413 if (PhysBody.HasPhysicalBody) 262 if (PhysBody.HasPhysicalBody)
414 PhysicsScene.PE.ClearAllForces(PhysBody); 263 PhysScene.PE.ClearAllForces(PhysBody);
415 }); 264 });
416 } 265 }
417 public override void ZeroAngularMotion(bool inTaintTime) 266 public override void ZeroAngularMotion(bool inTaintTime)
418 { 267 {
419 _rotationalVelocity = OMV.Vector3.Zero; 268 _rotationalVelocity = OMV.Vector3.Zero;
420 269
421 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 270 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
422 { 271 {
423 if (PhysBody.HasPhysicalBody) 272 if (PhysBody.HasPhysicalBody)
424 { 273 {
425 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 274 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
426 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 275 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
427 // The next also get rid of applied linear force but the linear velocity is untouched. 276 // The next also get rid of applied linear force but the linear velocity is untouched.
428 PhysicsScene.PE.ClearForces(PhysBody); 277 PhysScene.PE.ClearForces(PhysBody);
429 } 278 }
430 }); 279 });
431 } 280 }
@@ -433,38 +282,33 @@ public sealed class BSCharacter : BSPhysObject
433 282
434 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 283 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
435 284
436 public override OMV.Vector3 RawPosition
437 {
438 get { return _position; }
439 set { _position = value; }
440 }
441 public override OMV.Vector3 Position { 285 public override OMV.Vector3 Position {
442 get { 286 get {
443 // Don't refetch the position because this function is called a zillion times 287 // Don't refetch the position because this function is called a zillion times
444 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); 288 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
445 return _position; 289 return RawPosition;
446 } 290 }
447 set { 291 set {
448 _position = value; 292 RawPosition = value;
449 293
450 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 294 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
451 { 295 {
452 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 296 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
453 PositionSanityCheck(); 297 PositionSanityCheck();
454 ForcePosition = _position; 298 ForcePosition = RawPosition;
455 }); 299 });
456 } 300 }
457 } 301 }
458 public override OMV.Vector3 ForcePosition { 302 public override OMV.Vector3 ForcePosition {
459 get { 303 get {
460 _position = PhysicsScene.PE.GetPosition(PhysBody); 304 RawPosition = PhysScene.PE.GetPosition(PhysBody);
461 return _position; 305 return RawPosition;
462 } 306 }
463 set { 307 set {
464 _position = value; 308 RawPosition = value;
465 if (PhysBody.HasPhysicalBody) 309 if (PhysBody.HasPhysicalBody)
466 { 310 {
467 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 311 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
468 } 312 }
469 } 313 }
470 } 314 }
@@ -478,30 +322,30 @@ public sealed class BSCharacter : BSPhysObject
478 bool ret = false; 322 bool ret = false;
479 323
480 // TODO: check for out of bounds 324 // TODO: check for out of bounds
481 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 325 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
482 { 326 {
483 // The character is out of the known/simulated area. 327 // The character is out of the known/simulated area.
484 // Force the avatar position to be within known. ScenePresence will use the position 328 // Force the avatar position to be within known. ScenePresence will use the position
485 // plus the velocity to decide if the avatar is moving out of the region. 329 // plus the velocity to decide if the avatar is moving out of the region.
486 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); 330 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
487 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); 331 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
488 return true; 332 return true;
489 } 333 }
490 334
491 // If below the ground, move the avatar up 335 // If below the ground, move the avatar up
492 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 336 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
493 if (Position.Z < terrainHeight) 337 if (Position.Z < terrainHeight)
494 { 338 {
495 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); 339 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
496 _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; 340 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
497 ret = true; 341 ret = true;
498 } 342 }
499 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 343 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
500 { 344 {
501 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 345 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
502 if (Position.Z < waterHeight) 346 if (Position.Z < waterHeight)
503 { 347 {
504 _position.Z = waterHeight; 348 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
505 ret = true; 349 ret = true;
506 } 350 }
507 } 351 }
@@ -519,10 +363,10 @@ public sealed class BSCharacter : BSPhysObject
519 { 363 {
520 // The new position value must be pushed into the physics engine but we can't 364 // The new position value must be pushed into the physics engine but we can't
521 // just assign to "Position" because of potential call loops. 365 // just assign to "Position" because of potential call loops.
522 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 366 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
523 { 367 {
524 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 368 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
525 ForcePosition = _position; 369 ForcePosition = RawPosition;
526 }); 370 });
527 ret = true; 371 ret = true;
528 } 372 }
@@ -532,25 +376,25 @@ public sealed class BSCharacter : BSPhysObject
532 public override float Mass { get { return _mass; } } 376 public override float Mass { get { return _mass; } }
533 377
534 // used when we only want this prim's mass and not the linkset thing 378 // used when we only want this prim's mass and not the linkset thing
535 public override float RawMass { 379 public override float RawMass {
536 get {return _mass; } 380 get {return _mass; }
537 } 381 }
538 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 382 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
539 { 383 {
540 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 384 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
541 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 385 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
542 } 386 }
543 387
544 public override OMV.Vector3 Force { 388 public override OMV.Vector3 Force {
545 get { return _force; } 389 get { return RawForce; }
546 set { 390 set {
547 _force = value; 391 RawForce = value;
548 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 392 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
549 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 393 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
550 { 394 {
551 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 395 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
552 if (PhysBody.HasPhysicalBody) 396 if (PhysBody.HasPhysicalBody)
553 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 397 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
554 }); 398 });
555 } 399 }
556 } 400 }
@@ -564,6 +408,7 @@ public sealed class BSCharacter : BSPhysObject
564 408
565 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 409 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
566 public override void SetVolumeDetect(int param) { return; } 410 public override void SetVolumeDetect(int param) { return; }
411 public override bool IsVolumeDetect { get { return false; } }
567 412
568 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 413 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
569 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 414 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
@@ -573,61 +418,49 @@ public sealed class BSCharacter : BSPhysObject
573 { 418 {
574 get 419 get
575 { 420 {
576 return m_targetVelocity; 421 return base.m_targetVelocity;
577 } 422 }
578 set 423 set
579 { 424 {
580 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 425 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
581 m_targetVelocity = value; 426 m_targetVelocity = value;
582 OMV.Vector3 targetVel = value; 427 OMV.Vector3 targetVel = value;
583 if (_setAlwaysRun) 428 if (_setAlwaysRun && !_flying)
584 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); 429 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
585 430
586 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 431 if (m_moveActor != null)
587 { 432 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
588 _velocityMotor.Reset();
589 _velocityMotor.SetTarget(targetVel);
590 _velocityMotor.SetCurrent(_velocity);
591 _velocityMotor.Enabled = true;
592 });
593 } 433 }
594 } 434 }
595 public override OMV.Vector3 RawVelocity
596 {
597 get { return _velocity; }
598 set { _velocity = value; }
599 }
600 // Directly setting velocity means this is what the user really wants now. 435 // Directly setting velocity means this is what the user really wants now.
601 public override OMV.Vector3 Velocity { 436 public override OMV.Vector3 Velocity {
602 get { return _velocity; } 437 get { return RawVelocity; }
603 set { 438 set {
604 _velocity = value; 439 RawVelocity = value;
605 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 440 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
606 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 441 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
607 { 442 {
608 _velocityMotor.Reset(); 443 if (m_moveActor != null)
609 _velocityMotor.SetCurrent(_velocity); 444 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
610 _velocityMotor.SetTarget(_velocity);
611 _velocityMotor.Enabled = false;
612 445
613 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 446 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
614 ForceVelocity = _velocity; 447 ForceVelocity = RawVelocity;
615 }); 448 });
616 } 449 }
617 } 450 }
618 public override OMV.Vector3 ForceVelocity { 451 public override OMV.Vector3 ForceVelocity {
619 get { return _velocity; } 452 get { return RawVelocity; }
620 set { 453 set {
621 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 454 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
622 455
623 _velocity = value; 456 RawVelocity = value;
624 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 457 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
625 PhysicsScene.PE.Activate(PhysBody, true); 458 PhysScene.PE.Activate(PhysBody, true);
626 } 459 }
627 } 460 }
628 public override OMV.Vector3 Torque { 461 public override OMV.Vector3 Torque {
629 get { return _torque; } 462 get { return RawTorque; }
630 set { _torque = value; 463 set { RawTorque = value;
631 } 464 }
632 } 465 }
633 public override float CollisionScore { 466 public override float CollisionScore {
@@ -639,22 +472,27 @@ public sealed class BSCharacter : BSPhysObject
639 get { return _acceleration; } 472 get { return _acceleration; }
640 set { _acceleration = value; } 473 set { _acceleration = value; }
641 } 474 }
642 public override OMV.Quaternion RawOrientation
643 {
644 get { return _orientation; }
645 set { _orientation = value; }
646 }
647 public override OMV.Quaternion Orientation { 475 public override OMV.Quaternion Orientation {
648 get { return _orientation; } 476 get { return RawOrientation; }
649 set { 477 set {
650 // Orientation is set zillions of times when an avatar is walking. It's like 478 // Orientation is set zillions of times when an avatar is walking. It's like
651 // the viewer doesn't trust us. 479 // the viewer doesn't trust us.
652 if (_orientation != value) 480 if (RawOrientation != value)
653 { 481 {
654 _orientation = value; 482 RawOrientation = value;
655 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 483 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
656 { 484 {
657 ForceOrientation = _orientation; 485 // Bullet assumes we know what we are doing when forcing orientation
486 // so it lets us go against all the rules and just compensates for them later.
487 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
488 // This keeps us from flipping the capsule over which the veiwer does not understand.
489 float oRoll, oPitch, oYaw;
490 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
491 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
492 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
493 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
494 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
495 ForceOrientation = trimmedOrientation;
658 }); 496 });
659 } 497 }
660 } 498 }
@@ -664,16 +502,16 @@ public sealed class BSCharacter : BSPhysObject
664 { 502 {
665 get 503 get
666 { 504 {
667 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 505 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
668 return _orientation; 506 return RawOrientation;
669 } 507 }
670 set 508 set
671 { 509 {
672 _orientation = value; 510 RawOrientation = value;
673 if (PhysBody.HasPhysicalBody) 511 if (PhysBody.HasPhysicalBody)
674 { 512 {
675 // _position = PhysicsScene.PE.GetPosition(BSBody); 513 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
676 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 514 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
677 } 515 }
678 } 516 }
679 } 517 }
@@ -722,14 +560,14 @@ public sealed class BSCharacter : BSPhysObject
722 public override bool FloatOnWater { 560 public override bool FloatOnWater {
723 set { 561 set {
724 _floatOnWater = value; 562 _floatOnWater = value;
725 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 563 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
726 { 564 {
727 if (PhysBody.HasPhysicalBody) 565 if (PhysBody.HasPhysicalBody)
728 { 566 {
729 if (_floatOnWater) 567 if (_floatOnWater)
730 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 568 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
731 else 569 else
732 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 570 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
733 } 571 }
734 }); 572 });
735 } 573 }
@@ -750,7 +588,7 @@ public sealed class BSCharacter : BSPhysObject
750 public override float Buoyancy { 588 public override float Buoyancy {
751 get { return _buoyancy; } 589 get { return _buoyancy; }
752 set { _buoyancy = value; 590 set { _buoyancy = value;
753 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 591 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
754 { 592 {
755 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 593 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
756 ForceBuoyancy = _buoyancy; 594 ForceBuoyancy = _buoyancy;
@@ -759,8 +597,8 @@ public sealed class BSCharacter : BSPhysObject
759 } 597 }
760 public override float ForceBuoyancy { 598 public override float ForceBuoyancy {
761 get { return _buoyancy; } 599 get { return _buoyancy; }
762 set { 600 set {
763 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 601 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
764 602
765 _buoyancy = value; 603 _buoyancy = value;
766 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 604 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
@@ -768,7 +606,7 @@ public sealed class BSCharacter : BSPhysObject
768 float grav = BSParam.Gravity * (1f - _buoyancy); 606 float grav = BSParam.Gravity * (1f - _buoyancy);
769 Gravity = new OMV.Vector3(0f, 0f, grav); 607 Gravity = new OMV.Vector3(0f, 0f, grav);
770 if (PhysBody.HasPhysicalBody) 608 if (PhysBody.HasPhysicalBody)
771 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 609 PhysScene.PE.SetGravity(PhysBody, Gravity);
772 } 610 }
773 } 611 }
774 612
@@ -783,46 +621,25 @@ public sealed class BSCharacter : BSPhysObject
783 set { _PIDTau = value; } 621 set { _PIDTau = value; }
784 } 622 }
785 623
786 // Used for llSetHoverHeight and maybe vehicle height
787 // Hover Height will override MoveTo target's Z
788 public override bool PIDHoverActive {
789 set { _useHoverPID = value; }
790 }
791 public override float PIDHoverHeight {
792 set { _PIDHoverHeight = value; }
793 }
794 public override PIDHoverType PIDHoverType {
795 set { _PIDHoverType = value; }
796 }
797 public override float PIDHoverTau {
798 set { _PIDHoverTao = value; }
799 }
800
801 // For RotLookAt
802 public override OMV.Quaternion APIDTarget { set { return; } }
803 public override bool APIDActive { set { return; } }
804 public override float APIDStrength { set { return; } }
805 public override float APIDDamping { set { return; } }
806
807 public override void AddForce(OMV.Vector3 force, bool pushforce) 624 public override void AddForce(OMV.Vector3 force, bool pushforce)
808 { 625 {
809 // Since this force is being applied in only one step, make this a force per second. 626 // Since this force is being applied in only one step, make this a force per second.
810 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 627 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
811 AddForce(addForce, pushforce, false); 628 AddForce(addForce, pushforce, false);
812 } 629 }
813 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 630 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
814 if (force.IsFinite()) 631 if (force.IsFinite())
815 { 632 {
816 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 633 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
817 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 634 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
818 635
819 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 636 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
820 { 637 {
821 // Bullet adds this central force to the total force for this tick 638 // Bullet adds this central force to the total force for this tick
822 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 639 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
823 if (PhysBody.HasPhysicalBody) 640 if (PhysBody.HasPhysicalBody)
824 { 641 {
825 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 642 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
826 } 643 }
827 }); 644 });
828 } 645 }
@@ -833,7 +650,7 @@ public sealed class BSCharacter : BSPhysObject
833 } 650 }
834 } 651 }
835 652
836 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 653 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
837 } 654 }
838 public override void SetMomentum(OMV.Vector3 momentum) { 655 public override void SetMomentum(OMV.Vector3 momentum) {
839 } 656 }
@@ -841,14 +658,14 @@ public sealed class BSCharacter : BSPhysObject
841 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 658 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
842 { 659 {
843 OMV.Vector3 newScale; 660 OMV.Vector3 newScale;
844 661
845 // Bullet's capsule total height is the "passed height + radius * 2"; 662 // Bullet's capsule total height is the "passed height + radius * 2";
846 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 663 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
847 // The number we pass in for 'scaling' is the multiplier to get that base 664 // The number we pass in for 'scaling' is the multiplier to get that base
848 // shape to be the size desired. 665 // shape to be the size desired.
849 // So, when creating the scale for the avatar height, we take the passed height 666 // So, when creating the scale for the avatar height, we take the passed height
850 // (size.Z) and remove the caps. 667 // (size.Z) and remove the caps.
851 // Another oddity of the Bullet capsule implementation is that it presumes the Y 668 // An oddity of the Bullet capsule implementation is that it presumes the Y
852 // dimension is the radius of the capsule. Even though some of the code allows 669 // dimension is the radius of the capsule. Even though some of the code allows
853 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 670 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
854 671
@@ -856,12 +673,36 @@ public sealed class BSCharacter : BSPhysObject
856 newScale.X = size.X / 2f; 673 newScale.X = size.X / 2f;
857 newScale.Y = size.Y / 2f; 674 newScale.Y = size.Y / 2f;
858 675
676 float heightAdjust = BSParam.AvatarHeightMidFudge;
677 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
678 {
679 const float AVATAR_LOW = 1.1f;
680 const float AVATAR_MID = 1.775f; // 1.87f
681 const float AVATAR_HI = 2.45f;
682 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
683 float midHeightOffset = size.Z - AVATAR_MID;
684 if (midHeightOffset < 0f)
685 {
686 // Small avatar. Add the adjustment based on the distance from midheight
687 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
688 }
689 else
690 {
691 // Large avatar. Add the adjustment based on the distance from midheight
692 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
693 }
694 }
859 // The total scale height is the central cylindar plus the caps on the two ends. 695 // The total scale height is the central cylindar plus the caps on the two ends.
860 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 696 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
697 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
698
861 // If smaller than the endcaps, just fake like we're almost that small 699 // If smaller than the endcaps, just fake like we're almost that small
862 if (newScale.Z < 0) 700 if (newScale.Z < 0)
863 newScale.Z = 0.1f; 701 newScale.Z = 0.1f;
864 702
703 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
704 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
705
865 return newScale; 706 return newScale;
866 } 707 }
867 708
@@ -886,18 +727,18 @@ public sealed class BSCharacter : BSPhysObject
886 // the world that things have changed. 727 // the world that things have changed.
887 public override void UpdateProperties(EntityProperties entprop) 728 public override void UpdateProperties(EntityProperties entprop)
888 { 729 {
889 // Don't change position if standing on a stationary object. 730 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
890 if (!_isStationaryStanding) 731 TriggerPreUpdatePropertyAction(ref entprop);
891 _position = entprop.Position;
892 732
893 _orientation = entprop.Rotation; 733 RawPosition = entprop.Position;
734 RawOrientation = entprop.Rotation;
894 735
895 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar 736 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
896 // and will send agent updates to the clients if velocity changes by more than 737 // and will send agent updates to the clients if velocity changes by more than
897 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many 738 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
898 // extra updates. 739 // extra updates.
899 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) 740 if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
900 _velocity = entprop.Velocity; 741 RawVelocity = entprop.Velocity;
901 742
902 _acceleration = entprop.Acceleration; 743 _acceleration = entprop.Acceleration;
903 _rotationalVelocity = entprop.RotationalVelocity; 744 _rotationalVelocity = entprop.RotationalVelocity;
@@ -905,8 +746,8 @@ public sealed class BSCharacter : BSPhysObject
905 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 746 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
906 if (PositionSanityCheck(true)) 747 if (PositionSanityCheck(true))
907 { 748 {
908 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); 749 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
909 entprop.Position = _position; 750 entprop.Position = RawPosition;
910 } 751 }
911 752
912 // remember the current and last set values 753 // remember the current and last set values
@@ -917,10 +758,10 @@ public sealed class BSCharacter : BSPhysObject
917 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); 758 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
918 759
919 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 760 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
920 // base.RequestPhysicsterseUpdate(); 761 // PhysScene.PostUpdate(this);
921 762
922 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 763 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
923 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 764 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
924 } 765 }
925} 766}
926} 767}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 42b5c49..b47e9a8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -64,7 +64,7 @@ public abstract class BSConstraint : IDisposable
64 { 64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); 65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 BSScene.DetailLogZero, 67 m_body1.ID,
68 m_body1.ID, m_body1.AddrString, 68 m_body1.ID, m_body1.AddrString,
69 m_body2.ID, m_body2.AddrString, 69 m_body2.ID, m_body2.AddrString,
70 success); 70 success);
@@ -77,7 +77,10 @@ public abstract class BSConstraint : IDisposable
77 { 77 {
78 bool ret = false; 78 bool ret = false;
79 if (m_enabled) 79 if (m_enabled)
80 {
81 m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); 82 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
83 }
81 return ret; 84 return ret;
82 } 85 }
83 86
@@ -86,6 +89,7 @@ public abstract class BSConstraint : IDisposable
86 bool ret = false; 89 bool ret = false;
87 if (m_enabled) 90 if (m_enabled)
88 { 91 {
92 m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
89 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); 93 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
90 } 94 }
91 return ret; 95 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index d0949f5..7fcb75c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -32,12 +32,19 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public sealed class BSConstraint6Dof : BSConstraint 35public class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38 38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
42 {
43 m_body1 = obj1;
44 m_body2 = obj2;
45 m_enabled = false;
46 }
47
41 // Create a btGeneric6DofConstraint 48 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, 49 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 50 Vector3 frame1, Quaternion frame1rot,
@@ -52,9 +59,11 @@ public sealed class BSConstraint6Dof : BSConstraint
52 frame2, frame2rot, 59 frame2, frame2rot,
53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 60 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 m_enabled = true; 61 m_enabled = true;
55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 62 PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
56 BSScene.DetailLogZero, world.worldID, 63 m_body1.ID, world.worldID,
57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 64 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
65 PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
66 m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
58 } 67 }
59 68
60 // 6 Dof constraint based on a midpoint between the two constrained bodies 69 // 6 Dof constraint based on a midpoint between the two constrained bodies
@@ -79,9 +88,11 @@ public sealed class BSConstraint6Dof : BSConstraint
79 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, 88 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
80 joinPoint, 89 joinPoint,
81 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 90 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
91
82 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 92 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
83 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, 93 m_body1.ID, world.worldID, m_constraint.AddrString,
84 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 94 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
95
85 if (!m_constraint.HasPhysicalConstraint) 96 if (!m_constraint.HasPhysicalConstraint)
86 { 97 {
87 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 98 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
@@ -106,8 +117,10 @@ public sealed class BSConstraint6Dof : BSConstraint
106 frameInBloc, frameInBrot, 117 frameInBloc, frameInBrot,
107 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); 118 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
108 m_enabled = true; 119 m_enabled = true;
109 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", 120 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
110 BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); 121 m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
122 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
123 m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
111 } 124 }
112 125
113 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 126 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs
new file mode 100755
index 0000000..7a76a9a
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintConeTwist.cs
@@ -0,0 +1,54 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintConeTwist : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
38
39 public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52}
53
54}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index 7714a03..ed89f63 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -45,7 +45,7 @@ public sealed class BSConstraintHinge : BSConstraint
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2, 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 pivotInA, pivotInB, axisInA, axisInB, 48 pivotInA, pivotInB, axisInA, axisInB,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true; 50 m_enabled = true;
51 } 51 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs
new file mode 100755
index 0000000..37cfa07
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSlider.cs
@@ -0,0 +1,55 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintSlider : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52
53}
54
55}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs
new file mode 100755
index 0000000..8e7ddff
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintSpring.cs
@@ -0,0 +1,103 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34
35public sealed class BSConstraintSpring : BSConstraint6Dof
36{
37 public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frame1Loc, Quaternion frame1Rot,
41 Vector3 frame2Loc, Quaternion frame2Rot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 :base(world, obj1, obj2)
44 {
45 m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
46 frame1Loc, frame1Rot, frame2Loc, frame2Rot,
47 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
48 m_enabled = true;
49
50 PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
51 obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
52 PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
53 m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 }
55
56 public bool SetAxisEnable(int pIndex, bool pAxisEnable)
57 {
58 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
59 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
60 PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
61 return true;
62 }
63
64 public bool SetStiffness(int pIndex, float pStiffness)
65 {
66 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
67 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
68 PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
69 return true;
70 }
71
72 public bool SetDamping(int pIndex, float pDamping)
73 {
74 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
75 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
76 PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
77 return true;
78 }
79
80 public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
81 {
82 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
83 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
84 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
85 return true;
86 }
87
88 public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
89 {
90 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
91 m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
92 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
93 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
94 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
95 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
96 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
97 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
98 return true;
99 }
100
101}
102
103} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 0fd1f73..7b98f9d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 private static string LogHeader = "[BULLETSIM VEHICLE]"; 45 private static string LogHeader = "[BULLETSIM VEHICLE]";
46 46
47 // the prim this dynamic controller belongs to 47 // the prim this dynamic controller belongs to
48 private BSPrim ControllingPrim { get; set; } 48 private BSPrimLinkable ControllingPrim { get; set; }
49 49
50 private bool m_haveRegisteredForSceneEvents; 50 private bool m_haveRegisteredForSceneEvents;
51 51
@@ -125,33 +125,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
125 static readonly float PIOverFour = ((float)Math.PI) / 4f; 125 static readonly float PIOverFour = ((float)Math.PI) / 4f;
126 static readonly float PIOverTwo = ((float)Math.PI) / 2f; 126 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
127 127
128 // For debugging, flags to turn on and off individual corrections.
129 public bool enableAngularVerticalAttraction;
130 public bool enableAngularDeflection;
131 public bool enableAngularBanking;
132
133 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) 128 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
134 : base(myScene, myPrim, actorName) 129 : base(myScene, myPrim, actorName)
135 { 130 {
136 ControllingPrim = myPrim;
137 Type = Vehicle.TYPE_NONE; 131 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false; 132 m_haveRegisteredForSceneEvents = false;
139 SetupVehicleDebugging();
140 }
141 133
142 // Stopgap debugging enablement. Allows source level debugging but still checking 134 ControllingPrim = myPrim as BSPrimLinkable;
143 // in changes by making enablement of debugging flags from INI file. 135 if (ControllingPrim == null)
144 public void SetupVehicleDebugging()
145 {
146 enableAngularVerticalAttraction = true;
147 enableAngularDeflection = false;
148 enableAngularBanking = true;
149 if (BSParam.VehicleDebuggingEnabled)
150 { 136 {
151 enableAngularVerticalAttraction = true; 137 // THIS CANNOT HAPPEN!!
152 enableAngularDeflection = false;
153 enableAngularBanking = false;
154 } 138 }
139 VDetailLog("{0},Creation", ControllingPrim.LocalID);
155 } 140 }
156 141
157 // Return 'true' if this vehicle is doing vehicle things 142 // Return 'true' if this vehicle is doing vehicle things
@@ -173,7 +158,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
173 switch (pParam) 158 switch (pParam)
174 { 159 {
175 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 160 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
176 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 161 m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
177 break; 162 break;
178 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 163 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
179 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 164 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
@@ -209,7 +194,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
209 m_VhoverTimescale = Math.Max(pValue, 0.01f); 194 m_VhoverTimescale = Math.Max(pValue, 0.01f);
210 break; 195 break;
211 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 196 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
212 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 197 m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
213 break; 198 break;
214 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 199 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
215 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 200 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
@@ -235,7 +220,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
235 // set all of the components to the same value 220 // set all of the components to the same value
236 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 221 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
237 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 222 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
238 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
239 break; 223 break;
240 case Vehicle.ANGULAR_MOTOR_DIRECTION: 224 case Vehicle.ANGULAR_MOTOR_DIRECTION:
241 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 225 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
@@ -244,7 +228,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
244 break; 228 break;
245 case Vehicle.LINEAR_FRICTION_TIMESCALE: 229 case Vehicle.LINEAR_FRICTION_TIMESCALE:
246 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 230 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
247 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
248 break; 231 break;
249 case Vehicle.LINEAR_MOTOR_DIRECTION: 232 case Vehicle.LINEAR_MOTOR_DIRECTION:
250 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 233 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
@@ -265,7 +248,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 { 248 {
266 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 249 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
267 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 250 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
268 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
269 break; 251 break;
270 case Vehicle.ANGULAR_MOTOR_DIRECTION: 252 case Vehicle.ANGULAR_MOTOR_DIRECTION:
271 // Limit requested angular speed to 2 rps= 4 pi rads/sec 253 // Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -278,7 +260,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
278 break; 260 break;
279 case Vehicle.LINEAR_FRICTION_TIMESCALE: 261 case Vehicle.LINEAR_FRICTION_TIMESCALE:
280 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 262 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
281 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
282 break; 263 break;
283 case Vehicle.LINEAR_MOTOR_DIRECTION: 264 case Vehicle.LINEAR_MOTOR_DIRECTION:
284 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -559,25 +540,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
559 break; 540 break;
560 } 541 }
561 542
562 // Update any physical parameters based on this type. 543 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
563 Refresh(); 544 // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
564
565 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
566 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
567 1f);
568 m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
569 545
570 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 546 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
571 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 547 // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
572 1f);
573 m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
574 548
575 /* Not implemented 549 /* Not implemented
576 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, 550 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
577 BSMotor.Infinite, BSMotor.InfiniteVector, 551 BSMotor.Infinite, BSMotor.InfiniteVector,
578 m_verticalAttractionEfficiency); 552 m_verticalAttractionEfficiency);
579 // Z goes away and we keep X and Y 553 // Z goes away and we keep X and Y
580 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
581 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 554 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
582 */ 555 */
583 556
@@ -589,6 +562,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
589 { 562 {
590 RegisterForSceneEvents(); 563 RegisterForSceneEvents();
591 } 564 }
565
566 // Update any physical parameters based on this type.
567 Refresh();
592 } 568 }
593 #endregion // Vehicle parameter setting 569 #endregion // Vehicle parameter setting
594 570
@@ -596,6 +572,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
596 public override void Refresh() 572 public override void Refresh()
597 { 573 {
598 // If asking for a refresh, reset the physical parameters before the next simulation step. 574 // If asking for a refresh, reset the physical parameters before the next simulation step.
575 // Called whether active or not since the active state may be updated before the next step.
599 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() 576 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
600 { 577 {
601 SetPhysicalParameters(); 578 SetPhysicalParameters();
@@ -612,8 +589,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
612 m_vehicleMass = ControllingPrim.TotalMass; 589 m_vehicleMass = ControllingPrim.TotalMass;
613 590
614 // Friction affects are handled by this vehicle code 591 // Friction affects are handled by this vehicle code
615 m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); 592 // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
616 m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); 593 // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
594 ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
595 ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
617 596
618 // Moderate angular movement introduced by Bullet. 597 // Moderate angular movement introduced by Bullet.
619 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 598 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
@@ -623,17 +602,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
623 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); 602 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
624 603
625 // Vehicles report collision events so we know when it's on the ground 604 // Vehicles report collision events so we know when it's on the ground
626 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 605 // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
606 ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
627 607
628 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape, m_vehicleMass); 608 // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
629 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); 609 // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
630 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); 610 // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
611 // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
612 ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
631 613
632 // Set the gravity for the vehicle depending on the buoyancy 614 // Set the gravity for the vehicle depending on the buoyancy
633 // TODO: what should be done if prim and vehicle buoyancy differ? 615 // TODO: what should be done if prim and vehicle buoyancy differ?
634 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); 616 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
635 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. 617 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
636 m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); 618 // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
619 ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
637 620
638 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", 621 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
639 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, 622 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
@@ -645,11 +628,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
645 { 628 {
646 if (ControllingPrim.PhysBody.HasPhysicalBody) 629 if (ControllingPrim.PhysBody.HasPhysicalBody)
647 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 630 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
631 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
648 } 632 }
649 } 633 }
650 634
651 // BSActor.RemoveBodyDependencies 635 // BSActor.RemoveBodyDependencies
652 public override void RemoveBodyDependencies() 636 public override void RemoveDependencies()
653 { 637 {
654 Refresh(); 638 Refresh();
655 } 639 }
@@ -657,6 +641,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
657 // BSActor.Release() 641 // BSActor.Release()
658 public override void Dispose() 642 public override void Dispose()
659 { 643 {
644 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
660 UnregisterForSceneEvents(); 645 UnregisterForSceneEvents();
661 Type = Vehicle.TYPE_NONE; 646 Type = Vehicle.TYPE_NONE;
662 Enabled = false; 647 Enabled = false;
@@ -714,7 +699,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
714 private Vector3 m_knownRotationalVelocity; 699 private Vector3 m_knownRotationalVelocity;
715 private Vector3 m_knownRotationalForce; 700 private Vector3 m_knownRotationalForce;
716 private Vector3 m_knownRotationalImpulse; 701 private Vector3 m_knownRotationalImpulse;
717 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
718 702
719 private const int m_knownChangedPosition = 1 << 0; 703 private const int m_knownChangedPosition = 1 << 0;
720 private const int m_knownChangedVelocity = 1 << 1; 704 private const int m_knownChangedVelocity = 1 << 1;
@@ -726,7 +710,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
726 private const int m_knownChangedRotationalImpulse = 1 << 7; 710 private const int m_knownChangedRotationalImpulse = 1 << 7;
727 private const int m_knownChangedTerrainHeight = 1 << 8; 711 private const int m_knownChangedTerrainHeight = 1 << 8;
728 private const int m_knownChangedWaterLevel = 1 << 9; 712 private const int m_knownChangedWaterLevel = 1 << 9;
729 private const int m_knownChangedForwardVelocity = 1 <<10;
730 713
731 public void ForgetKnownVehicleProperties() 714 public void ForgetKnownVehicleProperties()
732 { 715 {
@@ -783,13 +766,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
783 766
784 // Since the computation of terrain height can be a little involved, this routine 767 // Since the computation of terrain height can be a little involved, this routine
785 // is used to fetch the height only once for each vehicle simulation step. 768 // is used to fetch the height only once for each vehicle simulation step.
786 Vector3 lastRememberedHeightPos; 769 Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
787 private float GetTerrainHeight(Vector3 pos) 770 private float GetTerrainHeight(Vector3 pos)
788 { 771 {
789 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) 772 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
790 { 773 {
791 lastRememberedHeightPos = pos; 774 lastRememberedHeightPos = pos;
792 m_knownTerrainHeight = ControllingPrim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 775 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
793 m_knownHas |= m_knownChangedTerrainHeight; 776 m_knownHas |= m_knownChangedTerrainHeight;
794 } 777 }
795 return m_knownTerrainHeight; 778 return m_knownTerrainHeight;
@@ -797,14 +780,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
797 780
798 // Since the computation of water level can be a little involved, this routine 781 // Since the computation of water level can be a little involved, this routine
799 // is used ot fetch the level only once for each vehicle simulation step. 782 // is used ot fetch the level only once for each vehicle simulation step.
783 Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
800 private float GetWaterLevel(Vector3 pos) 784 private float GetWaterLevel(Vector3 pos)
801 { 785 {
802 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 786 if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
803 { 787 {
804 m_knownWaterLevel = ControllingPrim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 788 lastRememberedWaterHeightPos = pos;
789 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
805 m_knownHas |= m_knownChangedWaterLevel; 790 m_knownHas |= m_knownChangedWaterLevel;
806 } 791 }
807 return (float)m_knownWaterLevel; 792 return m_knownWaterLevel;
808 } 793 }
809 794
810 private Vector3 VehiclePosition 795 private Vector3 VehiclePosition
@@ -930,14 +915,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
930 { 915 {
931 get 916 get
932 { 917 {
933 if ((m_knownHas & m_knownChangedForwardVelocity) == 0) 918 return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
934 {
935 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
936 m_knownHas |= m_knownChangedForwardVelocity;
937 }
938 return m_knownForwardVelocity;
939 } 919 }
940 } 920 }
921
941 private float VehicleForwardSpeed 922 private float VehicleForwardSpeed
942 { 923 {
943 get 924 get
@@ -988,6 +969,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
988 { 969 {
989 ComputeLinearVelocity(pTimestep); 970 ComputeLinearVelocity(pTimestep);
990 971
972 ComputeLinearDeflection(pTimestep);
973
991 ComputeLinearTerrainHeightCorrection(pTimestep); 974 ComputeLinearTerrainHeightCorrection(pTimestep);
992 975
993 ComputeLinearHover(pTimestep); 976 ComputeLinearHover(pTimestep);
@@ -1003,11 +986,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1003 { 986 {
1004 Vector3 vel = VehicleVelocity; 987 Vector3 vel = VehicleVelocity;
1005 if ((m_flags & (VehicleFlag.NO_X)) != 0) 988 if ((m_flags & (VehicleFlag.NO_X)) != 0)
989 {
1006 vel.X = 0; 990 vel.X = 0;
991 }
1007 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 992 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
993 {
1008 vel.Y = 0; 994 vel.Y = 0;
995 }
1009 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 996 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
997 {
1010 vel.Z = 0; 998 vel.Z = 0;
999 }
1011 VehicleVelocity = vel; 1000 VehicleVelocity = vel;
1012 } 1001 }
1013 1002
@@ -1019,13 +1008,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1019 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG 1008 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1020 VehicleVelocity /= VehicleVelocity.Length(); 1009 VehicleVelocity /= VehicleVelocity.Length();
1021 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; 1010 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1022 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", 1011 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1023 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); 1012 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1024 } 1013 }
1025 else if (newVelocityLengthSq < 0.001f) 1014 else if (newVelocityLengthSq < 0.001f)
1026 VehicleVelocity = Vector3.Zero; 1015 VehicleVelocity = Vector3.Zero;
1027 1016
1028 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); 1017 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
1029 1018
1030 } // end MoveLinear() 1019 } // end MoveLinear()
1031 1020
@@ -1033,9 +1022,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1033 { 1022 {
1034 // Step the motor from the current value. Get the correction needed this step. 1023 // Step the motor from the current value. Get the correction needed this step.
1035 Vector3 origVelW = VehicleVelocity; // DEBUG 1024 Vector3 origVelW = VehicleVelocity; // DEBUG
1036 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); 1025 Vector3 currentVelV = VehicleForwardVelocity;
1037 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); 1026 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1038 1027
1028 // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
1029 Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1030 linearMotorCorrectionV -= (currentVelV * frictionFactorV);
1031
1039 // Motor is vehicle coordinates. Rotate it to world coordinates 1032 // Motor is vehicle coordinates. Rotate it to world coordinates
1040 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; 1033 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
1041 1034
@@ -1049,8 +1042,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1049 // Add this correction to the velocity to make it faster/slower. 1042 // Add this correction to the velocity to make it faster/slower.
1050 VehicleVelocity += linearMotorVelocityW; 1043 VehicleVelocity += linearMotorVelocityW;
1051 1044
1052 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", 1045 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1053 ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); 1046 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1047 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1048 }
1049
1050 //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
1051 //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
1052 private void ComputeLinearDeflection(float pTimestep)
1053 {
1054 Vector3 linearDeflectionV = Vector3.Zero;
1055 Vector3 velocityV = VehicleForwardVelocity;
1056
1057 if (BSParam.VehicleEnableLinearDeflection)
1058 {
1059 // Velocity in Y and Z dimensions is movement to the side or turning.
1060 // Compute deflection factor from the to the side and rotational velocity
1061 linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
1062 linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
1063
1064 // Velocity to the side and around is corrected and moved into the forward direction
1065 linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
1066 linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
1067
1068 // Scale the deflection to the fractional simulation time
1069 linearDeflectionV *= pTimestep;
1070
1071 // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
1072 linearDeflectionV *= new Vector3(1, -1, -1);
1073
1074 // Correction is vehicle relative. Convert to world coordinates.
1075 Vector3 linearDeflectionW = linearDeflectionV * VehicleOrientation;
1076
1077 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1078 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1079 {
1080 linearDeflectionW.Z = 0f;
1081 }
1082
1083 VehicleVelocity += linearDeflectionW;
1084
1085 VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
1086 ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
1087 }
1054 } 1088 }
1055 1089
1056 public void ComputeLinearTerrainHeightCorrection(float pTimestep) 1090 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
@@ -1087,14 +1121,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1087 { 1121 {
1088 m_VhoverTargetHeight = m_VhoverHeight; 1122 m_VhoverTargetHeight = m_VhoverHeight;
1089 } 1123 }
1090
1091 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1124 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
1092 { 1125 {
1093 // If body is already heigher, use its height as target height 1126 // If body is already heigher, use its height as target height
1094 if (VehiclePosition.Z > m_VhoverTargetHeight) 1127 if (VehiclePosition.Z > m_VhoverTargetHeight)
1128 {
1095 m_VhoverTargetHeight = VehiclePosition.Z; 1129 m_VhoverTargetHeight = VehiclePosition.Z;
1130
1131 // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
1132 // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
1133 // scripts that it could not be changed.
1134 // So, if above the height, reapply gravity if buoyancy had it turned off.
1135 if (m_VehicleBuoyancy != 0)
1136 {
1137 Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
1138 VehicleAddForce(appliedGravity);
1139 }
1140 }
1096 } 1141 }
1097 1142
1098 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1143 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
1099 { 1144 {
1100 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1145 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -1136,7 +1181,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1136 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, 1181 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1137 verticalError, verticalCorrection); 1182 verticalError, verticalCorrection);
1138 } 1183 }
1139
1140 } 1184 }
1141 } 1185 }
1142 1186
@@ -1188,7 +1232,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1188 // used with conjunction with banking: the strength of the banking will decay when the 1232 // used with conjunction with banking: the strength of the banking will decay when the
1189 // vehicle no longer experiences collisions. The decay timescale is the same as 1233 // vehicle no longer experiences collisions. The decay timescale is the same as
1190 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1234 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1191 // when they are in mid jump. 1235 // when they are in mid jump.
1192 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1236 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1193 // This is just using the ground and a general collision check. Should really be using 1237 // This is just using the ground and a general collision check. Should really be using
1194 // a downward raycast to find what is below. 1238 // a downward raycast to find what is below.
@@ -1201,7 +1245,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1201 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); 1245 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1202 distanceAboveGround = VehiclePosition.Z - targetHeight; 1246 distanceAboveGround = VehiclePosition.Z - targetHeight;
1203 // Not colliding if the vehicle is off the ground 1247 // Not colliding if the vehicle is off the ground
1204 if (!Prim.IsColliding) 1248 if (!Prim.HasSomeCollision)
1205 { 1249 {
1206 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1250 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1207 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); 1251 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
@@ -1212,12 +1256,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1212 // be computed with a motor. 1256 // be computed with a motor.
1213 // TODO: add interaction with banking. 1257 // TODO: add interaction with banking.
1214 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", 1258 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1215 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); 1259 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1216 */ 1260 */
1217 1261
1218 // Another approach is to measure if we're going up. If going up and not colliding, 1262 // Another approach is to measure if we're going up. If going up and not colliding,
1219 // the vehicle is in the air. Fix that by pushing down. 1263 // the vehicle is in the air. Fix that by pushing down.
1220 if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) 1264 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1221 { 1265 {
1222 // Get rid of any of the velocity vector that is pushing us up. 1266 // Get rid of any of the velocity vector that is pushing us up.
1223 float upVelocity = VehicleVelocity.Z; 1267 float upVelocity = VehicleVelocity.Z;
@@ -1239,7 +1283,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1239 } 1283 }
1240 */ 1284 */
1241 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", 1285 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1242 ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); 1286 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1243 } 1287 }
1244 } 1288 }
1245 } 1289 }
@@ -1249,14 +1293,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1249 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; 1293 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1250 1294
1251 // Hack to reduce downward force if the vehicle is probably sitting on the ground 1295 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1252 if (ControllingPrim.IsColliding && IsGroundVehicle) 1296 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1253 appliedGravity *= BSParam.VehicleGroundGravityFudge; 1297 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1254 1298
1255 VehicleAddForce(appliedGravity); 1299 VehicleAddForce(appliedGravity);
1256 1300
1257 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", 1301 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1258 ControllingPrim.LocalID, m_VehicleGravity, 1302 ControllingPrim.LocalID, m_VehicleGravity,
1259 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); 1303 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1260 } 1304 }
1261 1305
1262 // ======================================================================= 1306 // =======================================================================
@@ -1323,6 +1367,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1323 private void ComputeAngularTurning(float pTimestep) 1367 private void ComputeAngularTurning(float pTimestep)
1324 { 1368 {
1325 // The user wants this many radians per second angular change? 1369 // The user wants this many radians per second angular change?
1370 Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
1326 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); 1371 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1327 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); 1372 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1328 1373
@@ -1330,18 +1375,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1330 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : 1375 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1331 // This flag prevents linear deflection parallel to world z-axis. This is useful 1376 // This flag prevents linear deflection parallel to world z-axis. This is useful
1332 // for preventing ground vehicles with large linear deflection, like bumper cars, 1377 // for preventing ground vehicles with large linear deflection, like bumper cars,
1333 // from climbing their linear deflection into the sky. 1378 // from climbing their linear deflection into the sky.
1334 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement 1379 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1335 // TODO: This is here because this is where ODE put it but documentation says it 1380 // TODO: This is here because this is where ODE put it but documentation says it
1336 // is a linear effect. Where should this check go? 1381 // is a linear effect. Where should this check go?
1337 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1382 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1338 // { 1383 // {
1339 // angularMotorContributionV.X = 0f; 1384 // angularMotorContributionV.X = 0f;
1340 // angularMotorContributionV.Y = 0f; 1385 // angularMotorContributionV.Y = 0f;
1341 // } 1386 // }
1387
1388 // Reduce any velocity by friction.
1389 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1390 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1391
1392 Vector3 angularMotorContributionW = angularMotorContributionV * VehicleOrientation;
1393 VehicleRotationalVelocity += angularMotorContributionW;
1342 1394
1343 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; 1395 VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
1344 VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", ControllingPrim.LocalID, angularMotorContributionV); 1396 ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
1345 } 1397 }
1346 1398
1347 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1399 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
@@ -1356,86 +1408,136 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1356 { 1408 {
1357 1409
1358 // If vertical attaction timescale is reasonable 1410 // If vertical attaction timescale is reasonable
1359 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1411 if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1360 { 1412 {
1361 // Possible solution derived from a discussion at: 1413 Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleOrientation;
1362 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no 1414 switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
1363
1364 // Create a rotation that is only the vehicle's rotation around Z
1365 Vector3 currentEuler = Vector3.Zero;
1366 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1367 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1368
1369 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1370 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1371 // Compute the angle between those to vectors.
1372 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1373 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1374
1375 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1376 // TODO: add 'efficiency'.
1377 differenceAngle /= m_verticalAttractionTimescale;
1378
1379 // Create the quaterian representing the correction angle
1380 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1381
1382 // Turn that quaternion into Euler values to make it into velocities to apply.
1383 Vector3 vertContributionV = Vector3.Zero;
1384 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1385 vertContributionV *= -1f;
1386
1387 VehicleRotationalVelocity += vertContributionV;
1388
1389 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1390 ControllingPrim.LocalID,
1391 differenceAxis,
1392 differenceAngle,
1393 correctionRotation,
1394 vertContributionV);
1395
1396 // ===================================================================
1397 /*
1398 Vector3 vertContributionV = Vector3.Zero;
1399 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1400
1401 // Take a vector pointing up and convert it from world to vehicle relative coords.
1402 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1403
1404 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1405 // is now:
1406 // leaning to one side: rotated around the X axis with the Y value going
1407 // from zero (nearly straight up) to one (completely to the side)) or
1408 // leaning front-to-back: rotated around the Y axis with the value of X being between
1409 // zero and one.
1410 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1411
1412 // Y error means needed rotation around X axis and visa versa.
1413 // Since the error goes from zero to one, the asin is the corresponding angle.
1414 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1415 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1416 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1417
1418 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1419 if (verticalError.Z < 0f)
1420 { 1415 {
1421 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; 1416 case 0:
1422 // vertContribution.Y -= PIOverFour; 1417 {
1418 //Another formula to try got from :
1419 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1420
1421 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1422 // since only computing half the distance between the angles.
1423 float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1424
1425 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1426 // this makes for a smoother adjustment and less fighting between the various forces.
1427 Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1428
1429 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1430 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1431
1432 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1433 Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
1434
1435 VehicleRotationalVelocity += vertContributionV;
1436
1437 VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
1438 ControllingPrim.LocalID,
1439 verticalAttractionSpeed,
1440 vehicleUpAxis,
1441 predictedUp,
1442 torqueVector,
1443 vertContributionV);
1444 break;
1445 }
1446 case 1:
1447 {
1448 // Possible solution derived from a discussion at:
1449 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1450
1451 // Create a rotation that is only the vehicle's rotation around Z
1452 Vector3 currentEulerW = Vector3.Zero;
1453 VehicleOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
1454 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
1455
1456 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1457 Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1458 // Compute the angle between those to vectors.
1459 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1460 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1461
1462 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1463 // TODO: add 'efficiency'.
1464 // differenceAngle /= m_verticalAttractionTimescale;
1465
1466 // Create the quaterian representing the correction angle
1467 Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
1468
1469 // Turn that quaternion into Euler values to make it into velocities to apply.
1470 Vector3 vertContributionW = Vector3.Zero;
1471 correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
1472 vertContributionW *= -1f;
1473 vertContributionW /= m_verticalAttractionTimescale;
1474
1475 VehicleRotationalVelocity += vertContributionW;
1476
1477 VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
1478 ControllingPrim.LocalID,
1479 vehicleUpAxis,
1480 differenceAxisW,
1481 differenceAngle,
1482 correctionRotationW,
1483 vertContributionW);
1484 break;
1485 }
1486 case 2:
1487 {
1488 Vector3 vertContributionV = Vector3.Zero;
1489 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1490
1491 // Take a vector pointing up and convert it from world to vehicle relative coords.
1492 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1493
1494 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1495 // is now:
1496 // leaning to one side: rotated around the X axis with the Y value going
1497 // from zero (nearly straight up) to one (completely to the side)) or
1498 // leaning front-to-back: rotated around the Y axis with the value of X being between
1499 // zero and one.
1500 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1501
1502 // Y error means needed rotation around X axis and visa versa.
1503 // Since the error goes from zero to one, the asin is the corresponding angle.
1504 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1505 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1506 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1507
1508 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1509 if (verticalError.Z < 0f)
1510 {
1511 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1512 // vertContribution.Y -= PIOverFour;
1513 }
1514
1515 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1516 // Correction happens over a number of seconds.
1517 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1518
1519 // The correction happens over the user's time period
1520 vertContributionV /= m_verticalAttractionTimescale;
1521
1522 // Rotate the vehicle rotation to the world coordinates.
1523 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1524
1525 VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
1526 ControllingPrim.LocalID,
1527 vehicleUpAxis,
1528 origRotVelW,
1529 verticalError,
1530 unscaledContribVerticalErrorV,
1531 m_verticalAttractionEfficiency,
1532 m_verticalAttractionTimescale,
1533 vertContributionV);
1534 break;
1535 }
1536 default:
1537 {
1538 break;
1539 }
1423 } 1540 }
1424
1425 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1426 // Correction happens over a number of seconds.
1427 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1428
1429 // The correction happens over the user's time period
1430 vertContributionV /= m_verticalAttractionTimescale;
1431
1432 // Rotate the vehicle rotation to the world coordinates.
1433 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1434
1435 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1436 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1437 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1438 */
1439 } 1541 }
1440 } 1542 }
1441 1543
@@ -1445,13 +1547,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1445 // in that direction. 1547 // in that direction.
1446 // TODO: implement reference frame. 1548 // TODO: implement reference frame.
1447 public void ComputeAngularDeflection() 1549 public void ComputeAngularDeflection()
1448 { 1550 {
1449 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1450 // approximately the same X or Y correction. When added together (when contributions are combined)
1451 // this creates an over-correction and then wabbling as the target is overshot.
1452 // TODO: rethink how the different correction computations inter-relate.
1453 1551
1454 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) 1552 if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1455 { 1553 {
1456 Vector3 deflectContributionV = Vector3.Zero; 1554 Vector3 deflectContributionV = Vector3.Zero;
1457 1555
@@ -1464,10 +1562,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1464 1562
1465 // The direction the vehicle is pointing 1563 // The direction the vehicle is pointing
1466 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; 1564 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1467 pointingDirection.Normalize(); 1565 //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
1566 // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
1567 Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1568 predictedPointingDirection.Normalize();
1468 1569
1469 // The difference between what is and what should be. 1570 // The difference between what is and what should be.
1470 Vector3 deflectionError = movingDirection - pointingDirection; 1571 // Vector3 deflectionError = movingDirection - predictedPointingDirection;
1572 Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
1471 1573
1472 // Don't try to correct very large errors (not our job) 1574 // Don't try to correct very large errors (not our job)
1473 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); 1575 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
@@ -1480,15 +1582,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1480 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); 1582 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1481 1583
1482 // Scale the correction by recovery timescale and efficiency 1584 // Scale the correction by recovery timescale and efficiency
1483 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; 1585 // Not modeling a spring so clamp the scale to no more then the arc
1484 deflectContributionV /= m_angularDeflectionTimescale; 1586 deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
1485 1587 //deflectContributionV /= m_angularDeflectionTimescale;
1486 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1487 1588
1589 // VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1590 VehicleRotationalVelocity += deflectContributionV;
1488 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1591 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1489 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); 1592 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1490 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1593 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
1491 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1594 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
1492 } 1595 }
1493 } 1596 }
1494 1597
@@ -1500,13 +1603,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1500 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1603 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1501 // of the yaw effect will be proportional to the 1604 // of the yaw effect will be proportional to the
1502 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1605 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1503 // velocity along its preferred axis of motion. 1606 // velocity along its preferred axis of motion.
1504 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1607 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1505 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1608 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1506 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1609 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1507 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1610 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1508 // Negating the banking coefficient will make it so that the vehicle leans to the 1611 // Negating the banking coefficient will make it so that the vehicle leans to the
1509 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1612 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1510 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1613 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1511 // banking vehicles do what you want rather than what the laws of physics allow. 1614 // banking vehicles do what you want rather than what the laws of physics allow.
1512 // For example, consider a real motorcycle...it must be moving forward in order for 1615 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1518,14 +1621,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1518 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1621 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1519 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1622 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1520 // to "dynamic" where the banking is also proportional to its velocity along its 1623 // to "dynamic" where the banking is also proportional to its velocity along its
1521 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1624 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1522 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1625 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1523 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1626 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1524 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1627 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1525 // make a sluggish vehicle by giving it a timescale of several seconds. 1628 // make a sluggish vehicle by giving it a timescale of several seconds.
1526 public void ComputeAngularBanking() 1629 public void ComputeAngularBanking()
1527 { 1630 {
1528 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1631 if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1529 { 1632 {
1530 Vector3 bankingContributionV = Vector3.Zero; 1633 Vector3 bankingContributionV = Vector3.Zero;
1531 1634
@@ -1551,7 +1654,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1551 1654
1552 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; 1655 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1553 VehicleRotationalVelocity += bankingContributionV; 1656 VehicleRotationalVelocity += bankingContributionV;
1554 1657
1555 1658
1556 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", 1659 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1557 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); 1660 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
@@ -1598,6 +1701,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1598 1701
1599 } 1702 }
1600 1703
1704 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1705 // some value by to apply this friction.
1706 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1707 {
1708 Vector3 frictionFactor = Vector3.Zero;
1709 if (friction != BSMotor.InfiniteVector)
1710 {
1711 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1712 // Individual friction components can be 'infinite' so compute each separately.
1713 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1714 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1715 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1716 frictionFactor *= pTimestep;
1717 }
1718 return frictionFactor;
1719 }
1720
1721 private float SortedClampInRange(float clampa, float val, float clampb)
1722 {
1723 if (clampa > clampb)
1724 {
1725 float temp = clampa;
1726 clampa = clampb;
1727 clampb = temp;
1728 }
1729 return ClampInRange(clampa, val, clampb);
1730
1731 }
1732
1601 private float ClampInRange(float low, float val, float high) 1733 private float ClampInRange(float low, float val, float high)
1602 { 1734 {
1603 return Math.Max(low, Math.Min(val, high)); 1735 return Math.Max(low, Math.Min(val, high));
@@ -1607,8 +1739,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1607 // Invoke the detailed logger and output something if it's enabled. 1739 // Invoke the detailed logger and output something if it's enabled.
1608 private void VDetailLog(string msg, params Object[] args) 1740 private void VDetailLog(string msg, params Object[] args)
1609 { 1741 {
1610 if (ControllingPrim.PhysicsScene.VehicleLoggingEnabled) 1742 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1611 ControllingPrim.PhysicsScene.DetailLog(msg, args); 1743 ControllingPrim.PhysScene.DetailLog(msg, args);
1612 } 1744 }
1613 } 1745 }
1614} 1746}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 4ece1eb..77f69a5 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -33,14 +33,6 @@ using OMV = OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
44public abstract class BSLinkset 36public abstract class BSLinkset
45{ 37{
46 // private static string LogHeader = "[BULLETSIM LINKSET]"; 38 // private static string LogHeader = "[BULLETSIM LINKSET]";
@@ -56,15 +48,15 @@ public abstract class BSLinkset
56 { 48 {
57 BSLinkset ret = null; 49 BSLinkset ret = null;
58 50
59 switch ((int)BSParam.LinksetImplementation) 51 switch (parent.LinksetType)
60 { 52 {
61 case (int)LinksetImplementation.Constraint: 53 case LinksetImplementation.Constraint:
62 ret = new BSLinksetConstraints(physScene, parent); 54 ret = new BSLinksetConstraints(physScene, parent);
63 break; 55 break;
64 case (int)LinksetImplementation.Compound: 56 case LinksetImplementation.Compound:
65 ret = new BSLinksetCompound(physScene, parent); 57 ret = new BSLinksetCompound(physScene, parent);
66 break; 58 break;
67 case (int)LinksetImplementation.Manual: 59 case LinksetImplementation.Manual:
68 // ret = new BSLinksetManual(physScene, parent); 60 // ret = new BSLinksetManual(physScene, parent);
69 break; 61 break;
70 default: 62 default:
@@ -78,28 +70,37 @@ public abstract class BSLinkset
78 return ret; 70 return ret;
79 } 71 }
80 72
73 public class BSLinkInfo
74 {
75 public BSPrimLinkable member;
76 public BSLinkInfo(BSPrimLinkable pMember)
77 {
78 member = pMember;
79 }
80 public virtual void ResetLink() { }
81 public virtual void SetLinkParameters(BSConstraint constrain) { }
82 // Returns 'true' if physical property updates from the child should be reported to the simulator
83 public virtual bool ShouldUpdateChildProperties() { return false; }
84 }
85
86 public LinksetImplementation LinksetImpl { get; protected set; }
87
81 public BSPrimLinkable LinksetRoot { get; protected set; } 88 public BSPrimLinkable LinksetRoot { get; protected set; }
82 89
83 public BSScene PhysicsScene { get; private set; } 90 protected BSScene m_physicsScene { get; private set; }
84 91
85 static int m_nextLinksetID = 1; 92 static int m_nextLinksetID = 1;
86 public int LinksetID { get; private set; } 93 public int LinksetID { get; private set; }
87 94
88 // The children under the root in this linkset. 95 // The children under the root in this linkset.
89 protected HashSet<BSPrimLinkable> m_children; 96 // protected HashSet<BSPrimLinkable> m_children;
97 protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
90 98
91 // We lock the diddling of linkset classes to prevent any badness. 99 // We lock the diddling of linkset classes to prevent any badness.
92 // This locks the modification of the instances of this class. Changes 100 // This locks the modification of the instances of this class. Changes
93 // to the physical representation is done via the tainting mechenism. 101 // to the physical representation is done via the tainting mechenism.
94 protected object m_linksetActivityLock = new Object(); 102 protected object m_linksetActivityLock = new Object();
95 103
96 // Some linksets have a preferred physical shape.
97 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
98 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor)
99 {
100 return BSPhysicsShapeType.SHAPE_UNKNOWN;
101 }
102
103 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 104 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
104 public float LinksetMass { get; protected set; } 105 public float LinksetMass { get; protected set; }
105 106
@@ -122,9 +123,9 @@ public abstract class BSLinkset
122 // We create LOTS of linksets. 123 // We create LOTS of linksets.
123 if (m_nextLinksetID <= 0) 124 if (m_nextLinksetID <= 0)
124 m_nextLinksetID = 1; 125 m_nextLinksetID = 1;
125 PhysicsScene = scene; 126 m_physicsScene = scene;
126 LinksetRoot = parent; 127 LinksetRoot = parent;
127 m_children = new HashSet<BSPrimLinkable>(); 128 m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
128 LinksetMass = parent.RawMass; 129 LinksetMass = parent.RawMass;
129 Rebuilding = false; 130 Rebuilding = false;
130 131
@@ -151,7 +152,7 @@ public abstract class BSLinkset
151 // Returns a new linkset for the child which is a linkset of one (just the 152 // Returns a new linkset for the child which is a linkset of one (just the
152 // orphened child). 153 // orphened child).
153 // Called at runtime. 154 // Called at runtime.
154 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child) 155 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
155 { 156 {
156 lock (m_linksetActivityLock) 157 lock (m_linksetActivityLock)
157 { 158 {
@@ -160,12 +161,12 @@ public abstract class BSLinkset
160 // Cannot remove the root from a linkset. 161 // Cannot remove the root from a linkset.
161 return this; 162 return this;
162 } 163 }
163 RemoveChildFromLinkset(child); 164 RemoveChildFromLinkset(child, inTaintTime);
164 LinksetMass = ComputeLinksetMass(); 165 LinksetMass = ComputeLinksetMass();
165 } 166 }
166 167
167 // The child is down to a linkset of just itself 168 // The child is down to a linkset of just itself
168 return BSLinkset.Factory(PhysicsScene, child); 169 return BSLinkset.Factory(m_physicsScene, child);
169 } 170 }
170 171
171 // Return 'true' if the passed object is the root object of this linkset 172 // Return 'true' if the passed object is the root object of this linkset
@@ -185,17 +186,7 @@ public abstract class BSLinkset
185 bool ret = false; 186 bool ret = false;
186 lock (m_linksetActivityLock) 187 lock (m_linksetActivityLock)
187 { 188 {
188 ret = m_children.Contains(child); 189 ret = m_children.ContainsKey(child);
189 /* Safer version but the above should work
190 foreach (BSPrimLinkable bp in m_children)
191 {
192 if (child.LocalID == bp.LocalID)
193 {
194 ret = true;
195 break;
196 }
197 }
198 */
199 } 190 }
200 return ret; 191 return ret;
201 } 192 }
@@ -209,7 +200,35 @@ public abstract class BSLinkset
209 lock (m_linksetActivityLock) 200 lock (m_linksetActivityLock)
210 { 201 {
211 action(LinksetRoot); 202 action(LinksetRoot);
212 foreach (BSPrimLinkable po in m_children) 203 foreach (BSPrimLinkable po in m_children.Keys)
204 {
205 if (action(po))
206 break;
207 }
208 }
209 return ret;
210 }
211
212 public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
213 {
214 bool ret = false;
215 BSLinkInfo found = null;
216 lock (m_linksetActivityLock)
217 {
218 ret = m_children.TryGetValue(child, out found);
219 }
220 foundInfo = found;
221 return ret;
222 }
223 // Perform an action on each member of the linkset including root prim.
224 // Depends on the action on whether this should be done at taint time.
225 public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
226 public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
227 {
228 bool ret = false;
229 lock (m_linksetActivityLock)
230 {
231 foreach (BSLinkInfo po in m_children.Values)
213 { 232 {
214 if (action(po)) 233 if (action(po))
215 break; 234 break;
@@ -218,13 +237,55 @@ public abstract class BSLinkset
218 return ret; 237 return ret;
219 } 238 }
220 239
240 // Check the type of the link and return 'true' if the link is flexible and the
241 // updates from the child should be sent to the simulator so things change.
242 public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
243 {
244 bool ret = false;
245
246 BSLinkInfo linkInfo;
247 if (m_children.TryGetValue(child, out linkInfo))
248 {
249 ret = linkInfo.ShouldUpdateChildProperties();
250 }
251
252 return ret;
253 }
254
255 // Called after a simulation step to post a collision with this object.
256 // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
257 // anything to add for the collision and it should be passed through normal processing.
258 // Default processing for a linkset.
259 public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
260 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
261 {
262 bool ret = false;
263
264 // prims in the same linkset cannot collide with each other
265 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
266 if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
267 {
268 // By returning 'true', we tell the caller the collision has been 'handled' so it won't
269 // do anything about this collision and thus, effectivily, ignoring the collision.
270 ret = true;
271 }
272 else
273 {
274 // Not a collision between members of the linkset. Must be a real collision.
275 // So the linkset root can know if there is a collision anywhere in the linkset.
276 LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
277 }
278
279 return ret;
280 }
281
221 // I am the root of a linkset and a new child is being added 282 // I am the root of a linkset and a new child is being added
222 // Called while LinkActivity is locked. 283 // Called while LinkActivity is locked.
223 protected abstract void AddChildToLinkset(BSPrimLinkable child); 284 protected abstract void AddChildToLinkset(BSPrimLinkable child);
224 285
225 // I am the root of a linkset and one of my children is being removed. 286 // I am the root of a linkset and one of my children is being removed.
226 // Safe to call even if the child is not really in my linkset. 287 // Safe to call even if the child is not really in my linkset.
227 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); 288 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
228 289
229 // When physical properties are changed the linkset needs to recalculate 290 // When physical properties are changed the linkset needs to recalculate
230 // its internal properties. 291 // its internal properties.
@@ -263,9 +324,88 @@ public abstract class BSLinkset
263 // This is called when the root body is changing. 324 // This is called when the root body is changing.
264 // Returns 'true' of something was actually removed and would need restoring 325 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!! 326 // Called at taint-time!!
266 public abstract bool RemoveBodyDependencies(BSPrimLinkable child); 327 public abstract bool RemoveDependencies(BSPrimLinkable child);
267 328
268 // ================================================================ 329 // ================================================================
330 // Some physical setting happen to all members of the linkset
331 public virtual void SetPhysicalFriction(float friction)
332 {
333 ForEachMember((member) =>
334 {
335 if (member.PhysBody.HasPhysicalBody)
336 m_physicsScene.PE.SetFriction(member.PhysBody, friction);
337 return false; // 'false' says to continue looping
338 }
339 );
340 }
341 public virtual void SetPhysicalRestitution(float restitution)
342 {
343 ForEachMember((member) =>
344 {
345 if (member.PhysBody.HasPhysicalBody)
346 m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
347 return false; // 'false' says to continue looping
348 }
349 );
350 }
351 public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
352 {
353 ForEachMember((member) =>
354 {
355 if (member.PhysBody.HasPhysicalBody)
356 m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
357 return false; // 'false' says to continue looping
358 }
359 );
360 }
361 public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
362 {
363 ForEachMember((member) =>
364 {
365 if (member.PhysBody.HasPhysicalBody)
366 {
367 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
368 member.Inertia = inertia * inertiaFactor;
369 m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
370 m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
371 DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
372
373 }
374 return false; // 'false' says to continue looping
375 }
376 );
377 }
378 public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
379 {
380 ForEachMember((member) =>
381 {
382 if (member.PhysBody.HasPhysicalBody)
383 m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
384 return false; // 'false' says to continue looping
385 }
386 );
387 }
388 public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
389 {
390 ForEachMember((member) =>
391 {
392 if (member.PhysBody.HasPhysicalBody)
393 m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
394 return false; // 'false' says to continue looping
395 }
396 );
397 }
398 public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
399 {
400 ForEachMember((member) =>
401 {
402 if (member.PhysBody.HasPhysicalBody)
403 m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
404 return false; // 'false' says to continue looping
405 }
406 );
407 }
408 // ================================================================
269 protected virtual float ComputeLinksetMass() 409 protected virtual float ComputeLinksetMass()
270 { 410 {
271 float mass = LinksetRoot.RawMass; 411 float mass = LinksetRoot.RawMass;
@@ -273,7 +413,7 @@ public abstract class BSLinkset
273 { 413 {
274 lock (m_linksetActivityLock) 414 lock (m_linksetActivityLock)
275 { 415 {
276 foreach (BSPrimLinkable bp in m_children) 416 foreach (BSPrimLinkable bp in m_children.Keys)
277 { 417 {
278 mass += bp.RawMass; 418 mass += bp.RawMass;
279 } 419 }
@@ -291,7 +431,7 @@ public abstract class BSLinkset
291 com = LinksetRoot.Position * LinksetRoot.RawMass; 431 com = LinksetRoot.Position * LinksetRoot.RawMass;
292 float totalMass = LinksetRoot.RawMass; 432 float totalMass = LinksetRoot.RawMass;
293 433
294 foreach (BSPrimLinkable bp in m_children) 434 foreach (BSPrimLinkable bp in m_children.Keys)
295 { 435 {
296 com += bp.Position * bp.RawMass; 436 com += bp.Position * bp.RawMass;
297 totalMass += bp.RawMass; 437 totalMass += bp.RawMass;
@@ -310,7 +450,7 @@ public abstract class BSLinkset
310 { 450 {
311 com = LinksetRoot.Position; 451 com = LinksetRoot.Position;
312 452
313 foreach (BSPrimLinkable bp in m_children) 453 foreach (BSPrimLinkable bp in m_children.Keys)
314 { 454 {
315 com += bp.Position; 455 com += bp.Position;
316 } 456 }
@@ -320,12 +460,18 @@ public abstract class BSLinkset
320 return com; 460 return com;
321 } 461 }
322 462
463 #region Extension
464 public virtual object Extension(string pFunct, params object[] pParams)
465 {
466 return null;
467 }
468 #endregion // Extension
469
323 // Invoke the detailed logger and output something if it's enabled. 470 // Invoke the detailed logger and output something if it's enabled.
324 protected void DetailLog(string msg, params Object[] args) 471 protected void DetailLog(string msg, params Object[] args)
325 { 472 {
326 if (PhysicsScene.PhysicsLogging.Enabled) 473 if (m_physicsScene.PhysicsLogging.Enabled)
327 PhysicsScene.DetailLog(msg, args); 474 m_physicsScene.DetailLog(msg, args);
328 } 475 }
329
330} 476}
331} 477}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index e05562a..8f12189 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -35,103 +35,78 @@ using OMV = OpenMetaverse;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37 37
38// When a child is linked, the relationship position of the child to the parent 38public sealed class BSLinksetCompound : BSLinkset
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{ 39{
43 public int Index; 40 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
44 public OMV.Vector3 OffsetFromRoot; 41
45 public OMV.Vector3 OffsetFromCenterOfMass; 42 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
46 public OMV.Quaternion OffsetRot; 43 : base(scene, parent)
47 public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r)
48 { 44 {
49 Index = indx; 45 LinksetImpl = LinksetImplementation.Compound;
50 OffsetFromRoot = p;
51 OffsetFromCenterOfMass = p;
52 OffsetRot = r;
53 } 46 }
54 // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) 47
55 public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) 48 // ================================================================
49 // Changing the physical property of the linkset only needs to change the root
50 public override void SetPhysicalFriction(float friction)
56 { 51 {
57 // Each child position and rotation is given relative to the center-of-mass. 52 if (LinksetRoot.PhysBody.HasPhysicalBody)
58 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); 53 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
59 OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation;
60 OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement;
61 OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation;
62
63 // Save relative position for recomputing child's world position after moving linkset.
64 Index = indx;
65 OffsetFromRoot = displacementFromRoot;
66 OffsetFromCenterOfMass = displacementFromCOM;
67 OffsetRot = displacementRot;
68 } 54 }
69 public override void Clear() 55 public override void SetPhysicalRestitution(float restitution)
70 { 56 {
71 Index = 0; 57 if (LinksetRoot.PhysBody.HasPhysicalBody)
72 OffsetFromRoot = OMV.Vector3.Zero; 58 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
73 OffsetFromCenterOfMass = OMV.Vector3.Zero;
74 OffsetRot = OMV.Quaternion.Identity;
75 } 59 }
76 public override string ToString() 60 public override void SetPhysicalGravity(OMV.Vector3 gravity)
77 { 61 {
78 StringBuilder buff = new StringBuilder(); 62 if (LinksetRoot.PhysBody.HasPhysicalBody)
79 buff.Append("<i="); 63 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
80 buff.Append(Index.ToString());
81 buff.Append(",p=");
82 buff.Append(OffsetFromRoot.ToString());
83 buff.Append(",m=");
84 buff.Append(OffsetFromCenterOfMass.ToString());
85 buff.Append(",r=");
86 buff.Append(OffsetRot.ToString());
87 buff.Append(">");
88 return buff.ToString();
89 } 64 }
90}; 65 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
91
92public sealed class BSLinksetCompound : BSLinkset
93{
94 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
95
96 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
97 : base(scene, parent)
98 { 66 {
67 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
68 LinksetRoot.Inertia = inertia * inertiaFactor;
69 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
70 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
99 } 71 }
100 72 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
101 // For compound implimented linksets, if there are children, use compound shape for the root. 73 {
102 public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) 74 if (LinksetRoot.PhysBody.HasPhysicalBody)
103 { 75 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
104 // Returning 'unknown' means we don't have a preference. 76 }
105 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 77 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
106 if (IsRoot(requestor) && HasAnyChildren) 78 {
107 { 79 if (LinksetRoot.PhysBody.HasPhysicalBody)
108 ret = BSPhysicsShapeType.SHAPE_COMPOUND; 80 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
109 }
110 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
111 return ret;
112 } 81 }
82 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
83 {
84 if (LinksetRoot.PhysBody.HasPhysicalBody)
85 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
86 }
87 // ================================================================
113 88
114 // When physical properties are changed the linkset needs to recalculate 89 // When physical properties are changed the linkset needs to recalculate
115 // its internal properties. 90 // its internal properties.
116 public override void Refresh(BSPrimLinkable requestor) 91 public override void Refresh(BSPrimLinkable requestor)
117 { 92 {
118 base.Refresh(requestor);
119
120 // Something changed so do the rebuilding thing 93 // Something changed so do the rebuilding thing
121 // ScheduleRebuild(); 94 ScheduleRebuild(requestor);
95 base.Refresh(requestor);
122 } 96 }
123 97
124 // Schedule a refresh to happen after all the other taint processing. 98 // Schedule a refresh to happen after all the other taint processing.
125 private void ScheduleRebuild(BSPrimLinkable requestor) 99 private void ScheduleRebuild(BSPrimLinkable requestor)
126 { 100 {
127 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", 101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
128 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); 102 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
103
129 // When rebuilding, it is possible to set properties that would normally require a rebuild. 104 // When rebuilding, it is possible to set properties that would normally require a rebuild.
130 // If already rebuilding, don't request another rebuild. 105 // If already rebuilding, don't request another rebuild.
131 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. 106 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
132 if (!Rebuilding && HasAnyChildren) 107 if (!Rebuilding && HasAnyChildren)
133 { 108 {
134 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() 109 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
135 { 110 {
136 if (HasAnyChildren) 111 if (HasAnyChildren)
137 RecomputeLinksetCompound(); 112 RecomputeLinksetCompound();
@@ -151,47 +126,24 @@ public sealed class BSLinksetCompound : BSLinkset
151 if (IsRoot(child)) 126 if (IsRoot(child))
152 { 127 {
153 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. 128 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
154 ScheduleRebuild(LinksetRoot); 129 Refresh(LinksetRoot);
155 }
156 else
157 {
158 // The origional prims are removed from the world as the shape of the root compound
159 // shape takes over.
160 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
161 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
162 // We don't want collisions from the old linkset children.
163 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
164
165 child.PhysBody.collisionType = CollisionType.LinksetChild;
166
167 ret = true;
168 } 130 }
169 return ret; 131 return ret;
170 } 132 }
171 133
172 // The object is going static (non-physical). Do any setup necessary for a static linkset. 134 // The object is going static (non-physical). We do not do anything for static linksets.
173 // Return 'true' if any properties updated on the passed object. 135 // Return 'true' if any properties updated on the passed object.
174 // This doesn't normally happen -- OpenSim removes the objects from the physical
175 // world if it is a static linkset.
176 // Called at taint-time! 136 // Called at taint-time!
177 public override bool MakeStatic(BSPrimLinkable child) 137 public override bool MakeStatic(BSPrimLinkable child)
178 { 138 {
179 bool ret = false; 139 bool ret = false;
140
180 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 141 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
142 child.ClearDisplacement();
181 if (IsRoot(child)) 143 if (IsRoot(child))
182 { 144 {
183 ScheduleRebuild(LinksetRoot); 145 // Schedule a rebuild to verify that the root shape is set to the real shape.
184 } 146 Refresh(LinksetRoot);
185 else
186 {
187 // The non-physical children can come back to life.
188 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
189
190 child.PhysBody.collisionType = CollisionType.LinksetChild;
191
192 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
193 PhysicsScene.PE.Activate(child.PhysBody, false);
194 ret = true;
195 } 147 }
196 return ret; 148 return ret;
197 } 149 }
@@ -200,13 +152,20 @@ public sealed class BSLinksetCompound : BSLinkset
200 // Called at taint-time. 152 // Called at taint-time.
201 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) 153 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
202 { 154 {
155 if (!LinksetRoot.IsPhysicallyActive)
156 {
157 // No reason to do this physical stuff for static linksets.
158 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
159 return;
160 }
161
203 // The user moving a child around requires the rebuilding of the linkset compound shape 162 // The user moving a child around requires the rebuilding of the linkset compound shape
204 // One problem is this happens when a border is crossed -- the simulator implementation 163 // One problem is this happens when a border is crossed -- the simulator implementation
205 // stores the position into the group which causes the move of the object 164 // stores the position into the group which causes the move of the object
206 // but it also means all the child positions get updated. 165 // but it also means all the child positions get updated.
207 // What would cause an unnecessary rebuild so we make sure the linkset is in a 166 // What would cause an unnecessary rebuild so we make sure the linkset is in a
208 // region before bothering to do a rebuild. 167 // region before bothering to do a rebuild.
209 if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) 168 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
210 { 169 {
211 // If a child of the linkset is updating only the position or rotation, that can be done 170 // If a child of the linkset is updating only the position or rotation, that can be done
212 // without rebuilding the linkset. 171 // without rebuilding the linkset.
@@ -218,22 +177,22 @@ public sealed class BSLinksetCompound : BSLinkset
218 // and that is caused by us updating the object. 177 // and that is caused by us updating the object.
219 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) 178 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
220 { 179 {
221 // Find the physical instance of the child 180 // Find the physical instance of the child
222 if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) 181 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
223 { 182 {
224 // It is possible that the linkset is still under construction and the child is not yet 183 // It is possible that the linkset is still under construction and the child is not yet
225 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will 184 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
226 // build the whole thing with the new position or rotation. 185 // build the whole thing with the new position or rotation.
227 // The index must be checked because Bullet references the child array but does no validity 186 // The index must be checked because Bullet references the child array but does no validity
228 // checking of the child index passed. 187 // checking of the child index passed.
229 int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); 188 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
230 if (updated.LinksetChildIndex < numLinksetChildren) 189 if (updated.LinksetChildIndex < numLinksetChildren)
231 { 190 {
232 BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); 191 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
233 if (linksetChildShape.HasPhysicalShape) 192 if (linksetChildShape.HasPhysicalShape)
234 { 193 {
235 // Found the child shape within the compound shape 194 // Found the child shape within the compound shape
236 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, 195 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
237 updated.RawPosition - LinksetRoot.RawPosition, 196 updated.RawPosition - LinksetRoot.RawPosition,
238 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), 197 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
239 true /* shouldRecalculateLocalAabb */); 198 true /* shouldRecalculateLocalAabb */);
@@ -267,83 +226,29 @@ public sealed class BSLinksetCompound : BSLinkset
267 // there will already be a rebuild scheduled. 226 // there will already be a rebuild scheduled.
268 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", 227 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
269 updated.LocalID, whichUpdated); 228 updated.LocalID, whichUpdated);
270 updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. 229 Refresh(updated);
271 ScheduleRebuild(updated);
272 } 230 }
273 } 231 }
274 } 232 }
275 } 233 }
276 234
277 // Routine called when rebuilding the body of some member of the linkset. 235 // Routine called when rebuilding the body of some member of the linkset.
278 // Since we don't keep in world relationships, do nothing unless it's a child changing. 236 // If one of the bodies is being changed, the linkset needs rebuilding.
237 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
279 // Returns 'true' of something was actually removed and would need restoring 238 // Returns 'true' of something was actually removed and would need restoring
280 // Called at taint-time!! 239 // Called at taint-time!!
281 public override bool RemoveBodyDependencies(BSPrimLinkable child) 240 public override bool RemoveDependencies(BSPrimLinkable child)
282 { 241 {
283 bool ret = false; 242 bool ret = false;
284 243
285 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 244 DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
286 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); 245 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
287 246
288 if (!IsRoot(child)) 247 Refresh(child);
289 {
290 // Because it is a convenient time, recompute child world position and rotation based on
291 // its position in the linkset.
292 RecomputeChildWorldPosition(child, true /* inTaintTime */);
293 child.LinksetInfo = null;
294 }
295
296 // Cannot schedule a refresh/rebuild here because this routine is called when
297 // the linkset is being rebuilt.
298 // InternalRefresh(LinksetRoot);
299 248
300 return ret; 249 return ret;
301 } 250 }
302 251
303 // When the linkset is built, the child shape is added to the compound shape relative to the
304 // root shape. The linkset then moves around but this does not move the actual child
305 // prim. The child prim's location must be recomputed based on the location of the root shape.
306 private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime)
307 {
308 // For the moment (20130201), disable this computation (converting the child physical addr back to
309 // a region address) until we have a good handle on center-of-mass offsets and what the physics
310 // engine moving a child actually means.
311 // The simulator keeps track of where children should be as the linkset moves. Setting
312 // the pos/rot here does not effect that knowledge as there is no good way for the
313 // physics engine to send the simulator an update for a child.
314
315 /*
316 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
317 if (lci != null)
318 {
319 if (inTaintTime)
320 {
321 OMV.Vector3 oldPos = child.RawPosition;
322 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot;
323 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
324 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
325 child.LocalID, oldPos, lci, child.RawPosition);
326 }
327 else
328 {
329 // TaintedObject is not used here so the raw position is set now and not at taint-time.
330 child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot;
331 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
332 }
333 }
334 else
335 {
336 // This happens when children have been added to the linkset but the linkset
337 // has not been constructed yet. So like, at taint time, adding children to a linkset
338 // and then changing properties of the children (makePhysical, for instance)
339 // but the post-print action of actually rebuilding the linkset has not yet happened.
340 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
341 // LogHeader, child.LocalID);
342 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
343 }
344 */
345 }
346
347 // ================================================================ 252 // ================================================================
348 253
349 // Add a new child to the linkset. 254 // Add a new child to the linkset.
@@ -352,19 +257,19 @@ public sealed class BSLinksetCompound : BSLinkset
352 { 257 {
353 if (!HasChild(child)) 258 if (!HasChild(child))
354 { 259 {
355 m_children.Add(child); 260 m_children.Add(child, new BSLinkInfo(child));
356 261
357 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 262 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
358 263
359 // Rebuild the compound shape with the new child shape included 264 // Rebuild the compound shape with the new child shape included
360 ScheduleRebuild(child); 265 Refresh(child);
361 } 266 }
362 return; 267 return;
363 } 268 }
364 269
365 // Remove the specified child from the linkset. 270 // Remove the specified child from the linkset.
366 // Safe to call even if the child is not really in the linkset. 271 // Safe to call even if the child is not really in the linkset.
367 protected override void RemoveChildFromLinkset(BSPrimLinkable child) 272 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
368 { 273 {
369 child.ClearDisplacement(); 274 child.ClearDisplacement();
370 275
@@ -376,19 +281,17 @@ public sealed class BSLinksetCompound : BSLinkset
376 child.LocalID, child.PhysBody.AddrString); 281 child.LocalID, child.PhysBody.AddrString);
377 282
378 // Cause the child's body to be rebuilt and thus restored to normal operation 283 // Cause the child's body to be rebuilt and thus restored to normal operation
379 RecomputeChildWorldPosition(child, false); 284 child.ForceBodyShapeRebuild(inTaintTime);
380 child.LinksetInfo = null;
381 child.ForceBodyShapeRebuild(false);
382 285
383 if (!HasAnyChildren) 286 if (!HasAnyChildren)
384 { 287 {
385 // The linkset is now empty. The root needs rebuilding. 288 // The linkset is now empty. The root needs rebuilding.
386 LinksetRoot.ForceBodyShapeRebuild(false); 289 LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
387 } 290 }
388 else 291 else
389 { 292 {
390 // Rebuild the compound shape with the child removed 293 // Rebuild the compound shape with the child removed
391 ScheduleRebuild(LinksetRoot); 294 Refresh(LinksetRoot);
392 } 295 }
393 } 296 }
394 return; 297 return;
@@ -399,108 +302,118 @@ public sealed class BSLinksetCompound : BSLinkset
399 // Constraint linksets are rebuilt every time. 302 // Constraint linksets are rebuilt every time.
400 // Note that this works for rebuilding just the root after a linkset is taken apart. 303 // Note that this works for rebuilding just the root after a linkset is taken apart.
401 // Called at taint time!! 304 // Called at taint time!!
402 private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged 305 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
403 private void RecomputeLinksetCompound() 306 private void RecomputeLinksetCompound()
404 { 307 {
405 try 308 try
406 { 309 {
407 // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.)
408 Rebuilding = true; 310 Rebuilding = true;
409 311
410 // Cause the root shape to be rebuilt as a compound object with just the root in it 312 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
411 LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); 313 // to what they should be as if the root was not in a linkset.
314 // Not that bad since we only get into this routine if there are children in the linkset and
315 // something has been updated/changed.
316 // Have to do the rebuild before checking for physical because this might be a linkset
317 // being destructed and going non-physical.
318 LinksetRoot.ForceBodyShapeRebuild(true);
412 319
413 // The center of mass for the linkset is the geometric center of the group. 320 // There is no reason to build all this physical stuff for a non-physical or empty linkset.
414 // Compute a displacement for each component so it is relative to the center-of-mass. 321 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
415 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
416 OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition;
417 if (!disableCOM) // DEBUG DEBUG
418 { 322 {
419 // Compute a center-of-mass in world coordinates. 323 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
420 centerOfMassW = ComputeLinksetCenterOfMass(); 324 return; // Note the 'finally' clause at the botton which will get executed.
421 } 325 }
422 326
423 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); 327 // Get a new compound shape to build the linkset shape in.
424 328 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
425 // 'centerDisplacement' is the value to subtract from children to give physical offset position
426 OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
427 LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement);
428 329
429 // This causes the physical position of the root prim to be offset to accomodate for the displacements 330 // Compute a displacement for each component so it is relative to the center-of-mass.
430 LinksetRoot.ForcePosition = LinksetRoot.RawPosition; 331 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
332 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
431 333
432 // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM 334 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
433 PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, 335 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
434 -centerDisplacement,
435 OMV.Quaternion.Identity, // LinksetRoot.RawOrientation,
436 false /* shouldRecalculateLocalAabb (is done later after linkset built) */);
437 336
438 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", 337 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
439 LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); 338 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
339 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
340 {
341 // Zero everything if center-of-mass displacement is not being done.
342 centerDisplacementV = OMV.Vector3.Zero;
343 LinksetRoot.ClearDisplacement();
344 }
345 else
346 {
347 // The actual center-of-mass could have been set by the user.
348 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
349 }
440 350
441 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", 351 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
442 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); 352 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
443 353
444 // Add a shape for each of the other children in the linkset 354 // Add the shapes of all the components of the linkset
445 int memberIndex = 1; 355 int memberIndex = 1;
446 ForEachMember(delegate(BSPrimLinkable cPrim) 356 ForEachMember((cPrim) =>
447 { 357 {
448 if (IsRoot(cPrim)) 358 if (IsRoot(cPrim))
449 { 359 {
360 // Root shape is always index zero.
450 cPrim.LinksetChildIndex = 0; 361 cPrim.LinksetChildIndex = 0;
451 } 362 }
452 else 363 else
453 { 364 {
454 cPrim.LinksetChildIndex = memberIndex; 365 cPrim.LinksetChildIndex = memberIndex;
366 memberIndex++;
367 }
455 368
456 if (cPrim.PhysShape.isNativeShape) 369 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
457 { 370 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
458 // A native shape is turned into a hull collision shape because native
459 // shapes are not shared so we have to hullify it so it will be tracked
460 // and freed at the correct time. This also solves the scaling problem
461 // (native shapes scale but hull/meshes are assumed to not be).
462 // TODO: decide of the native shape can just be used in the compound shape.
463 // Use call to CreateGeomNonSpecial().
464 BulletShape saveShape = cPrim.PhysShape;
465 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
466 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
467 BulletShape newShape = cPrim.PhysShape;
468 cPrim.PhysShape = saveShape;
469
470 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
471 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
472 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
473 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
474 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot);
475 }
476 else
477 {
478 // For the shared shapes (meshes and hulls), just use the shape in the child.
479 // The reference count added here will be decremented when the compound shape
480 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
481 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
482 {
483 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
484 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
485 }
486 OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement;
487 OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation;
488 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
489 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}",
490 LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot);
491 371
492 } 372 // Offset the child shape from the center-of-mass and rotate it to vehicle relative.
493 memberIndex++; 373 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
374 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
375
376 // Add the child shape to the compound shape being built
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
380
381 // Since we are borrowing the shape of the child, disable the origional child body
382 if (!IsRoot(cPrim))
383 {
384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
386 // We don't want collisions from the old linkset children.
387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
494 } 389 }
390
495 return false; // 'false' says to move onto the next child in the list 391 return false; // 'false' says to move onto the next child in the list
496 }); 392 });
497 393
394 // Replace the root shape with the built compound shape.
395 // Object removed and added to world to get collision cache rebuilt for new shape.
396 LinksetRoot.PhysShape.Dereference(m_physicsScene);
397 LinksetRoot.PhysShape = linksetShape;
398 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
399 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
400 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
402 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
403
498 // With all of the linkset packed into the root prim, it has the mass of everyone. 404 // With all of the linkset packed into the root prim, it has the mass of everyone.
499 LinksetMass = ComputeLinksetMass(); 405 LinksetMass = ComputeLinksetMass();
500 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); 406 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
501 407
502 // Enable the physical position updator to return the position and rotation of the root shape 408 if (UseBulletSimRootOffsetHack)
503 PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); 409 {
410 // Enable the physical position updator to return the position and rotation of the root shape.
411 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
412 // compound shape. This aleviates the need to offset the returned physical position by the
413 // center-of-mass offset.
414 // TODO: either debug this feature or remove it.
415 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
416 }
504 } 417 }
505 finally 418 finally
506 { 419 {
@@ -508,7 +421,7 @@ public sealed class BSLinksetCompound : BSLinkset
508 } 421 }
509 422
510 // See that the Aabb surrounds the new shape 423 // See that the Aabb surrounds the new shape
511 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); 424 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
512 } 425 }
513} 426}
514} \ No newline at end of file 427} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index 6d252ca..aaf92c8 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -28,6 +28,8 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30 30
31using OpenSim.Region.OptionalModules.Scripting;
32
31using OMV = OpenMetaverse; 33using OMV = OpenMetaverse;
32 34
33namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
@@ -36,26 +38,194 @@ public sealed class BSLinksetConstraints : BSLinkset
36{ 38{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 39 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 40
41 public class BSLinkInfoConstraint : BSLinkInfo
42 {
43 public ConstraintType constraintType;
44 public BSConstraint constraint;
45 public OMV.Vector3 linearLimitLow;
46 public OMV.Vector3 linearLimitHigh;
47 public OMV.Vector3 angularLimitLow;
48 public OMV.Vector3 angularLimitHigh;
49 public bool useFrameOffset;
50 public bool enableTransMotor;
51 public float transMotorMaxVel;
52 public float transMotorMaxForce;
53 public float cfm;
54 public float erp;
55 public float solverIterations;
56 //
57 public OMV.Vector3 frameInAloc;
58 public OMV.Quaternion frameInArot;
59 public OMV.Vector3 frameInBloc;
60 public OMV.Quaternion frameInBrot;
61 public bool useLinearReferenceFrameA;
62 // Spring
63 public bool[] springAxisEnable;
64 public float[] springDamping;
65 public float[] springStiffness;
66 public OMV.Vector3 springLinearEquilibriumPoint;
67 public OMV.Vector3 springAngularEquilibriumPoint;
68
69 public BSLinkInfoConstraint(BSPrimLinkable pMember)
70 : base(pMember)
71 {
72 constraint = null;
73 ResetLink();
74 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
75 }
76
77 // Set all the parameters for this constraint to a fixed, non-movable constraint.
78 public override void ResetLink()
79 {
80 // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
81 constraintType = ConstraintType.FIXED_CONSTRAINT_TYPE;
82 linearLimitLow = OMV.Vector3.Zero;
83 linearLimitHigh = OMV.Vector3.Zero;
84 angularLimitLow = OMV.Vector3.Zero;
85 angularLimitHigh = OMV.Vector3.Zero;
86 useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
87 enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
88 transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
89 transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
90 cfm = BSParam.LinkConstraintCFM;
91 erp = BSParam.LinkConstraintERP;
92 solverIterations = BSParam.LinkConstraintSolverIterations;
93 frameInAloc = OMV.Vector3.Zero;
94 frameInArot = OMV.Quaternion.Identity;
95 frameInBloc = OMV.Vector3.Zero;
96 frameInBrot = OMV.Quaternion.Identity;
97 useLinearReferenceFrameA = true;
98 springAxisEnable = new bool[6];
99 springDamping = new float[6];
100 springStiffness = new float[6];
101 for (int ii = 0; ii < springAxisEnable.Length; ii++)
102 {
103 springAxisEnable[ii] = false;
104 springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
105 springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
106 }
107 springLinearEquilibriumPoint = OMV.Vector3.Zero;
108 springAngularEquilibriumPoint = OMV.Vector3.Zero;
109 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
110 }
111
112 // Given a constraint, apply the current constraint parameters to same.
113 public override void SetLinkParameters(BSConstraint constrain)
114 {
115 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
116 switch (constraintType)
117 {
118 case ConstraintType.FIXED_CONSTRAINT_TYPE:
119 case ConstraintType.D6_CONSTRAINT_TYPE:
120 BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
121 if (constrain6dof != null)
122 {
123 // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
124 // zero linear and angular limits makes the objects unable to move in relation to each other
125 constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
126 constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
127
128 // tweek the constraint to increase stability
129 constrain6dof.UseFrameOffset(useFrameOffset);
130 constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
131 constrain6dof.SetCFMAndERP(cfm, erp);
132 if (solverIterations != 0f)
133 {
134 constrain6dof.SetSolverIterations(solverIterations);
135 }
136 }
137 break;
138 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
139 BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
140 if (constrainSpring != null)
141 {
142 // zero linear and angular limits makes the objects unable to move in relation to each other
143 constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
144 constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
145
146 // tweek the constraint to increase stability
147 constrainSpring.UseFrameOffset(useFrameOffset);
148 constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
149 constrainSpring.SetCFMAndERP(cfm, erp);
150 if (solverIterations != 0f)
151 {
152 constrainSpring.SetSolverIterations(solverIterations);
153 }
154 for (int ii = 0; ii < springAxisEnable.Length; ii++)
155 {
156 constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
157 if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
158 constrainSpring.SetDamping(ii, springDamping[ii]);
159 if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
160 constrainSpring.SetStiffness(ii, springStiffness[ii]);
161 }
162 constrainSpring.CalculateTransforms();
163
164 if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
165 constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
166 else
167 constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
168 }
169 break;
170 default:
171 break;
172 }
173 }
174
175 // Return 'true' if the property updates from the physics engine should be reported
176 // to the simulator.
177 // If the constraint is fixed, we don't need to report as the simulator and viewer will
178 // report the right things.
179 public override bool ShouldUpdateChildProperties()
180 {
181 bool ret = true;
182 if (constraintType == ConstraintType.FIXED_CONSTRAINT_TYPE)
183 ret = false;
184
185 return ret;
186 }
187 }
188
39 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) 189 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
40 { 190 {
191 LinksetImpl = LinksetImplementation.Constraint;
41 } 192 }
42 193
194 private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
195
43 // When physical properties are changed the linkset needs to recalculate 196 // When physical properties are changed the linkset needs to recalculate
44 // its internal properties. 197 // its internal properties.
45 // This is queued in the 'post taint' queue so the 198 // This is queued in the 'post taint' queue so the
46 // refresh will happen once after all the other taints are applied. 199 // refresh will happen once after all the other taints are applied.
47 public override void Refresh(BSPrimLinkable requestor) 200 public override void Refresh(BSPrimLinkable requestor)
48 { 201 {
202 ScheduleRebuild(requestor);
49 base.Refresh(requestor); 203 base.Refresh(requestor);
50 204
51 if (HasAnyChildren && IsRoot(requestor)) 205 }
206
207 private void ScheduleRebuild(BSPrimLinkable requestor)
208 {
209 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
210 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
211
212 // When rebuilding, it is possible to set properties that would normally require a rebuild.
213 // If already rebuilding, don't request another rebuild.
214 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
215 if (!Rebuilding && HasAnyChildren)
52 { 216 {
53 // Queue to happen after all the other taint processing 217 // Queue to happen after all the other taint processing
54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 218 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
219 {
220 if (HasAnyChildren)
55 { 221 {
56 if (HasAnyChildren && IsRoot(requestor)) 222 // Constraints that have not been changed are not rebuild but make sure
57 RecomputeLinksetConstraints(); 223 // the constraint of the requestor is rebuilt.
58 }); 224 PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
225 // Rebuild the linkset and all its constraints.
226 RecomputeLinksetConstraints();
227 }
228 });
59 } 229 }
60 } 230 }
61 231
@@ -67,8 +237,14 @@ public sealed class BSLinksetConstraints : BSLinkset
67 // Called at taint-time! 237 // Called at taint-time!
68 public override bool MakeDynamic(BSPrimLinkable child) 238 public override bool MakeDynamic(BSPrimLinkable child)
69 { 239 {
70 // What is done for each object in BSPrim is what we want. 240 bool ret = false;
71 return false; 241 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
242 if (IsRoot(child))
243 {
244 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
245 Refresh(LinksetRoot);
246 }
247 return ret;
72 } 248 }
73 249
74 // The object is going static (non-physical). Do any setup necessary for a static linkset. 250 // The object is going static (non-physical). Do any setup necessary for a static linkset.
@@ -78,8 +254,16 @@ public sealed class BSLinksetConstraints : BSLinkset
78 // Called at taint-time! 254 // Called at taint-time!
79 public override bool MakeStatic(BSPrimLinkable child) 255 public override bool MakeStatic(BSPrimLinkable child)
80 { 256 {
81 // What is done for each object in BSPrim is what we want. 257 bool ret = false;
82 return false; 258
259 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
260 child.ClearDisplacement();
261 if (IsRoot(child))
262 {
263 // Schedule a rebuild to verify that the root shape is set to the real shape.
264 Refresh(LinksetRoot);
265 }
266 return ret;
83 } 267 }
84 268
85 // Called at taint-time!! 269 // Called at taint-time!!
@@ -93,11 +277,11 @@ public sealed class BSLinksetConstraints : BSLinkset
93 // up to rebuild the constraints before the next simulation step. 277 // up to rebuild the constraints before the next simulation step.
94 // Returns 'true' of something was actually removed and would need restoring 278 // Returns 'true' of something was actually removed and would need restoring
95 // Called at taint-time!! 279 // Called at taint-time!!
96 public override bool RemoveBodyDependencies(BSPrimLinkable child) 280 public override bool RemoveDependencies(BSPrimLinkable child)
97 { 281 {
98 bool ret = false; 282 bool ret = false;
99 283
100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 284 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); 285 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
102 286
103 lock (m_linksetActivityLock) 287 lock (m_linksetActivityLock)
@@ -118,7 +302,7 @@ public sealed class BSLinksetConstraints : BSLinkset
118 { 302 {
119 if (!HasChild(child)) 303 if (!HasChild(child))
120 { 304 {
121 m_children.Add(child); 305 m_children.Add(child, new BSLinkInfoConstraint(child));
122 306
123 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 307 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
124 308
@@ -130,7 +314,7 @@ public sealed class BSLinksetConstraints : BSLinkset
130 314
131 // Remove the specified child from the linkset. 315 // Remove the specified child from the linkset.
132 // Safe to call even if the child is not really in my linkset. 316 // Safe to call even if the child is not really in my linkset.
133 protected override void RemoveChildFromLinkset(BSPrimLinkable child) 317 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
134 { 318 {
135 if (m_children.Remove(child)) 319 if (m_children.Remove(child))
136 { 320 {
@@ -142,7 +326,7 @@ public sealed class BSLinksetConstraints : BSLinkset
142 rootx.LocalID, rootx.PhysBody.AddrString, 326 rootx.LocalID, rootx.PhysBody.AddrString,
143 childx.LocalID, childx.PhysBody.AddrString); 327 childx.LocalID, childx.PhysBody.AddrString);
144 328
145 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 329 m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
146 { 330 {
147 PhysicallyUnlinkAChildFromRoot(rootx, childx); 331 PhysicallyUnlinkAChildFromRoot(rootx, childx);
148 }); 332 });
@@ -165,73 +349,86 @@ public sealed class BSLinksetConstraints : BSLinkset
165 Refresh(rootPrim); 349 Refresh(rootPrim);
166 } 350 }
167 351
168 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) 352 // Create a static constraint between the two passed objects
353 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
169 { 354 {
355 BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
356 if (linkInfo == null)
357 return null;
358
170 // Zero motion for children so they don't interpolate 359 // Zero motion for children so they don't interpolate
171 childPrim.ZeroMotion(true); 360 li.member.ZeroMotion(true);
172 361
173 // Relative position normalized to the root prim 362 BSConstraint constrain = null;
174 // Essentually a vector pointing from center of rootPrim to center of childPrim 363
175 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; 364 switch (linkInfo.constraintType)
176
177 // real world coordinate of midpoint between the two objects
178 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
179
180 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
181 rootPrim.LocalID,
182 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
183 childPrim.LocalID, childPrim.PhysBody.AddrString,
184 rootPrim.Position, childPrim.Position, midPoint);
185
186 // create a constraint that allows no freedom of movement between the two objects
187 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
188
189 BSConstraint6Dof constrain = new BSConstraint6Dof(
190 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
191 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
192
193 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
194 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
195 * of the objects.
196 * Code left for future programmers.
197 // ==================================================================================
198 // relative position normalized to the root prim
199 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
200 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
201
202 // relative rotation of the child to the parent
203 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
204 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
205
206 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
207 BS6DofConstraint constrain = new BS6DofConstraint(
208 PhysicsScene.World, rootPrim.Body, childPrim.Body,
209 OMV.Vector3.Zero,
210 OMV.Quaternion.Inverse(rootPrim.Orientation),
211 OMV.Vector3.Zero,
212 OMV.Quaternion.Inverse(childPrim.Orientation),
213 true,
214 true
215 );
216 // ==================================================================================
217 */
218
219 PhysicsScene.Constraints.AddConstraint(constrain);
220
221 // zero linear and angular limits makes the objects unable to move in relation to each other
222 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
223 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
224
225 // tweek the constraint to increase stability
226 constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset);
227 constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor,
228 BSParam.LinkConstraintTransMotorMaxVel,
229 BSParam.LinkConstraintTransMotorMaxForce);
230 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
231 if (BSParam.LinkConstraintSolverIterations != 0f)
232 { 365 {
233 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); 366 case ConstraintType.FIXED_CONSTRAINT_TYPE:
367 case ConstraintType.D6_CONSTRAINT_TYPE:
368 // Relative position normalized to the root prim
369 // Essentually a vector pointing from center of rootPrim to center of li.member
370 OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
371
372 // real world coordinate of midpoint between the two objects
373 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
374
375 DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
376 rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
377 rootPrim.Position, linkInfo.member.Position, midPoint);
378
379 // create a constraint that allows no freedom of movement between the two objects
380 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
381
382 constrain = new BSConstraint6Dof(
383 m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
384
385 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
386 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
387 * of the objects.
388 * Code left for future programmers.
389 // ==================================================================================
390 // relative position normalized to the root prim
391 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
392 OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
393
394 // relative rotation of the child to the parent
395 OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
396 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
397
398 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
399 constrain = new BS6DofConstraint(
400 PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
401 OMV.Vector3.Zero,
402 OMV.Quaternion.Inverse(rootPrim.Orientation),
403 OMV.Vector3.Zero,
404 OMV.Quaternion.Inverse(liConstraint.member.Orientation),
405 true,
406 true
407 );
408 // ==================================================================================
409 */
410
411 break;
412 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
413 constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
414 linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
415 linkInfo.useLinearReferenceFrameA,
416 true /*disableCollisionsBetweenLinkedBodies*/);
417 DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
418 rootPrim.LocalID,
419 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
420 linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
421 rootPrim.Position, linkInfo.member.Position);
422
423 break;
424 default:
425 break;
234 } 426 }
427
428 linkInfo.SetLinkParameters(constrain);
429
430 m_physicsScene.Constraints.AddConstraint(constrain);
431
235 return constrain; 432 return constrain;
236 } 433 }
237 434
@@ -247,13 +444,22 @@ public sealed class BSLinksetConstraints : BSLinkset
247 rootPrim.LocalID, rootPrim.PhysBody.AddrString, 444 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
248 childPrim.LocalID, childPrim.PhysBody.AddrString); 445 childPrim.LocalID, childPrim.PhysBody.AddrString);
249 446
250 // Find the constraint for this link and get rid of it from the overall collection and from my list 447 // If asked to unlink root from root, just remove all the constraints
251 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) 448 if (rootPrim == childPrim || childPrim == LinksetRoot)
252 { 449 {
253 // Make the child refresh its location 450 PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
254 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
255 ret = true; 451 ret = true;
256 } 452 }
453 else
454 {
455 // Find the constraint for this link and get rid of it from the overall collection and from my list
456 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
457 {
458 // Make the child refresh its location
459 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
460 ret = true;
461 }
462 }
257 463
258 return ret; 464 return ret;
259 } 465 }
@@ -265,7 +471,7 @@ public sealed class BSLinksetConstraints : BSLinkset
265 { 471 {
266 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 472 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
267 473
268 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); 474 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
269 } 475 }
270 476
271 // Call each of the constraints that make up this linkset and recompute the 477 // Call each of the constraints that make up this linkset and recompute the
@@ -281,24 +487,360 @@ public sealed class BSLinksetConstraints : BSLinkset
281 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", 487 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
282 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); 488 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
283 489
284 foreach (BSPrimLinkable child in m_children) 490 try
285 { 491 {
286 // A child in the linkset physically shows the mass of the whole linkset. 492 Rebuilding = true;
287 // This allows Bullet to apply enough force on the child to move the whole linkset.
288 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
289 child.UpdatePhysicalMassProperties(linksetMass, true);
290 493
291 BSConstraint constrain; 494 // There is no reason to build all this physical stuff for a non-physical linkset.
292 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 495 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
293 { 496 {
294 // If constraint doesn't exist yet, create it. 497 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
295 constrain = BuildConstraint(LinksetRoot, child); 498 return; // Note the 'finally' clause at the botton which will get executed.
296 } 499 }
297 constrain.RecomputeConstraintVariables(linksetMass);
298 500
299 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG 501 ForEachLinkInfo((li) =>
502 {
503 // A child in the linkset physically shows the mass of the whole linkset.
504 // This allows Bullet to apply enough force on the child to move the whole linkset.
505 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
506 li.member.UpdatePhysicalMassProperties(linksetMass, true);
507
508 BSConstraint constrain;
509 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
510 {
511 // If constraint doesn't exist yet, create it.
512 constrain = BuildConstraint(LinksetRoot, li);
513 }
514 li.SetLinkParameters(constrain);
515 constrain.RecomputeConstraintVariables(linksetMass);
516
517 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
518 return false; // 'false' says to keep processing other members
519 });
300 } 520 }
521 finally
522 {
523 Rebuilding = false;
524 }
525 }
301 526
527 #region Extension
528 public override object Extension(string pFunct, params object[] pParams)
529 {
530 object ret = null;
531 switch (pFunct)
532 {
533 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
534 case ExtendedPhysics.PhysFunctChangeLinkType:
535 if (pParams.Length > 2)
536 {
537 int requestedType = (int)pParams[2];
538 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
539 if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE
540 || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
541 || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
542 || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
543 || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
544 || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
545 {
546 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
547 if (child != null)
548 {
549 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
550 LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
551 m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
552 {
553 // Pick up all the constraints currently created.
554 RemoveDependencies(child);
555
556 BSLinkInfo linkInfo = null;
557 if (TryGetLinkInfo(child, out linkInfo))
558 {
559 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
560 if (linkInfoC != null)
561 {
562 linkInfoC.constraintType = (ConstraintType)requestedType;
563 ret = (object)true;
564 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
565 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
566 }
567 else
568 {
569 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
570 }
571 }
572 else
573 {
574 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
575 }
576 // Cause the whole linkset to be rebuilt in post-taint time.
577 Refresh(child);
578 });
579 }
580 else
581 {
582 DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
583 }
584 }
585 else
586 {
587 DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
588 LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
589 }
590 }
591 break;
592 // pParams = [ BSPhysObject root, BSPhysObject child ]
593 case ExtendedPhysics.PhysFunctGetLinkType:
594 if (pParams.Length > 0)
595 {
596 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
597 if (child != null)
598 {
599 BSLinkInfo linkInfo = null;
600 if (TryGetLinkInfo(child, out linkInfo))
601 {
602 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
603 if (linkInfoC != null)
604 {
605 ret = (object)(int)linkInfoC.constraintType;
606 DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
607 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
608
609 }
610 }
611 }
612 }
613 break;
614 // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
615 case ExtendedPhysics.PhysFunctChangeLinkParams:
616 // There should be two parameters: the childActor and a list of parameters to set
617 if (pParams.Length > 2)
618 {
619 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
620 BSLinkInfo baseLinkInfo = null;
621 if (TryGetLinkInfo(child, out baseLinkInfo))
622 {
623 BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
624 if (linkInfo != null)
625 {
626 int valueInt;
627 float valueFloat;
628 bool valueBool;
629 OMV.Vector3 valueVector;
630 OMV.Vector3 valueVector2;
631 OMV.Quaternion valueQuaternion;
632 int axisLow, axisHigh;
633
634 int opIndex = 2;
635 while (opIndex < pParams.Length)
636 {
637 int thisOp = 0;
638 string errMsg = "";
639 try
640 {
641 thisOp = (int)pParams[opIndex];
642 DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
643 linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
644 switch (thisOp)
645 {
646 case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
647 valueInt = (int)pParams[opIndex + 1];
648 ConstraintType valueType = (ConstraintType)valueInt;
649 if (valueType == ConstraintType.FIXED_CONSTRAINT_TYPE
650 || valueType == ConstraintType.D6_CONSTRAINT_TYPE
651 || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
652 || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
653 || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
654 || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
655 {
656 linkInfo.constraintType = valueType;
657 }
658 opIndex += 2;
659 break;
660 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
661 errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
662 valueVector = (OMV.Vector3)pParams[opIndex + 1];
663 linkInfo.frameInAloc = valueVector;
664 opIndex += 2;
665 break;
666 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
667 errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
668 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
669 linkInfo.frameInArot = valueQuaternion;
670 opIndex += 2;
671 break;
672 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
673 errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
674 valueVector = (OMV.Vector3)pParams[opIndex + 1];
675 linkInfo.frameInBloc = valueVector;
676 opIndex += 2;
677 break;
678 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
679 errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
680 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
681 linkInfo.frameInBrot = valueQuaternion;
682 opIndex += 2;
683 break;
684 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
685 errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
686 valueVector = (OMV.Vector3)pParams[opIndex + 1];
687 linkInfo.linearLimitLow = valueVector;
688 opIndex += 2;
689 break;
690 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
691 errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
692 valueVector = (OMV.Vector3)pParams[opIndex + 1];
693 linkInfo.linearLimitHigh = valueVector;
694 opIndex += 2;
695 break;
696 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
697 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
698 valueVector = (OMV.Vector3)pParams[opIndex + 1];
699 linkInfo.angularLimitLow = valueVector;
700 opIndex += 2;
701 break;
702 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
703 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
704 valueVector = (OMV.Vector3)pParams[opIndex + 1];
705 linkInfo.angularLimitHigh = valueVector;
706 opIndex += 2;
707 break;
708 case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
709 errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
710 valueBool = ((int)pParams[opIndex + 1]) != 0;
711 linkInfo.useFrameOffset = valueBool;
712 opIndex += 2;
713 break;
714 case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
715 errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
716 valueBool = ((int)pParams[opIndex + 1]) != 0;
717 linkInfo.enableTransMotor = valueBool;
718 opIndex += 2;
719 break;
720 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
721 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
722 valueFloat = (float)pParams[opIndex + 1];
723 linkInfo.transMotorMaxVel = valueFloat;
724 opIndex += 2;
725 break;
726 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
727 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
728 valueFloat = (float)pParams[opIndex + 1];
729 linkInfo.transMotorMaxForce = valueFloat;
730 opIndex += 2;
731 break;
732 case ExtendedPhysics.PHYS_PARAM_CFM:
733 errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
734 valueFloat = (float)pParams[opIndex + 1];
735 linkInfo.cfm = valueFloat;
736 opIndex += 2;
737 break;
738 case ExtendedPhysics.PHYS_PARAM_ERP:
739 errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
740 valueFloat = (float)pParams[opIndex + 1];
741 linkInfo.erp = valueFloat;
742 opIndex += 2;
743 break;
744 case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
745 errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
746 valueFloat = (float)pParams[opIndex + 1];
747 linkInfo.solverIterations = valueFloat;
748 opIndex += 2;
749 break;
750 case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
751 errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
752 valueInt = (int)pParams[opIndex + 1];
753 valueBool = ((int)pParams[opIndex + 2]) != 0;
754 GetAxisRange(valueInt, out axisLow, out axisHigh);
755 for (int ii = axisLow; ii <= axisHigh; ii++)
756 linkInfo.springAxisEnable[ii] = valueBool;
757 opIndex += 3;
758 break;
759 case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
760 errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
761 valueInt = (int)pParams[opIndex + 1];
762 valueFloat = (float)pParams[opIndex + 2];
763 GetAxisRange(valueInt, out axisLow, out axisHigh);
764 for (int ii = axisLow; ii <= axisHigh; ii++)
765 linkInfo.springDamping[ii] = valueFloat;
766 opIndex += 3;
767 break;
768 case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
769 errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
770 valueInt = (int)pParams[opIndex + 1];
771 valueFloat = (float)pParams[opIndex + 2];
772 GetAxisRange(valueInt, out axisLow, out axisHigh);
773 for (int ii = axisLow; ii <= axisHigh; ii++)
774 linkInfo.springStiffness[ii] = valueFloat;
775 opIndex += 3;
776 break;
777 case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
778 errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
779 valueVector = (OMV.Vector3)pParams[opIndex + 1];
780 valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
781 linkInfo.springLinearEquilibriumPoint = valueVector;
782 linkInfo.springAngularEquilibriumPoint = valueVector2;
783 opIndex += 3;
784 break;
785 case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
786 errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
787 valueBool = ((int)pParams[opIndex + 1]) != 0;
788 linkInfo.useLinearReferenceFrameA = valueBool;
789 opIndex += 2;
790 break;
791 default:
792 break;
793 }
794 }
795 catch (InvalidCastException e)
796 {
797 m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
798 LogHeader, errMsg, e);
799 }
800 catch (Exception e)
801 {
802 m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
803 }
804 }
805 }
806 // Something changed so a rebuild is in order
807 Refresh(child);
808 }
809 }
810 break;
811 default:
812 ret = base.Extension(pFunct, pParams);
813 break;
814 }
815 return ret;
816 }
817
818 // Bullet constraints keep some limit parameters for each linear and angular axis.
819 // Setting same is easier if there is an easy way to see all or types.
820 // This routine returns the array limits for the set of axis.
821 private void GetAxisRange(int rangeSpec, out int low, out int high)
822 {
823 switch (rangeSpec)
824 {
825 case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
826 low = 0;
827 high = 2;
828 break;
829 case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
830 low = 3;
831 high = 5;
832 break;
833 case ExtendedPhysics.PHYS_AXIS_ALL:
834 low = 0;
835 high = 5;
836 break;
837 default:
838 low = high = rangeSpec;
839 break;
840 }
841 return;
302 } 842 }
843 #endregion // Extension
844
303} 845}
304} 846}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index 9501e2d..7693195 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -65,13 +65,11 @@ public abstract class BSMotor
65} 65}
66 66
67// Motor which moves CurrentValue to TargetValue over TimeScale seconds. 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68// The TargetValue decays in TargetValueDecayTimeScale and 68// The TargetValue decays in TargetValueDecayTimeScale.
69// the CurrentValue will be held back by FrictionTimeScale.
70// This motor will "zero itself" over time in that the targetValue will 69// This motor will "zero itself" over time in that the targetValue will
71// decay to zero and the currentValue will follow it to that zero. 70// decay to zero and the currentValue will follow it to that zero.
72// The overall effect is for the returned correction value to go from large 71// The overall effect is for the returned correction value to go from large
73// values (the total difference between current and target minus friction) 72// values to small and eventually zero values.
74// to small and eventually zero values.
75// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. 73// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
76 74
77// For instance, if something is moving at speed X and the desired speed is Y, 75// For instance, if something is moving at speed X and the desired speed is Y,
@@ -88,7 +86,6 @@ public class BSVMotor : BSMotor
88 86
89 public virtual float TimeScale { get; set; } 87 public virtual float TimeScale { get; set; }
90 public virtual float TargetValueDecayTimeScale { get; set; } 88 public virtual float TargetValueDecayTimeScale { get; set; }
91 public virtual Vector3 FrictionTimescale { get; set; }
92 public virtual float Efficiency { get; set; } 89 public virtual float Efficiency { get; set; }
93 90
94 public virtual float ErrorZeroThreshold { get; set; } 91 public virtual float ErrorZeroThreshold { get; set; }
@@ -102,7 +99,7 @@ public class BSVMotor : BSMotor
102 return ErrorIsZero(LastError); 99 return ErrorIsZero(LastError);
103 } 100 }
104 public virtual bool ErrorIsZero(Vector3 err) 101 public virtual bool ErrorIsZero(Vector3 err)
105 { 102 {
106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); 103 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 } 104 }
108 105
@@ -111,16 +108,14 @@ public class BSVMotor : BSMotor
111 { 108 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; 109 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f; 110 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero; 111 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f; 112 ErrorZeroThreshold = 0.001f;
117 } 113 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 114 public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
119 : this(useName) 115 : this(useName)
120 { 116 {
121 TimeScale = timeScale; 117 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale; 118 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency; 119 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero; 120 CurrentValue = TargetValue = Vector3.Zero;
126 } 121 }
@@ -149,7 +144,6 @@ public class BSVMotor : BSMotor
149 144
150 Vector3 correction = Vector3.Zero; 145 Vector3 correction = Vector3.Zero;
151 Vector3 error = TargetValue - CurrentValue; 146 Vector3 error = TargetValue - CurrentValue;
152 LastError = error;
153 if (!ErrorIsZero(error)) 147 if (!ErrorIsZero(error))
154 { 148 {
155 correction = StepError(timeStep, error); 149 correction = StepError(timeStep, error);
@@ -165,26 +159,11 @@ public class BSVMotor : BSMotor
165 TargetValue *= (1f - decayFactor); 159 TargetValue *= (1f - decayFactor);
166 } 160 }
167 161
168 // The amount we can correct the error is reduced by the friction
169 Vector3 frictionFactor = Vector3.Zero;
170 if (FrictionTimescale != BSMotor.InfiniteVector)
171 {
172 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
173 // Individual friction components can be 'infinite' so compute each separately.
174 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
175 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
176 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
177 frictionFactor *= timeStep;
178 CurrentValue *= (Vector3.One - frictionFactor);
179 }
180
181 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", 162 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
182 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 163 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
183 timeStep, error, correction); 164 timeStep, error, correction);
184 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 165 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
185 BSScene.DetailLogZero, UseName, 166 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
186 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
187 TargetValue, CurrentValue);
188 } 167 }
189 else 168 else
190 { 169 {
@@ -199,6 +178,7 @@ public class BSVMotor : BSMotor
199 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", 178 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
200 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); 179 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
201 } 180 }
181 LastError = error;
202 182
203 return correction; 183 return correction;
204 } 184 }
@@ -208,6 +188,8 @@ public class BSVMotor : BSMotor
208 CurrentValue = current; 188 CurrentValue = current;
209 return Step(timeStep); 189 return Step(timeStep);
210 } 190 }
191 // Given and error, computer a correction for this step.
192 // Simple scaling of the error by the timestep.
211 public virtual Vector3 StepError(float timeStep, Vector3 error) 193 public virtual Vector3 StepError(float timeStep, Vector3 error)
212 { 194 {
213 if (!Enabled) return Vector3.Zero; 195 if (!Enabled) return Vector3.Zero;
@@ -235,27 +217,27 @@ public class BSVMotor : BSMotor
235 // maximum number of outputs to generate. 217 // maximum number of outputs to generate.
236 int maxOutput = 50; 218 int maxOutput = 50;
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); 219 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
238 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}", 220 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
239 BSScene.DetailLogZero, UseName, 221 BSScene.DetailLogZero, UseName,
240 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 222 TimeScale, TargetValueDecayTimeScale, Efficiency,
241 CurrentValue, TargetValue); 223 CurrentValue, TargetValue);
242 224
243 LastError = BSMotor.InfiniteVector; 225 LastError = BSMotor.InfiniteVector;
244 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 226 while (maxOutput-- > 0 && !ErrorIsZero())
245 { 227 {
246 Vector3 lastStep = Step(timeStep); 228 Vector3 lastStep = Step(timeStep);
247 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", 229 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
248 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); 230 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
249 } 231 }
250 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); 232 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
251 233
252 234
253 } 235 }
254 236
255 public override string ToString() 237 public override string ToString()
256 { 238 {
257 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 239 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
258 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 240 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
259 } 241 }
260} 242}
261 243
@@ -265,7 +247,6 @@ public class BSFMotor : BSMotor
265{ 247{
266 public virtual float TimeScale { get; set; } 248 public virtual float TimeScale { get; set; }
267 public virtual float TargetValueDecayTimeScale { get; set; } 249 public virtual float TargetValueDecayTimeScale { get; set; }
268 public virtual float FrictionTimescale { get; set; }
269 public virtual float Efficiency { get; set; } 250 public virtual float Efficiency { get; set; }
270 251
271 public virtual float ErrorZeroThreshold { get; set; } 252 public virtual float ErrorZeroThreshold { get; set; }
@@ -279,16 +260,15 @@ public class BSFMotor : BSMotor
279 return ErrorIsZero(LastError); 260 return ErrorIsZero(LastError);
280 } 261 }
281 public virtual bool ErrorIsZero(float err) 262 public virtual bool ErrorIsZero(float err)
282 { 263 {
283 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); 264 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
284 } 265 }
285 266
286 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) 267 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
287 : base(useName) 268 : base(useName)
288 { 269 {
289 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; 270 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
290 Efficiency = 1f; 271 Efficiency = 1f;
291 FrictionTimescale = BSMotor.Infinite;
292 CurrentValue = TargetValue = 0f; 272 CurrentValue = TargetValue = 0f;
293 ErrorZeroThreshold = 0.01f; 273 ErrorZeroThreshold = 0.01f;
294 } 274 }
@@ -315,7 +295,6 @@ public class BSFMotor : BSMotor
315 295
316 float correction = 0f; 296 float correction = 0f;
317 float error = TargetValue - CurrentValue; 297 float error = TargetValue - CurrentValue;
318 LastError = error;
319 if (!ErrorIsZero(error)) 298 if (!ErrorIsZero(error))
320 { 299 {
321 correction = StepError(timeStep, error); 300 correction = StepError(timeStep, error);
@@ -331,24 +310,11 @@ public class BSFMotor : BSMotor
331 TargetValue *= (1f - decayFactor); 310 TargetValue *= (1f - decayFactor);
332 } 311 }
333 312
334 // The amount we can correct the error is reduced by the friction
335 float frictionFactor = 0f;
336 if (FrictionTimescale != BSMotor.Infinite)
337 {
338 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
339 // Individual friction components can be 'infinite' so compute each separately.
340 frictionFactor = 1f / FrictionTimescale;
341 frictionFactor *= timeStep;
342 CurrentValue *= (1f - frictionFactor);
343 }
344
345 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", 313 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
346 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 314 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
347 timeStep, error, correction); 315 timeStep, error, correction);
348 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 316 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
349 BSScene.DetailLogZero, UseName, 317 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
350 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
351 TargetValue, CurrentValue);
352 } 318 }
353 else 319 else
354 { 320 {
@@ -363,6 +329,7 @@ public class BSFMotor : BSMotor
363 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", 329 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
364 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); 330 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
365 } 331 }
332 LastError = error;
366 333
367 return CurrentValue; 334 return CurrentValue;
368 } 335 }
@@ -390,15 +357,15 @@ public class BSFMotor : BSMotor
390 357
391 public override string ToString() 358 public override string ToString()
392 { 359 {
393 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 360 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
394 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 361 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
395 } 362 }
396 363
397} 364}
398 365
399// ============================================================================ 366// ============================================================================
400// ============================================================================ 367// ============================================================================
401// Proportional, Integral, Derivitive Motor 368// Proportional, Integral, Derivitive ("PID") Motor
402// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. 369// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
403public class BSPIDVMotor : BSVMotor 370public class BSPIDVMotor : BSVMotor
404{ 371{
@@ -410,7 +377,6 @@ public class BSPIDVMotor : BSVMotor
410 // The factors are vectors for the three dimensions. This is the proportional of each 377 // The factors are vectors for the three dimensions. This is the proportional of each
411 // that is applied. This could be multiplied through the actual factors but it 378 // that is applied. This could be multiplied through the actual factors but it
412 // is sometimes easier to manipulate the factors and their mix separately. 379 // is sometimes easier to manipulate the factors and their mix separately.
413 // to
414 public Vector3 FactorMix; 380 public Vector3 FactorMix;
415 381
416 // Arbritrary factor range. 382 // Arbritrary factor range.
@@ -448,14 +414,14 @@ public class BSPIDVMotor : BSVMotor
448 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. 414 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
449 // If efficiency is low (0f), use a factor value that overcorrects. 415 // If efficiency is low (0f), use a factor value that overcorrects.
450 // TODO: might want to vary contribution of different factor depending on efficiency. 416 // TODO: might want to vary contribution of different factor depending on efficiency.
451 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; 417 // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
452 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; 418 float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
453 419
454 proportionFactor = new Vector3(factor, factor, factor); 420 proportionFactor = new Vector3(factor, factor, factor);
455 integralFactor = new Vector3(factor, factor, factor); 421 integralFactor = new Vector3(factor, factor, factor);
456 derivFactor = new Vector3(factor, factor, factor); 422 derivFactor = new Vector3(factor, factor, factor);
457 423
458 MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); 424 MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
459 } 425 }
460 } 426 }
461 427
@@ -469,16 +435,15 @@ public class BSPIDVMotor : BSVMotor
469 435
470 // A simple derivitive is the rate of change from the last error. 436 // A simple derivitive is the rate of change from the last error.
471 Vector3 derivitive = (error - LastError) * timeStep; 437 Vector3 derivitive = (error - LastError) * timeStep;
472 LastError = error;
473 438
474 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) 439 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
475 Vector3 ret = error * timeStep * proportionFactor * FactorMix.X 440 Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X
476 + RunningIntegration * integralFactor * FactorMix.Y 441 + RunningIntegration / TimeScale * integralFactor * FactorMix.Y
477 + derivitive * derivFactor * FactorMix.Z 442 + derivitive / TimeScale * derivFactor * FactorMix.Z
478 ; 443 ;
479 444
480 MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", 445 MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
481 BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); 446 BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
482 447
483 return ret; 448 return ret;
484 } 449 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
index 385ed9e..834228e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Text; 30using System.Text;
30 31
31using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
@@ -37,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
37{ 38{
38public static class BSParam 39public static class BSParam
39{ 40{
40 private static string LogHeader = "[BULLETSIM PARAMETERS]"; 41 private static string LogHeader = "[BULLETSIM PARAMETERS]";
41 42
42 // Tuning notes: 43 // Tuning notes:
43 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 44 // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
@@ -51,7 +52,10 @@ public static class BSParam
51 // This is separate/independent from the collision margin. The collision margin increases the object a bit 52 // This is separate/independent from the collision margin. The collision margin increases the object a bit
52 // to improve collision detection performance and accuracy. 53 // to improve collision detection performance and accuracy.
53 // =================== 54 // ===================
54 // From: 55 // From:
56
57 public static bool UseSeparatePhysicsThread { get; private set; }
58 public static float PhysicsTimeStep { get; private set; }
55 59
56 // Level of Detail values kept as float because that's what the Meshmerizer wants 60 // Level of Detail values kept as float because that's what the Meshmerizer wants
57 public static float MeshLOD { get; private set; } 61 public static float MeshLOD { get; private set; }
@@ -86,8 +90,12 @@ public static class BSParam
86 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes 90 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
87 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects 91 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
88 public static bool ShouldRemoveZeroWidthTriangles { get; private set; } 92 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
93 public static bool ShouldUseBulletHACD { get; set; }
94 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
95 public static bool ShouldUseGImpactShapeForPrims { get; set; }
96 public static bool ShouldUseAssetHulls { get; set; }
89 97
90 public static float TerrainImplementation { get; private set; } 98 public static float TerrainImplementation { get; set; }
91 public static int TerrainMeshMagnification { get; private set; } 99 public static int TerrainMeshMagnification { get; private set; }
92 public static float TerrainFriction { get; private set; } 100 public static float TerrainFriction { get; private set; }
93 public static float TerrainHitFraction { get; private set; } 101 public static float TerrainHitFraction { get; private set; }
@@ -112,6 +120,7 @@ public static class BSParam
112 public static float NumberOfSolverIterations { get; private set; } 120 public static float NumberOfSolverIterations { get; private set; }
113 public static bool UseSingleSidedMeshes { get; private set; } 121 public static bool UseSingleSidedMeshes { get; private set; }
114 public static float GlobalContactBreakingThreshold { get; private set; } 122 public static float GlobalContactBreakingThreshold { get; private set; }
123 public static float PhysicsUnmanLoggingFrames { get; private set; }
115 124
116 // Avatar parameters 125 // Avatar parameters
117 public static float AvatarFriction { get; private set; } 126 public static float AvatarFriction { get; private set; }
@@ -122,11 +131,18 @@ public static class BSParam
122 public static float AvatarCapsuleWidth { get; private set; } 131 public static float AvatarCapsuleWidth { get; private set; }
123 public static float AvatarCapsuleDepth { get; private set; } 132 public static float AvatarCapsuleDepth { get; private set; }
124 public static float AvatarCapsuleHeight { get; private set; } 133 public static float AvatarCapsuleHeight { get; private set; }
134 public static float AvatarHeightLowFudge { get; private set; }
135 public static float AvatarHeightMidFudge { get; private set; }
136 public static float AvatarHeightHighFudge { get; private set; }
125 public static float AvatarContactProcessingThreshold { get; private set; } 137 public static float AvatarContactProcessingThreshold { get; private set; }
138 public static float AvatarStopZeroThreshold { get; private set; }
139 public static int AvatarJumpFrames { get; private set; }
126 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } 140 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
127 public static float AvatarStepHeight { get; private set; } 141 public static float AvatarStepHeight { get; private set; }
128 public static float AvatarStepApproachFactor { get; private set; } 142 public static float AvatarStepApproachFactor { get; private set; }
129 public static float AvatarStepForceFactor { get; private set; } 143 public static float AvatarStepForceFactor { get; private set; }
144 public static float AvatarStepUpCorrectionFactor { get; private set; }
145 public static int AvatarStepSmoothingSteps { get; private set; }
130 146
131 // Vehicle parameters 147 // Vehicle parameters
132 public static float VehicleMaxLinearVelocity { get; private set; } 148 public static float VehicleMaxLinearVelocity { get; private set; }
@@ -138,9 +154,15 @@ public static class BSParam
138 public static float VehicleRestitution { get; private set; } 154 public static float VehicleRestitution { get; private set; }
139 public static Vector3 VehicleLinearFactor { get; private set; } 155 public static Vector3 VehicleLinearFactor { get; private set; }
140 public static Vector3 VehicleAngularFactor { get; private set; } 156 public static Vector3 VehicleAngularFactor { get; private set; }
157 public static Vector3 VehicleInertiaFactor { get; private set; }
141 public static float VehicleGroundGravityFudge { get; private set; } 158 public static float VehicleGroundGravityFudge { get; private set; }
142 public static float VehicleAngularBankingTimescaleFudge { get; private set; } 159 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
143 public static bool VehicleDebuggingEnabled { get; private set; } 160 public static bool VehicleEnableLinearDeflection { get; private set; }
161 public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; }
162 public static bool VehicleEnableAngularVerticalAttraction { get; private set; }
163 public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; }
164 public static bool VehicleEnableAngularDeflection { get; private set; }
165 public static bool VehicleEnableAngularBanking { get; private set; }
144 166
145 // Convex Hulls 167 // Convex Hulls
146 public static int CSHullMaxDepthSplit { get; private set; } 168 public static int CSHullMaxDepthSplit { get; private set; }
@@ -149,9 +171,19 @@ public static class BSParam
149 public static float CSHullVolumeConservationThresholdPercent { get; private set; } 171 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
150 public static int CSHullMaxVertices { get; private set; } 172 public static int CSHullMaxVertices { get; private set; }
151 public static float CSHullMaxSkinWidth { get; private set; } 173 public static float CSHullMaxSkinWidth { get; private set; }
174 public static float BHullMaxVerticesPerHull { get; private set; } // 100
175 public static float BHullMinClusters { get; private set; } // 2
176 public static float BHullCompacityWeight { get; private set; } // 0.1
177 public static float BHullVolumeWeight { get; private set; } // 0.0
178 public static float BHullConcavity { get; private set; } // 100
179 public static bool BHullAddExtraDistPoints { get; private set; } // false
180 public static bool BHullAddNeighboursDistPoints { get; private set; } // false
181 public static bool BHullAddFacesPoints { get; private set; } // false
182 public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
152 183
153 // Linkset implementation parameters 184 // Linkset implementation parameters
154 public static float LinksetImplementation { get; private set; } 185 public static float LinksetImplementation { get; private set; }
186 public static bool LinksetOffsetCenterOfMass { get; private set; }
155 public static bool LinkConstraintUseFrameOffset { get; private set; } 187 public static bool LinkConstraintUseFrameOffset { get; private set; }
156 public static bool LinkConstraintEnableTransMotor { get; private set; } 188 public static bool LinkConstraintEnableTransMotor { get; private set; }
157 public static float LinkConstraintTransMotorMaxVel { get; private set; } 189 public static float LinkConstraintTransMotorMaxVel { get; private set; }
@@ -223,16 +255,41 @@ public static class BSParam
223 getter = pGetter; 255 getter = pGetter;
224 objectSet = pObjSetter; 256 objectSet = pObjSetter;
225 } 257 }
226 /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work 258 // Simple parameter variable where property name is the same as the INI file name
227 public ParameterDefn(string pName, string pDesc, T pDefault, ref T loc) 259 // and the value is only a simple get and set.
260 public ParameterDefn(string pName, string pDesc, T pDefault)
228 : base(pName, pDesc) 261 : base(pName, pDesc)
229 { 262 {
230 defaultValue = pDefault; 263 defaultValue = pDefault;
231 setter = (s, v) => { loc = v; }; 264 setter = (s, v) => { SetValueByName(s, name, v); };
232 getter = (s) => { return loc; }; 265 getter = (s) => { return GetValueByName(s, name); };
233 objectSet = null; 266 objectSet = null;
234 } 267 }
235 */ 268 // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
269 private void SetValueByName(BSScene s, string pName, T val)
270 {
271 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
272 if (prop == null)
273 {
274 // This should only be output when someone adds a new INI parameter and misspells the name.
275 s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
276 }
277 else
278 {
279 prop.SetValue(null, val, null);
280 }
281 }
282 // Use reflection to find the property named 'pName' in BSParam and return the value in same.
283 private T GetValueByName(BSScene s, string pName)
284 {
285 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
286 if (prop == null)
287 {
288 // This should only be output when someone adds a new INI parameter and misspells the name.
289 s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
290 }
291 return (T)prop.GetValue(null, null);
292 }
236 public override void AssignDefault(BSScene s) 293 public override void AssignDefault(BSScene s)
237 { 294 {
238 setter(s, defaultValue); 295 setter(s, defaultValue);
@@ -309,6 +366,11 @@ public static class BSParam
309 // v = value (appropriate type) 366 // v = value (appropriate type)
310 private static ParameterDefnBase[] ParameterDefinitions = 367 private static ParameterDefnBase[] ParameterDefinitions =
311 { 368 {
369 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
370 false ),
371 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
372 0.089f ),
373
312 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", 374 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
313 true, 375 true,
314 (s) => { return ShouldMeshSculptedPrim; }, 376 (s) => { return ShouldMeshSculptedPrim; },
@@ -322,18 +384,20 @@ public static class BSParam
322 (s) => { return ShouldUseHullsForPhysicalObjects; }, 384 (s) => { return ShouldUseHullsForPhysicalObjects; },
323 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), 385 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
324 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", 386 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
325 true, 387 true ),
326 (s) => { return ShouldRemoveZeroWidthTriangles; }, 388 new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
327 (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), 389 false ),
390 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
391 true ),
392 new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
393 false ),
394 new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
395 true ),
328 396
329 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", 397 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
330 5, 398 5 ),
331 (s) => { return CrossingFailuresBeforeOutOfBounds; },
332 (s,v) => { CrossingFailuresBeforeOutOfBounds = v; } ),
333 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", 399 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
334 0.1f, 400 0.1f ),
335 (s) => { return UpdateVelocityChangeThreshold; },
336 (s,v) => { UpdateVelocityChangeThreshold = v; } ),
337 401
338 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 402 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
339 32f, 403 32f,
@@ -399,26 +463,22 @@ public static class BSParam
399 (s) => { return MaxAddForceMagnitude; }, 463 (s) => { return MaxAddForceMagnitude; },
400 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), 464 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
401 // Density is passed around as 100kg/m3. This scales that to 1kg/m3. 465 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
466 // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
402 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", 467 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
403 0.01f, 468 0.01f ),
404 (s) => { return DensityScaleFactor; },
405 (s,v) => { DensityScaleFactor = v; } ),
406 469
407 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", 470 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
408 2200f, 471 2200f ),
409 (s) => { return (float)PID_D; },
410 (s,v) => { PID_D = v; } ),
411 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", 472 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
412 900f, 473 900f ),
413 (s) => { return (float)PID_P; },
414 (s,v) => { PID_P = v; } ),
415 474
416 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", 475 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
417 0.2f, 476 0.2f,
418 (s) => { return DefaultFriction; }, 477 (s) => { return DefaultFriction; },
419 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), 478 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
479 // For historical reasons, the viewer and simulator multiply the density by 100
420 new ParameterDefn<float>("DefaultDensity", "Density for new objects" , 480 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
421 10.000006836f, // Aluminum g/cm3 481 1000.0006836f, // Aluminum g/cm3 * 100
422 (s) => { return DefaultDensity; }, 482 (s) => { return DefaultDensity; },
423 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), 483 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
424 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , 484 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
@@ -478,86 +538,61 @@ public static class BSParam
478 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), 538 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
479 539
480 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", 540 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
481 (float)BSTerrainPhys.TerrainImplementation.Mesh, 541 (float)BSTerrainPhys.TerrainImplementation.Mesh ),
482 (s) => { return TerrainImplementation; },
483 (s,v) => { TerrainImplementation = v; } ),
484 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , 542 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
485 2, 543 2 ),
486 (s) => { return TerrainMeshMagnification; },
487 (s,v) => { TerrainMeshMagnification = v; } ),
488 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , 544 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
489 0.3f, 545 0.3f ),
490 (s) => { return TerrainFriction; },
491 (s,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
492 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , 546 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
493 0.8f, 547 0.8f ),
494 (s) => { return TerrainHitFraction; },
495 (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
496 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , 548 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
497 0f, 549 0f ),
498 (s) => { return TerrainRestitution; },
499 (s,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
500 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , 550 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
501 0.0f, 551 0.0f ),
502 (s) => { return TerrainContactProcessingThreshold; },
503 (s,v) => { TerrainContactProcessingThreshold = v; /* TODO: set on real terrain */ } ),
504 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , 552 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
505 0.08f, 553 0.08f ),
506 (s) => { return TerrainCollisionMargin; },
507 (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
508 554
509 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 555 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
510 0.2f, 556 0.2f ),
511 (s) => { return AvatarFriction; },
512 (s,v) => { AvatarFriction = v; } ),
513 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", 557 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
514 0.95f, 558 0.95f ),
515 (s) => { return AvatarStandingFriction; },
516 (s,v) => { AvatarStandingFriction = v; } ),
517 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", 559 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
518 1.3f, 560 1.3f ),
519 (s) => { return AvatarAlwaysRunFactor; }, 561 // For historical reasons, density is reported * 100
520 (s,v) => { AvatarAlwaysRunFactor = v; } ), 562 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
521 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 563 3500f) , // 3.5 * 100
522 3.5f,
523 (s) => { return AvatarDensity; },
524 (s,v) => { AvatarDensity = v; } ),
525 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 564 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
526 0f, 565 0f ),
527 (s) => { return AvatarRestitution; },
528 (s,v) => { AvatarRestitution = v; } ),
529 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", 566 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
530 0.6f, 567 0.6f ) ,
531 (s) => { return AvatarCapsuleWidth; },
532 (s,v) => { AvatarCapsuleWidth = v; } ),
533 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", 568 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
534 0.45f, 569 0.45f ),
535 (s) => { return AvatarCapsuleDepth; },
536 (s,v) => { AvatarCapsuleDepth = v; } ),
537 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", 570 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
538 1.5f, 571 1.5f ),
539 (s) => { return AvatarCapsuleHeight; }, 572 new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
540 (s,v) => { AvatarCapsuleHeight = v; } ), 573 -0.2f ),
574 new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
575 0.1f ),
576 new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
577 0.1f ),
541 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 578 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
542 0.1f, 579 0.1f ),
543 (s) => { return AvatarContactProcessingThreshold; }, 580 new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
544 (s,v) => { AvatarContactProcessingThreshold = v; } ), 581 0.1f ),
545 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", 582 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
546 1.0f, 583 1.0f ),
547 (s) => { return AvatarBelowGroundUpCorrectionMeters; }, 584 new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
548 (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), 585 4 ),
549 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", 586 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
550 0.3f, 587 0.6f ) ,
551 (s) => { return AvatarStepHeight; },
552 (s,v) => { AvatarStepHeight = v; } ),
553 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", 588 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
554 0.6f, 589 0.6f ),
555 (s) => { return AvatarStepApproachFactor; },
556 (s,v) => { AvatarStepApproachFactor = v; } ),
557 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", 590 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
558 2.0f, 591 1.0f ),
559 (s) => { return AvatarStepForceFactor; }, 592 new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
560 (s,v) => { AvatarStepForceFactor = v; } ), 593 1.0f ),
594 new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
595 2 ),
561 596
562 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", 597 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
563 1000.0f, 598 1000.0f,
@@ -568,37 +603,33 @@ public static class BSParam
568 (s) => { return (float)VehicleMaxAngularVelocity; }, 603 (s) => { return (float)VehicleMaxAngularVelocity; },
569 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), 604 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
570 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", 605 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
571 0.0f, 606 0.0f ),
572 (s) => { return VehicleAngularDamping; },
573 (s,v) => { VehicleAngularDamping = v; } ),
574 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", 607 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
575 new Vector3(1f, 1f, 1f), 608 new Vector3(1f, 1f, 1f) ),
576 (s) => { return VehicleLinearFactor; },
577 (s,v) => { VehicleLinearFactor = v; } ),
578 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", 609 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
579 new Vector3(1f, 1f, 1f), 610 new Vector3(1f, 1f, 1f) ),
580 (s) => { return VehicleAngularFactor; }, 611 new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
581 (s,v) => { VehicleAngularFactor = v; } ), 612 new Vector3(1f, 1f, 1f) ),
582 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", 613 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
583 0.0f, 614 0.0f ),
584 (s) => { return VehicleFriction; },
585 (s,v) => { VehicleFriction = v; } ),
586 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", 615 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
587 0.0f, 616 0.0f ),
588 (s) => { return VehicleRestitution; },
589 (s,v) => { VehicleRestitution = v; } ),
590 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", 617 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
591 0.2f, 618 0.2f ),
592 (s) => { return VehicleGroundGravityFudge; },
593 (s,v) => { VehicleGroundGravityFudge = v; } ),
594 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", 619 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
595 60.0f, 620 60.0f ),
596 (s) => { return VehicleAngularBankingTimescaleFudge; }, 621 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
597 (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), 622 true ),
598 new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", 623 new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles",
599 false, 624 true ),
600 (s) => { return VehicleDebuggingEnabled; }, 625 new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect",
601 (s,v) => { VehicleDebuggingEnabled = v; } ), 626 true ),
627 new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.",
628 0 ),
629 new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect",
630 true ),
631 new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect",
632 true ),
602 633
603 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 634 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
604 0f, 635 0f,
@@ -611,7 +642,7 @@ public static class BSParam
611 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", 642 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
612 false, 643 false,
613 (s) => { return ShouldDisableContactPoolDynamicAllocation; }, 644 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
614 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; 645 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
615 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), 646 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
616 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", 647 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
617 false, 648 false,
@@ -641,64 +672,61 @@ public static class BSParam
641 0f, 672 0f,
642 (s) => { return GlobalContactBreakingThreshold; }, 673 (s) => { return GlobalContactBreakingThreshold; },
643 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), 674 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
675 new ParameterDefn<float>("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics",
676 0f,
677 (s) => { return PhysicsUnmanLoggingFrames; },
678 (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ),
644 679
645 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", 680 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
646 7, 681 7 ),
647 (s) => { return CSHullMaxDepthSplit; },
648 (s,v) => { CSHullMaxDepthSplit = v; } ),
649 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", 682 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
650 2, 683 2 ),
651 (s) => { return CSHullMaxDepthSplitForSimpleShapes; },
652 (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ),
653 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", 684 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
654 5f, 685 5f ),
655 (s) => { return CSHullConcavityThresholdPercent; },
656 (s,v) => { CSHullConcavityThresholdPercent = v; } ),
657 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", 686 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
658 5f, 687 5f ),
659 (s) => { return CSHullVolumeConservationThresholdPercent; },
660 (s,v) => { CSHullVolumeConservationThresholdPercent = v; } ),
661 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", 688 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
662 32, 689 32 ),
663 (s) => { return CSHullMaxVertices; },
664 (s,v) => { CSHullMaxVertices = v; } ),
665 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", 690 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
666 0, 691 0f ),
667 (s) => { return CSHullMaxSkinWidth; }, 692
668 (s,v) => { CSHullMaxSkinWidth = v; } ), 693 new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
694 200f ),
695 new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
696 10f ),
697 new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
698 20f ),
699 new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
700 0.1f ),
701 new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
702 10f ),
703 new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
704 true ),
705 new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
706 true ),
707 new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
708 true ),
709 new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
710 false ),
669 711
670 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", 712 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
671 (float)BSLinkset.LinksetImplementation.Compound, 713 (float)BSLinkset.LinksetImplementation.Compound ),
672 (s) => { return LinksetImplementation; }, 714 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
673 (s,v) => { LinksetImplementation = v; } ), 715 true ),
674 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 716 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
675 false, 717 false ),
676 (s) => { return LinkConstraintUseFrameOffset; },
677 (s,v) => { LinkConstraintUseFrameOffset = v; } ),
678 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", 718 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
679 true, 719 true ),
680 (s) => { return LinkConstraintEnableTransMotor; },
681 (s,v) => { LinkConstraintEnableTransMotor = v; } ),
682 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", 720 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
683 5.0f, 721 5.0f ),
684 (s) => { return LinkConstraintTransMotorMaxVel; },
685 (s,v) => { LinkConstraintTransMotorMaxVel = v; } ),
686 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", 722 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
687 0.1f, 723 0.1f ),
688 (s) => { return LinkConstraintTransMotorMaxForce; },
689 (s,v) => { LinkConstraintTransMotorMaxForce = v; } ),
690 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 724 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
691 0.1f, 725 0.1f ),
692 (s) => { return LinkConstraintCFM; },
693 (s,v) => { LinkConstraintCFM = v; } ),
694 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 726 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
695 0.1f, 727 0.1f ),
696 (s) => { return LinkConstraintERP; },
697 (s,v) => { LinkConstraintERP = v; } ),
698 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", 728 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
699 40, 729 40 ),
700 (s) => { return LinkConstraintSolverIterations; },
701 (s,v) => { LinkConstraintSolverIterations = v; } ),
702 730
703 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", 731 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
704 0, 732 0,
@@ -707,7 +735,7 @@ public static class BSParam
707 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", 735 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
708 0f, 736 0f,
709 (s) => { return 0f; }, 737 (s) => { return 0f; },
710 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), 738 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ),
711 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", 739 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
712 0f, 740 0f,
713 (s) => { return 0f; }, 741 (s) => { return 0f; },
@@ -793,10 +821,10 @@ public static class BSParam
793 // ===================================================================== 821 // =====================================================================
794 // There are parameters that, when set, cause things to happen in the physics engine. 822 // There are parameters that, when set, cause things to happen in the physics engine.
795 // This causes the broadphase collision cache to be cleared. 823 // This causes the broadphase collision cache to be cleared.
796 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) 824 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime)
797 { 825 {
798 BSScene physScene = pPhysScene; 826 BSScene physScene = pPhysScene;
799 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() 827 physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate()
800 { 828 {
801 physScene.PE.ResetBroadphasePool(physScene.World); 829 physScene.PE.ResetBroadphasePool(physScene.World);
802 }); 830 });
@@ -806,7 +834,7 @@ public static class BSParam
806 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) 834 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
807 { 835 {
808 BSScene physScene = pPhysScene; 836 BSScene physScene = pPhysScene;
809 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() 837 physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
810 { 838 {
811 physScene.PE.ResetConstraintSolver(physScene.World); 839 physScene.PE.ResetConstraintSolver(physScene.World);
812 }); 840 });
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 98ea833..f89b376 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -38,12 +38,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
38 * Class to wrap all objects. 38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims 39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant. 40 * unless the difference is significant.
41 * 41 *
42 * Variables in the physicsl objects are in three forms: 42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc 43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value 44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time. 46 * The last one should only be referenced in taint-time.
47 */ 47 */
48 48
49/* 49/*
@@ -52,7 +52,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce 52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse 53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v 54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque 55 * BS.ApplyCentralForce BS.ApplyTorque
56 */ 56 */
57 57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. 58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
@@ -72,22 +72,27 @@ public abstract class BSPhysObject : PhysicsActor
72 } 72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) 73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 { 74 {
75 PhysicsScene = parentScene; 75 IsInitialized = false;
76
77 PhysScene = parentScene;
76 LocalID = localID; 78 LocalID = localID;
77 PhysObjectName = name; 79 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate. 80 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
79 TypeName = typeName; 81 TypeName = typeName;
80 82
81 // The collection of things that push me around 83 // The collection of things that push me around
82 PhysicalActors = new BSActorCollection(PhysicsScene); 84 PhysicalActors = new BSActorCollection(PhysScene);
83 85
84 // Initialize variables kept in base. 86 // Initialize variables kept in base.
85 GravModifier = 1.0f; 87 GravModifier = 1.0f;
86 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); 88 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
89 HoverActive = false;
87 90
88 // We don't have any physical representation yet. 91 // We don't have any physical representation yet.
89 PhysBody = new BulletBody(localID); 92 PhysBody = new BulletBody(localID);
90 PhysShape = new BulletShape(); 93 PhysShape = new BSShapeNull();
94
95 UserSetCenterOfMassDisplacement = null;
91 96
92 PrimAssetState = PrimAssetCondition.Unknown; 97 PrimAssetState = PrimAssetCondition.Unknown;
93 98
@@ -95,34 +100,41 @@ public abstract class BSPhysObject : PhysicsActor
95 SetMaterial((int)MaterialAttributes.Material.Wood); 100 SetMaterial((int)MaterialAttributes.Material.Wood);
96 101
97 CollisionCollection = new CollisionEventUpdate(); 102 CollisionCollection = new CollisionEventUpdate();
98 CollisionsLastTick = CollisionCollection; 103 CollisionsLastReported = CollisionCollection;
104 CollisionsLastTick = new CollisionEventUpdate();
105 CollisionsLastTickStep = -1;
106
99 SubscribedEventsMs = 0; 107 SubscribedEventsMs = 0;
100 CollidingStep = 0; 108 // Crazy values that will never be true
101 CollidingGroundStep = 0; 109 CollidingStep = BSScene.NotASimulationStep;
102 CollisionAccumulation = 0; 110 CollidingGroundStep = BSScene.NotASimulationStep;
111 CollisionAccumulation = BSScene.NotASimulationStep;
103 ColliderIsMoving = false; 112 ColliderIsMoving = false;
104 CollisionScore = 0; 113 CollisionScore = 0;
105 114
106 // All axis free. 115 // All axis free.
107 LockedAxis = LockedAxisFree; 116 LockedLinearAxis = LockedAxisFree;
117 LockedAngularAxis = LockedAxisFree;
108 } 118 }
109 119
110 // Tell the object to clean up. 120 // Tell the object to clean up.
111 public virtual void Destroy() 121 public virtual void Destroy()
112 { 122 {
113 UnRegisterAllPreStepActions(); 123 PhysicalActors.Enable(false);
114 UnRegisterAllPostStepActions(); 124 PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
115 PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate()
116 { 125 {
117 PhysicalActors.Release(); 126 PhysicalActors.Dispose();
118 }); 127 });
119 } 128 }
120 129
121 public BSScene PhysicsScene { get; protected set; } 130 public BSScene PhysScene { get; protected set; }
122 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 131 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
123 public string PhysObjectName { get; protected set; } 132 public string PhysObjectName { get; protected set; }
124 public string TypeName { get; protected set; } 133 public string TypeName { get; protected set; }
125 134
135 // Set to 'true' when the object is completely initialized.
136 // This mostly prevents property updates and collisions until the object is completely here.
137 public bool IsInitialized { get; protected set; }
126 138
127 // Return the object mass without calculating it or having side effects 139 // Return the object mass without calculating it or having side effects
128 public abstract float RawMass { get; } 140 public abstract float RawMass { get; }
@@ -138,26 +150,19 @@ public abstract class BSPhysObject : PhysicsActor
138 // Reference to the physical body (btCollisionObject) of this object 150 // Reference to the physical body (btCollisionObject) of this object
139 public BulletBody PhysBody; 151 public BulletBody PhysBody;
140 // Reference to the physical shape (btCollisionShape) of this object 152 // Reference to the physical shape (btCollisionShape) of this object
141 public BulletShape PhysShape; 153 public BSShape PhysShape;
142 154
143 // The physical representation of the prim might require an asset fetch. 155 // The physical representation of the prim might require an asset fetch.
144 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. 156 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
145 public enum PrimAssetCondition 157 public enum PrimAssetCondition
146 { 158 {
147 Unknown, Waiting, Failed, Fetched 159 Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
148 } 160 }
149 public PrimAssetCondition PrimAssetState { get; set; } 161 public PrimAssetCondition PrimAssetState { get; set; }
150 162
151 // The objects base shape information. Null if not a prim type shape. 163 // The objects base shape information. Null if not a prim type shape.
152 public PrimitiveBaseShape BaseShape { get; protected set; } 164 public PrimitiveBaseShape BaseShape { get; protected set; }
153 165
154 // Some types of objects have preferred physical representations.
155 // Returns SHAPE_UNKNOWN if there is no preference.
156 public virtual BSPhysicsShapeType PreferredPhysicalShape
157 {
158 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
159 }
160
161 // When the physical properties are updated, an EntityProperty holds the update values. 166 // When the physical properties are updated, an EntityProperty holds the update values.
162 // Keep the current and last EntityProperties to enable computation of differences 167 // Keep the current and last EntityProperties to enable computation of differences
163 // between the current update and the previous values. 168 // between the current update and the previous values.
@@ -175,6 +180,7 @@ public abstract class BSPhysObject : PhysicsActor
175 public abstract bool IsSolid { get; } 180 public abstract bool IsSolid { get; }
176 public abstract bool IsStatic { get; } 181 public abstract bool IsStatic { get; }
177 public abstract bool IsSelected { get; } 182 public abstract bool IsSelected { get; }
183 public abstract bool IsVolumeDetect { get; }
178 184
179 // Materialness 185 // Materialness
180 public MaterialAttributes.Material Material { get; private set; } 186 public MaterialAttributes.Material Material { get; private set; }
@@ -183,13 +189,27 @@ public abstract class BSPhysObject : PhysicsActor
183 Material = (MaterialAttributes.Material)material; 189 Material = (MaterialAttributes.Material)material;
184 190
185 // Setting the material sets the material attributes also. 191 // Setting the material sets the material attributes also.
192 // TODO: decide if this is necessary -- the simulator does this.
186 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); 193 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
187 Friction = matAttrib.friction; 194 Friction = matAttrib.friction;
188 Restitution = matAttrib.restitution; 195 Restitution = matAttrib.restitution;
189 Density = matAttrib.density / BSParam.DensityScaleFactor; 196 Density = matAttrib.density;
190 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); 197 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
191 } 198 }
192 199
200 public override float Density
201 {
202 get
203 {
204 return base.Density;
205 }
206 set
207 {
208 DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
209 base.Density = value;
210 }
211 }
212
193 // Stop all physical motion. 213 // Stop all physical motion.
194 public abstract void ZeroMotion(bool inTaintTime); 214 public abstract void ZeroMotion(bool inTaintTime);
195 public abstract void ZeroAngularMotion(bool inTaintTime); 215 public abstract void ZeroAngularMotion(bool inTaintTime);
@@ -197,21 +217,55 @@ public abstract class BSPhysObject : PhysicsActor
197 // Update the physical location and motion of the object. Called with data from Bullet. 217 // Update the physical location and motion of the object. Called with data from Bullet.
198 public abstract void UpdateProperties(EntityProperties entprop); 218 public abstract void UpdateProperties(EntityProperties entprop);
199 219
200 public abstract OMV.Vector3 RawPosition { get; set; } 220 public virtual OMV.Vector3 RawPosition { get; set; }
201 public abstract OMV.Vector3 ForcePosition { get; set; } 221 public abstract OMV.Vector3 ForcePosition { get; set; }
202 222
203 public abstract OMV.Quaternion RawOrientation { get; set; } 223 public virtual OMV.Quaternion RawOrientation { get; set; }
204 public abstract OMV.Quaternion ForceOrientation { get; set; } 224 public abstract OMV.Quaternion ForceOrientation { get; set; }
205 225
206 public abstract OMV.Vector3 RawVelocity { get; set; } 226 public OMV.Vector3 RawVelocity { get; set; }
207 public abstract OMV.Vector3 ForceVelocity { get; set; } 227 public abstract OMV.Vector3 ForceVelocity { get; set; }
208 228
229 public OMV.Vector3 RawForce { get; set; }
230 public OMV.Vector3 RawTorque { get; set; }
231 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
232 {
233 AddAngularForce(force, pushforce, false);
234 }
235 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
236 public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
237
209 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 238 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
210 239
211 public abstract float ForceBuoyancy { get; set; } 240 public abstract float ForceBuoyancy { get; set; }
212 241
213 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 242 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
214 243
244 public override bool PIDActive { set { MoveToTargetActive = value; } }
245 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
246 public override float PIDTau { set { MoveToTargetTau = value; } }
247
248 public bool MoveToTargetActive { get; set; }
249 public OMV.Vector3 MoveToTargetTarget { get; set; }
250 public float MoveToTargetTau { get; set; }
251
252 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
253 public override bool PIDHoverActive { set { HoverActive = value; } }
254 public override float PIDHoverHeight { set { HoverHeight = value; } }
255 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
256 public override float PIDHoverTau { set { HoverTau = value; } }
257
258 public bool HoverActive { get; set; }
259 public float HoverHeight { get; set; }
260 public PIDHoverType HoverType { get; set; }
261 public float HoverTau { get; set; }
262
263 // For RotLookAt
264 public override OMV.Quaternion APIDTarget { set { return; } }
265 public override bool APIDActive { set { return; } }
266 public override float APIDStrength { set { return; } }
267 public override float APIDDamping { set { return; } }
268
215 // The current velocity forward 269 // The current velocity forward
216 public virtual float ForwardSpeed 270 public virtual float ForwardSpeed
217 { 271 {
@@ -233,11 +287,69 @@ public abstract class BSPhysObject : PhysicsActor
233 287
234 // The user can optionally set the center of mass. The user's setting will override any 288 // The user can optionally set the center of mass. The user's setting will override any
235 // computed center-of-mass (like in linksets). 289 // computed center-of-mass (like in linksets).
236 public OMV.Vector3? UserSetCenterOfMass { get; set; } 290 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
291 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
292
293 public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free.
294 public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free.
295 public const float FreeAxis = 1f;
296 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
297
298 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
299 // they need waking up when parameters are changed.
300 // Called in taint-time!!
301 public void ActivateIfPhysical(bool forceIt)
302 {
303 if (PhysBody.HasPhysicalBody)
304 {
305 if (IsPhysical)
306 {
307 // Physical objects might need activating
308 PhysScene.PE.Activate(PhysBody, forceIt);
309 }
310 else
311 {
312 // Clear the collision cache since we've changed some properties.
313 PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
314 }
315 }
316 }
237 317
238 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. 318 // 'actors' act on the physical object to change or constrain its motion. These can range from
239 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free 319 // hovering to complex vehicle motion.
240 public readonly String LockedAxisActorName = "BSPrim.LockedAxis"; 320 // May be called at non-taint time as this just adds the actor to the action list and the real
321 // work is done during the simulation step.
322 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
323 // in the list disabled.
324 public delegate BSActor CreateActor();
325 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
326 {
327 lock (PhysicalActors)
328 {
329 BSActor theActor;
330 if (PhysicalActors.TryGetActor(actorName, out theActor))
331 {
332 // The actor already exists so just turn it on or off
333 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
334 theActor.Enabled = enableActor;
335 }
336 else
337 {
338 // The actor does not exist. If it should, create it.
339 if (enableActor)
340 {
341 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
342 theActor = creator();
343 PhysicalActors.Add(actorName, theActor);
344 theActor.Enabled = true;
345 }
346 else
347 {
348 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
349 }
350 }
351 }
352 }
241 353
242 #region Collisions 354 #region Collisions
243 355
@@ -255,70 +367,98 @@ public abstract class BSPhysObject : PhysicsActor
255 protected CollisionFlags CurrentCollisionFlags { get; set; } 367 protected CollisionFlags CurrentCollisionFlags { get; set; }
256 // On a collision, check the collider and remember if the last collider was moving 368 // On a collision, check the collider and remember if the last collider was moving
257 // Used to modify the standing of avatars (avatars on stationary things stand still) 369 // Used to modify the standing of avatars (avatars on stationary things stand still)
258 protected bool ColliderIsMoving; 370 public bool ColliderIsMoving;
371 // 'true' if the last collider was a volume detect object
372 public bool ColliderIsVolumeDetect;
373 // Used by BSCharacter to manage standing (and not slipping)
374 public bool IsStationary;
259 375
260 // Count of collisions for this object 376 // Count of collisions for this object
261 protected long CollisionAccumulation { get; set; } 377 protected long CollisionAccumulation { get; set; }
262 378
263 public override bool IsColliding { 379 public override bool IsColliding {
264 get { return (CollidingStep == PhysicsScene.SimulationStep); } 380 get { return (CollidingStep == PhysScene.SimulationStep); }
265 set { 381 set {
266 if (value) 382 if (value)
267 CollidingStep = PhysicsScene.SimulationStep; 383 CollidingStep = PhysScene.SimulationStep;
268 else 384 else
269 CollidingStep = 0; 385 CollidingStep = BSScene.NotASimulationStep;
270 } 386 }
271 } 387 }
388 // Complex objects (like linksets) need to know if there is a collision on any part of
389 // their shape. 'IsColliding' has an existing definition of reporting a collision on
390 // only this specific prim or component of linksets.
391 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
392 // the complex body that this prim is the root of.
393 public virtual bool HasSomeCollision
394 {
395 get { return IsColliding; }
396 set { IsColliding = value; }
397 }
272 public override bool CollidingGround { 398 public override bool CollidingGround {
273 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } 399 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
274 set 400 set
275 { 401 {
276 if (value) 402 if (value)
277 CollidingGroundStep = PhysicsScene.SimulationStep; 403 CollidingGroundStep = PhysScene.SimulationStep;
278 else 404 else
279 CollidingGroundStep = 0; 405 CollidingGroundStep = BSScene.NotASimulationStep;
280 } 406 }
281 } 407 }
282 public override bool CollidingObj { 408 public override bool CollidingObj {
283 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } 409 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
284 set { 410 set {
285 if (value) 411 if (value)
286 CollidingObjectStep = PhysicsScene.SimulationStep; 412 CollidingObjectStep = PhysScene.SimulationStep;
287 else 413 else
288 CollidingObjectStep = 0; 414 CollidingObjectStep = BSScene.NotASimulationStep;
289 } 415 }
290 } 416 }
291 417
292 // The collisions that have been collected this tick 418 // The collisions that have been collected for the next collision reporting (throttled by subscription)
293 protected CollisionEventUpdate CollisionCollection; 419 protected CollisionEventUpdate CollisionCollection;
294 // Remember collisions from last tick for fancy collision based actions 420 // This is the collision collection last reported to the Simulator.
421 public CollisionEventUpdate CollisionsLastReported;
422 // Remember the collisions recorded in the last tick for fancy collision checking
295 // (like a BSCharacter walking up stairs). 423 // (like a BSCharacter walking up stairs).
296 protected CollisionEventUpdate CollisionsLastTick; 424 public CollisionEventUpdate CollisionsLastTick;
425 private long CollisionsLastTickStep = -1;
297 426
298 // The simulation step is telling this object about a collision. 427 // The simulation step is telling this object about a collision.
299 // Return 'true' if a collision was processed and should be sent up. 428 // Return 'true' if a collision was processed and should be sent up.
300 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. 429 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
301 // Called at taint time from within the Step() function 430 // Called at taint time from within the Step() function
431 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
302 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 432 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
303 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 433 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
304 { 434 {
305 bool ret = false; 435 bool ret = false;
306 436
307 // The following lines make IsColliding(), CollidingGround() and CollidingObj work 437 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
308 CollidingStep = PhysicsScene.SimulationStep; 438 CollidingStep = PhysScene.SimulationStep;
309 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 439 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
310 { 440 {
311 CollidingGroundStep = PhysicsScene.SimulationStep; 441 CollidingGroundStep = PhysScene.SimulationStep;
312 } 442 }
313 else 443 else
314 { 444 {
315 CollidingObjectStep = PhysicsScene.SimulationStep; 445 CollidingObjectStep = PhysScene.SimulationStep;
316 } 446 }
317 447
318 CollisionAccumulation++; 448 CollisionAccumulation++;
319 449
320 // For movement tests, remember if we are colliding with an object that is moving. 450 // For movement tests, remember if we are colliding with an object that is moving.
321 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; 451 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
452 ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
453
454 // Make a collection of the collisions that happened the last simulation tick.
455 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
456 if (CollisionsLastTickStep != PhysScene.SimulationStep)
457 {
458 CollisionsLastTick = new CollisionEventUpdate();
459 CollisionsLastTickStep = PhysScene.SimulationStep;
460 }
461 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
322 462
323 // If someone has subscribed for collision events log the collision so it will be reported up 463 // If someone has subscribed for collision events log the collision so it will be reported up
324 if (SubscribedEvents()) { 464 if (SubscribedEvents()) {
@@ -340,12 +480,12 @@ public abstract class BSPhysObject : PhysicsActor
340 bool ret = true; 480 bool ret = true;
341 481
342 // If the 'no collision' call, force it to happen right now so quick collision_end 482 // If the 'no collision' call, force it to happen right now so quick collision_end
343 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); 483 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
344 484
345 // throttle the collisions to the number of milliseconds specified in the subscription 485 // throttle the collisions to the number of milliseconds specified in the subscription
346 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 486 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
347 { 487 {
348 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; 488 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
349 489
350 // We are called if we previously had collisions. If there are no collisions 490 // We are called if we previously had collisions. If there are no collisions
351 // this time, send up one last empty event so OpenSim can sense collision end. 491 // this time, send up one last empty event so OpenSim can sense collision end.
@@ -359,11 +499,11 @@ public abstract class BSPhysObject : PhysicsActor
359 base.SendCollisionUpdate(CollisionCollection); 499 base.SendCollisionUpdate(CollisionCollection);
360 500
361 // Remember the collisions from this tick for some collision specific processing. 501 // Remember the collisions from this tick for some collision specific processing.
362 CollisionsLastTick = CollisionCollection; 502 CollisionsLastReported = CollisionCollection;
363 503
364 // The CollisionCollection instance is passed around in the simulator. 504 // The CollisionCollection instance is passed around in the simulator.
365 // Make sure we don't have a handle to that one and that a new one is used for next time. 505 // Make sure we don't have a handle to that one and that a new one is used for next time.
366 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, 506 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
367 // a race condition is created for the other users of this instance. 507 // a race condition is created for the other users of this instance.
368 CollisionCollection = new CollisionEventUpdate(); 508 CollisionCollection = new CollisionEventUpdate();
369 } 509 }
@@ -380,10 +520,10 @@ public abstract class BSPhysObject : PhysicsActor
380 // make sure first collision happens 520 // make sure first collision happens
381 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); 521 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
382 522
383 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 523 PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
384 { 524 {
385 if (PhysBody.HasPhysicalBody) 525 if (PhysBody.HasPhysicalBody)
386 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 526 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
387 }); 527 });
388 } 528 }
389 else 529 else
@@ -395,11 +535,11 @@ public abstract class BSPhysObject : PhysicsActor
395 public override void UnSubscribeEvents() { 535 public override void UnSubscribeEvents() {
396 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 536 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
397 SubscribedEventsMs = 0; 537 SubscribedEventsMs = 0;
398 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 538 PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
399 { 539 {
400 // Make sure there is a body there because sometimes destruction happens in an un-ideal order. 540 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
401 if (PhysBody.HasPhysicalBody) 541 if (PhysBody.HasPhysicalBody)
402 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 542 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
403 }); 543 });
404 } 544 }
405 // Return 'true' if the simulator wants collision events 545 // Return 'true' if the simulator wants collision events
@@ -413,7 +553,7 @@ public abstract class BSPhysObject : PhysicsActor
413 { 553 {
414 // Scale the collision count by the time since the last collision. 554 // Scale the collision count by the time since the last collision.
415 // The "+1" prevents dividing by zero. 555 // The "+1" prevents dividing by zero.
416 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; 556 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
417 CollisionScore = CollisionAccumulation / timeAgo; 557 CollisionScore = CollisionAccumulation / timeAgo;
418 } 558 }
419 public override float CollisionScore { get; set; } 559 public override float CollisionScore { get; set; }
@@ -424,104 +564,6 @@ public abstract class BSPhysObject : PhysicsActor
424 564
425 public BSActorCollection PhysicalActors; 565 public BSActorCollection PhysicalActors;
426 566
427 // There are some actions that must be performed for a physical object before each simulation step.
428 // These actions are optional so, rather than scanning all the physical objects and asking them
429 // if they have anything to do, a physical object registers for an event call before the step is performed.
430 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
431 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
432 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
433 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
434 {
435 string identifier = op + "-" + id.ToString();
436
437 lock (RegisteredPrestepActions)
438 {
439 // Clean out any existing action
440 UnRegisterPreStepAction(op, id);
441 RegisteredPrestepActions[identifier] = actn;
442 PhysicsScene.BeforeStep += actn;
443 }
444 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
445 }
446
447 // Unregister a pre step action. Safe to call if the action has not been registered.
448 // Returns 'true' if an action was actually removed
449 protected bool UnRegisterPreStepAction(string op, uint id)
450 {
451 string identifier = op + "-" + id.ToString();
452 bool removed = false;
453 lock (RegisteredPrestepActions)
454 {
455 if (RegisteredPrestepActions.ContainsKey(identifier))
456 {
457 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
458 RegisteredPrestepActions.Remove(identifier);
459 removed = true;
460 }
461 }
462 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
463 return removed;
464 }
465
466 protected void UnRegisterAllPreStepActions()
467 {
468 lock (RegisteredPrestepActions)
469 {
470 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
471 {
472 PhysicsScene.BeforeStep -= kvp.Value;
473 }
474 RegisteredPrestepActions.Clear();
475 }
476 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
477 }
478
479 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
480 {
481 string identifier = op + "-" + id.ToString();
482
483 lock (RegisteredPoststepActions)
484 {
485 // Clean out any existing action
486 UnRegisterPostStepAction(op, id);
487 RegisteredPoststepActions[identifier] = actn;
488 PhysicsScene.AfterStep += actn;
489 }
490 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
491 }
492
493 // Unregister a pre step action. Safe to call if the action has not been registered.
494 // Returns 'true' if an action was actually removed.
495 protected bool UnRegisterPostStepAction(string op, uint id)
496 {
497 string identifier = op + "-" + id.ToString();
498 bool removed = false;
499 lock (RegisteredPoststepActions)
500 {
501 if (RegisteredPoststepActions.ContainsKey(identifier))
502 {
503 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
504 RegisteredPoststepActions.Remove(identifier);
505 removed = true;
506 }
507 }
508 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
509 return removed;
510 }
511
512 protected void UnRegisterAllPostStepActions()
513 {
514 lock (RegisteredPoststepActions)
515 {
516 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
517 {
518 PhysicsScene.AfterStep -= kvp.Value;
519 }
520 RegisteredPoststepActions.Clear();
521 }
522 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
523 }
524
525 // When an update to the physical properties happens, this event is fired to let 567 // When an update to the physical properties happens, this event is fired to let
526 // different actors to modify the update before it is passed around 568 // different actors to modify the update before it is passed around
527 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); 569 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
@@ -533,53 +575,13 @@ public abstract class BSPhysObject : PhysicsActor
533 actions(ref entprop); 575 actions(ref entprop);
534 } 576 }
535 577
536 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
537 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
538 {
539 lock (RegisteredPreUpdatePropertyActions)
540 {
541 // Clean out any existing action
542 UnRegisterPreUpdatePropertyAction(identifier);
543 RegisteredPreUpdatePropertyActions[identifier] = actn;
544 OnPreUpdateProperty += actn;
545 }
546 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
547 }
548 public bool UnRegisterPreUpdatePropertyAction(string identifier)
549 {
550 bool removed = false;
551 lock (RegisteredPreUpdatePropertyActions)
552 {
553 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
554 {
555 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
556 RegisteredPreUpdatePropertyActions.Remove(identifier);
557 removed = true;
558 }
559 }
560 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
561 return removed;
562 }
563 public void UnRegisterAllPreUpdatePropertyActions()
564 {
565 lock (RegisteredPreUpdatePropertyActions)
566 {
567 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
568 {
569 OnPreUpdateProperty -= kvp.Value;
570 }
571 RegisteredPreUpdatePropertyActions.Clear();
572 }
573 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
574 }
575
576 #endregion // Per Simulation Step actions 578 #endregion // Per Simulation Step actions
577 579
578 // High performance detailed logging routine used by the physical objects. 580 // High performance detailed logging routine used by the physical objects.
579 protected void DetailLog(string msg, params Object[] args) 581 protected void DetailLog(string msg, params Object[] args)
580 { 582 {
581 if (PhysicsScene.PhysicsLogging.Enabled) 583 if (PhysScene.PhysicsLogging.Enabled)
582 PhysicsScene.DetailLog(msg, args); 584 PhysScene.DetailLog(msg, args);
583 } 585 }
584 586
585} 587}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index e56276a..15b7090 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -41,7 +41,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
41 [Serializable] 41 [Serializable]
42public class BSPrim : BSPhysObject 42public class BSPrim : BSPhysObject
43{ 43{
44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
@@ -51,15 +51,8 @@ public class BSPrim : BSPhysObject
51 private bool _isSelected; 51 private bool _isSelected;
52 private bool _isVolumeDetect; 52 private bool _isVolumeDetect;
53 53
54 // _position is what the simulator thinks the positions of the prim is.
55 private OMV.Vector3 _position;
56
57 private float _mass; // the mass of this object 54 private float _mass; // the mass of this object
58 private OMV.Vector3 _force;
59 private OMV.Vector3 _velocity;
60 private OMV.Vector3 _torque;
61 private OMV.Vector3 _acceleration; 55 private OMV.Vector3 _acceleration;
62 private OMV.Quaternion _orientation;
63 private int _physicsActorType; 56 private int _physicsActorType;
64 private bool _isPhysical; 57 private bool _isPhysical;
65 private bool _flying; 58 private bool _flying;
@@ -72,17 +65,18 @@ public class BSPrim : BSPhysObject
72 65
73 private int CrossingFailures { get; set; } 66 private int CrossingFailures { get; set; }
74 67
75 public BSDynamics VehicleActor; 68 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
76 public string VehicleActorName = "BasicVehicle"; 69 public const string VehicleActorName = "BasicVehicle";
77
78 private BSVMotor _targetMotor;
79 private OMV.Vector3 _PIDTarget;
80 private float _PIDTau;
81 70
82 private BSFMotor _hoverMotor; 71 // Parameters for the hover actor
83 private float _PIDHoverHeight; 72 public const string HoverActorName = "BSPrim.HoverActor";
84 private PIDHoverType _PIDHoverType; 73 // Parameters for the axis lock actor
85 private float _PIDHoverTau; 74 public const String LockedAxisActorName = "BSPrim.LockedAxis";
75 // Parameters for the move to target actor
76 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
77 // Parameters for the setForce and setTorque actors
78 public const string SetForceActorName = "BSPrim.SetForceActor";
79 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
86 80
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 81 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 82 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -90,32 +84,34 @@ public class BSPrim : BSPhysObject
90 { 84 {
91 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 85 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
92 _physicsActorType = (int)ActorTypes.Prim; 86 _physicsActorType = (int)ActorTypes.Prim;
93 _position = pos; 87 RawPosition = pos;
94 _size = size; 88 _size = size;
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes). 89 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation; 90 RawOrientation = rotation;
97 _buoyancy = 0f; 91 _buoyancy = 0f;
98 _velocity = OMV.Vector3.Zero; 92 RawVelocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero; 93 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs; 94 BaseShape = pbs;
101 _isPhysical = pisPhysical; 95 _isPhysical = pisPhysical;
102 _isVolumeDetect = false; 96 _isVolumeDetect = false;
103 97
104 VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); 98 // Add a dynamic vehicle to our set of actors that can move this prim.
105 PhysicalActors.Add(VehicleActorName, VehicleActor); 99 // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName));
106 100
107 _mass = CalculateMass(); 101 _mass = CalculateMass();
108 102
109 // DetailLog("{0},BSPrim.constructor,call", LocalID); 103 // DetailLog("{0},BSPrim.constructor,call", LocalID);
110 // do the actual object creation at taint time 104 // do the actual object creation at taint time
111 PhysicsScene.TaintedObject("BSPrim.create", delegate() 105 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
112 { 106 {
113 // Make sure the object is being created with some sanity. 107 // Make sure the object is being created with some sanity.
114 ExtremeSanityCheck(true /* inTaintTime */); 108 ExtremeSanityCheck(true /* inTaintTime */);
115 109
116 CreateGeomAndObject(true); 110 CreateGeomAndObject(true);
117 111
118 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); 112 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
113
114 IsInitialized = true;
119 }); 115 });
120 } 116 }
121 117
@@ -123,19 +119,21 @@ public class BSPrim : BSPhysObject
123 public override void Destroy() 119 public override void Destroy()
124 { 120 {
125 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 121 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
122 IsInitialized = false;
123
126 base.Destroy(); 124 base.Destroy();
127 125
128 // Undo any vehicle properties 126 // Undo any vehicle properties
129 this.VehicleType = (int)Vehicle.TYPE_NONE; 127 this.VehicleType = (int)Vehicle.TYPE_NONE;
130 128
131 PhysicsScene.TaintedObject("BSPrim.Destroy", delegate() 129 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
132 { 130 {
133 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 131 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
134 // If there are physical body and shape, release my use of same. 132 // If there are physical body and shape, release my use of same.
135 PhysicsScene.Shapes.DereferenceBody(PhysBody, null); 133 PhysScene.Shapes.DereferenceBody(PhysBody, null);
136 PhysBody.Clear(); 134 PhysBody.Clear();
137 PhysicsScene.Shapes.DereferenceShape(PhysShape, null); 135 PhysShape.Dereference(PhysScene);
138 PhysShape.Clear(); 136 PhysShape = new BSShapeNull();
139 }); 137 });
140 } 138 }
141 139
@@ -161,25 +159,13 @@ public class BSPrim : BSPhysObject
161 ForceBodyShapeRebuild(false); 159 ForceBodyShapeRebuild(false);
162 } 160 }
163 } 161 }
164 // 'unknown' says to choose the best type
165 public override BSPhysicsShapeType PreferredPhysicalShape
166 { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } }
167
168 public override bool ForceBodyShapeRebuild(bool inTaintTime) 162 public override bool ForceBodyShapeRebuild(bool inTaintTime)
169 { 163 {
170 if (inTaintTime) 164 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
171 { 165 {
172 _mass = CalculateMass(); // changing the shape changes the mass 166 _mass = CalculateMass(); // changing the shape changes the mass
173 CreateGeomAndObject(true); 167 CreateGeomAndObject(true);
174 } 168 });
175 else
176 {
177 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate()
178 {
179 _mass = CalculateMass(); // changing the shape changes the mass
180 CreateGeomAndObject(true);
181 });
182 }
183 return true; 169 return true;
184 } 170 }
185 public override bool Grabbed { 171 public override bool Grabbed {
@@ -192,7 +178,7 @@ public class BSPrim : BSPhysObject
192 if (value != _isSelected) 178 if (value != _isSelected)
193 { 179 {
194 _isSelected = value; 180 _isSelected = value;
195 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 181 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
196 { 182 {
197 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 183 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
198 SetObjectDynamic(false); 184 SetObjectDynamic(false);
@@ -233,28 +219,28 @@ public class BSPrim : BSPhysObject
233 // Called at taint time! 219 // Called at taint time!
234 public override void ZeroMotion(bool inTaintTime) 220 public override void ZeroMotion(bool inTaintTime)
235 { 221 {
236 _velocity = OMV.Vector3.Zero; 222 RawVelocity = OMV.Vector3.Zero;
237 _acceleration = OMV.Vector3.Zero; 223 _acceleration = OMV.Vector3.Zero;
238 _rotationalVelocity = OMV.Vector3.Zero; 224 _rotationalVelocity = OMV.Vector3.Zero;
239 225
240 // Zero some other properties in the physics engine 226 // Zero some other properties in the physics engine
241 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 227 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
242 { 228 {
243 if (PhysBody.HasPhysicalBody) 229 if (PhysBody.HasPhysicalBody)
244 PhysicsScene.PE.ClearAllForces(PhysBody); 230 PhysScene.PE.ClearAllForces(PhysBody);
245 }); 231 });
246 } 232 }
247 public override void ZeroAngularMotion(bool inTaintTime) 233 public override void ZeroAngularMotion(bool inTaintTime)
248 { 234 {
249 _rotationalVelocity = OMV.Vector3.Zero; 235 _rotationalVelocity = OMV.Vector3.Zero;
250 // Zero some other properties in the physics engine 236 // Zero some other properties in the physics engine
251 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 237 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
252 { 238 {
253 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); 239 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
254 if (PhysBody.HasPhysicalBody) 240 if (PhysBody.HasPhysicalBody)
255 { 241 {
256 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 242 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
257 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 243 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
258 } 244 }
259 }); 245 });
260 } 246 }
@@ -268,64 +254,58 @@ public class BSPrim : BSPhysObject
268 if (axis.X != 1) locking.X = 0f; 254 if (axis.X != 1) locking.X = 0f;
269 if (axis.Y != 1) locking.Y = 0f; 255 if (axis.Y != 1) locking.Y = 0f;
270 if (axis.Z != 1) locking.Z = 0f; 256 if (axis.Z != 1) locking.Z = 0f;
271 LockedAxis = locking; 257 LockedAngularAxis = locking;
272 258
273 if (LockedAxis != LockedAxisFree) 259 EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate()
274 { 260 {
275 PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() 261 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
276 { 262 });
277 // If there is not already an axis locker, make one 263
278 if (!PhysicalActors.HasActor(LockedAxisActorName)) 264 // Update parameters so the new actor's Refresh() action is called at the right time.
279 { 265 PhysScene.TaintedObject(LocalID, "BSPrim.LockAngularMotion", delegate()
280 DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID); 266 {
281 PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName)); 267 UpdatePhysicalParameters();
282 } 268 });
283 UpdatePhysicalParameters(); 269
284 });
285 }
286 return; 270 return;
287 } 271 }
288 272
289 public override OMV.Vector3 RawPosition
290 {
291 get { return _position; }
292 set { _position = value; }
293 }
294 public override OMV.Vector3 Position { 273 public override OMV.Vector3 Position {
295 get { 274 get {
296 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 275 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
297 // _position = ForcePosition; 276 // RawPosition = ForcePosition;
298 return _position; 277 return RawPosition;
299 } 278 }
300 set { 279 set {
301 // If the position must be forced into the physics engine, use ForcePosition. 280 // If the position must be forced into the physics engine, use ForcePosition.
302 // All positions are given in world positions. 281 // All positions are given in world positions.
303 if (_position == value) 282 if (RawPosition == value)
304 { 283 {
305 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); 284 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
306 return; 285 return;
307 } 286 }
308 _position = value; 287 RawPosition = value;
309 PositionSanityCheck(false); 288 PositionSanityCheck(false);
310 289
311 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 290 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
312 { 291 {
313 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 292 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
314 ForcePosition = _position; 293 ForcePosition = RawPosition;
315 }); 294 });
316 } 295 }
317 } 296 }
318 297
298 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
319 public override OMV.Vector3 ForcePosition { 299 public override OMV.Vector3 ForcePosition {
320 get { 300 get {
321 _position = PhysicsScene.PE.GetPosition(PhysBody); 301 RawPosition = PhysScene.PE.GetPosition(PhysBody);
322 return _position; 302 return RawPosition;
323 } 303 }
324 set { 304 set {
325 _position = value; 305 RawPosition = value;
326 if (PhysBody.HasPhysicalBody) 306 if (PhysBody.HasPhysicalBody)
327 { 307 {
328 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 308 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
329 ActivateIfPhysical(false); 309 ActivateIfPhysical(false);
330 } 310 }
331 } 311 }
@@ -342,7 +322,7 @@ public class BSPrim : BSPhysObject
342 if (!IsPhysicallyActive) 322 if (!IsPhysicallyActive)
343 return ret; 323 return ret;
344 324
345 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 325 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
346 { 326 {
347 // The physical object is out of the known/simulated area. 327 // The physical object is out of the known/simulated area.
348 // Upper levels of code will handle the transition to other areas so, for 328 // Upper levels of code will handle the transition to other areas so, for
@@ -350,7 +330,7 @@ public class BSPrim : BSPhysObject
350 return ret; 330 return ret;
351 } 331 }
352 332
353 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 333 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
354 OMV.Vector3 upForce = OMV.Vector3.Zero; 334 OMV.Vector3 upForce = OMV.Vector3.Zero;
355 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); 335 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
356 if ((RawPosition.Z + approxSize / 2f) < terrainHeight) 336 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
@@ -359,10 +339,10 @@ public class BSPrim : BSPhysObject
359 float targetHeight = terrainHeight + (Size.Z / 2f); 339 float targetHeight = terrainHeight + (Size.Z / 2f);
360 // If the object is below ground it just has to be moved up because pushing will 340 // If the object is below ground it just has to be moved up because pushing will
361 // not get it through the terrain 341 // not get it through the terrain
362 _position.Z = targetHeight; 342 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
363 if (inTaintTime) 343 if (inTaintTime)
364 { 344 {
365 ForcePosition = _position; 345 ForcePosition = RawPosition;
366 } 346 }
367 // If we are throwing the object around, zero its other forces 347 // If we are throwing the object around, zero its other forces
368 ZeroMotion(inTaintTime); 348 ZeroMotion(inTaintTime);
@@ -371,7 +351,7 @@ public class BSPrim : BSPhysObject
371 351
372 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 352 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
373 { 353 {
374 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 354 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
375 // TODO: a floating motor so object will bob in the water 355 // TODO: a floating motor so object will bob in the water
376 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) 356 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
377 { 357 {
@@ -379,8 +359,8 @@ public class BSPrim : BSPhysObject
379 upForce.Z = (waterHeight - RawPosition.Z) * 1f; 359 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
380 360
381 // Apply upforce and overcome gravity. 361 // Apply upforce and overcome gravity.
382 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; 362 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
383 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); 363 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
384 AddForce(correctionForce, false, inTaintTime); 364 AddForce(correctionForce, false, inTaintTime);
385 ret = true; 365 ret = true;
386 } 366 }
@@ -399,17 +379,17 @@ public class BSPrim : BSPhysObject
399 uint wayOutThere = Constants.RegionSize * Constants.RegionSize; 379 uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
400 // There have been instances of objects getting thrown way out of bounds and crashing 380 // There have been instances of objects getting thrown way out of bounds and crashing
401 // the border crossing code. 381 // the border crossing code.
402 if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere 382 if ( RawPosition.X < -Constants.RegionSize || RawPosition.X > wayOutThere
403 || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere 383 || RawPosition.Y < -Constants.RegionSize || RawPosition.Y > wayOutThere
404 || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) 384 || RawPosition.Z < -Constants.RegionSize || RawPosition.Z > wayOutThere)
405 { 385 {
406 _position = new OMV.Vector3(10, 10, 50); 386 RawPosition = new OMV.Vector3(10, 10, 50);
407 ZeroMotion(inTaintTime); 387 ZeroMotion(inTaintTime);
408 ret = true; 388 ret = true;
409 } 389 }
410 if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) 390 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
411 { 391 {
412 _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); 392 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
413 ret = true; 393 ret = true;
414 } 394 }
415 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) 395 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
@@ -434,7 +414,7 @@ public class BSPrim : BSPhysObject
434 get { return _mass; } 414 get { return _mass; }
435 } 415 }
436 // used when we only want this prim's mass and not the linkset thing 416 // used when we only want this prim's mass and not the linkset thing
437 public override float RawMass { 417 public override float RawMass {
438 get { return _mass; } 418 get { return _mass; }
439 } 419 }
440 // Set the physical mass to the passed mass. 420 // Set the physical mass to the passed mass.
@@ -445,10 +425,10 @@ public class BSPrim : BSPhysObject
445 { 425 {
446 if (IsStatic) 426 if (IsStatic)
447 { 427 {
448 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); 428 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
449 Inertia = OMV.Vector3.Zero; 429 Inertia = OMV.Vector3.Zero;
450 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); 430 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
451 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 431 PhysScene.PE.UpdateInertiaTensor(PhysBody);
452 } 432 }
453 else 433 else
454 { 434 {
@@ -457,16 +437,19 @@ public class BSPrim : BSPhysObject
457 // Changing interesting properties doesn't change proxy and collision cache 437 // Changing interesting properties doesn't change proxy and collision cache
458 // information. The Bullet solution is to re-add the object to the world 438 // information. The Bullet solution is to re-add the object to the world
459 // after parameters are changed. 439 // after parameters are changed.
460 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 440 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
461 } 441 }
462 442
463 // The computation of mass props requires gravity to be set on the object. 443 // The computation of mass props requires gravity to be set on the object.
464 Gravity = ComputeGravity(Buoyancy); 444 Gravity = ComputeGravity(Buoyancy);
465 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 445 PhysScene.PE.SetGravity(PhysBody, Gravity);
446
447 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
448 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
466 449
467 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 450 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
468 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); 451 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
469 PhysicsScene.PE.UpdateInertiaTensor(PhysBody); 452 PhysScene.PE.UpdateInertiaTensor(PhysBody);
470 453
471 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", 454 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
472 LocalID, physMass, Inertia, Gravity, inWorld); 455 LocalID, physMass, Inertia, Gravity, inWorld);
@@ -482,7 +465,7 @@ public class BSPrim : BSPhysObject
482 // Return what gravity should be set to this very moment 465 // Return what gravity should be set to this very moment
483 public OMV.Vector3 ComputeGravity(float buoyancy) 466 public OMV.Vector3 ComputeGravity(float buoyancy)
484 { 467 {
485 OMV.Vector3 ret = PhysicsScene.DefaultGravity; 468 OMV.Vector3 ret = PhysScene.DefaultGravity;
486 469
487 if (!IsStatic) 470 if (!IsStatic)
488 { 471 {
@@ -506,83 +489,121 @@ public class BSPrim : BSPhysObject
506 } 489 }
507 490
508 public override OMV.Vector3 Force { 491 public override OMV.Vector3 Force {
509 get { return _force; } 492 get { return RawForce; }
510 set { 493 set {
511 _force = value; 494 RawForce = value;
512 if (_force != OMV.Vector3.Zero) 495 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
513 { 496 {
514 // If the force is non-zero, it must be reapplied each tick because 497 return new BSActorSetForce(PhysScene, this, SetForceActorName);
515 // Bullet clears the forces applied last frame. 498 });
516 RegisterPreStepAction("BSPrim.setForce", LocalID, 499 }
517 delegate(float timeStep) 500 }
518 {
519 if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
520 {
521 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
522 return;
523 }
524 501
525 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); 502 // Find and return a handle to the current vehicle actor.
526 if (PhysBody.HasPhysicalBody) 503 // Return 'null' if there is no vehicle actor.
527 { 504 public BSDynamics GetVehicleActor(bool createIfNone)
528 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); 505 {
529 ActivateIfPhysical(false); 506 BSDynamics ret = null;
530 } 507 BSActor actor;
531 } 508 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
532 ); 509 {
533 } 510 ret = actor as BSDynamics;
534 else 511 }
512 else
513 {
514 if (createIfNone)
535 { 515 {
536 UnRegisterPreStepAction("BSPrim.setForce", LocalID); 516 ret = new BSDynamics(PhysScene, this, VehicleActorName);
517 PhysicalActors.Add(ret.ActorName, ret);
537 } 518 }
538 } 519 }
520 return ret;
539 } 521 }
540 522
541 public override int VehicleType { 523 public override int VehicleType {
542 get { 524 get {
543 return (int)VehicleActor.Type; // if we are a vehicle, return that type 525 int ret = (int)Vehicle.TYPE_NONE;
526 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
527 if (vehicleActor != null)
528 ret = (int)vehicleActor.Type;
529 return ret;
544 } 530 }
545 set { 531 set {
546 Vehicle type = (Vehicle)value; 532 Vehicle type = (Vehicle)value;
547 533
548 PhysicsScene.TaintedObject("setVehicleType", delegate() 534 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
549 { 535 {
550 // Done at taint time so we're sure the physics engine is not using the variables 536 // Some vehicle scripts change vehicle type on the fly as an easy way to
551 // Vehicle code changes the parameters for this vehicle type. 537 // change all the parameters. Like a plane changing to CAR when on the
552 VehicleActor.ProcessTypeChange(type); 538 // ground. In this case, don't want to zero motion.
553 ActivateIfPhysical(false); 539 // ZeroMotion(true /* inTaintTime */);
540 if (type == Vehicle.TYPE_NONE)
541 {
542 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
543 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
544 if (vehicleActor != null)
545 {
546 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
547 }
548 }
549 else
550 {
551 // Vehicle type is not 'none' so create an actor and set it running.
552 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
553 if (vehicleActor != null)
554 {
555 vehicleActor.ProcessTypeChange(type);
556 ActivateIfPhysical(false);
557 }
558 }
554 }); 559 });
555 } 560 }
556 } 561 }
557 public override void VehicleFloatParam(int param, float value) 562 public override void VehicleFloatParam(int param, float value)
558 { 563 {
559 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 564 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
560 { 565 {
561 VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); 566 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
562 ActivateIfPhysical(false); 567 if (vehicleActor != null)
568 {
569 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
570 ActivateIfPhysical(false);
571 }
563 }); 572 });
564 } 573 }
565 public override void VehicleVectorParam(int param, OMV.Vector3 value) 574 public override void VehicleVectorParam(int param, OMV.Vector3 value)
566 { 575 {
567 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 576 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
568 { 577 {
569 VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); 578 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
570 ActivateIfPhysical(false); 579 if (vehicleActor != null)
580 {
581 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
582 ActivateIfPhysical(false);
583 }
571 }); 584 });
572 } 585 }
573 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 586 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
574 { 587 {
575 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 588 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
576 { 589 {
577 VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); 590 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
578 ActivateIfPhysical(false); 591 if (vehicleActor != null)
592 {
593 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
594 ActivateIfPhysical(false);
595 }
579 }); 596 });
580 } 597 }
581 public override void VehicleFlags(int param, bool remove) 598 public override void VehicleFlags(int param, bool remove)
582 { 599 {
583 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() 600 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
584 { 601 {
585 VehicleActor.ProcessVehicleFlags(param, remove); 602 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
603 if (vehicleActor != null)
604 {
605 vehicleActor.ProcessVehicleFlags(param, remove);
606 }
586 }); 607 });
587 } 608 }
588 609
@@ -592,7 +613,7 @@ public class BSPrim : BSPhysObject
592 if (_isVolumeDetect != newValue) 613 if (_isVolumeDetect != newValue)
593 { 614 {
594 _isVolumeDetect = newValue; 615 _isVolumeDetect = newValue;
595 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() 616 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
596 { 617 {
597 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); 618 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
598 SetObjectDynamic(true); 619 SetObjectDynamic(true);
@@ -600,10 +621,14 @@ public class BSPrim : BSPhysObject
600 } 621 }
601 return; 622 return;
602 } 623 }
624 public override bool IsVolumeDetect
625 {
626 get { return _isVolumeDetect; }
627 }
603 public override void SetMaterial(int material) 628 public override void SetMaterial(int material)
604 { 629 {
605 base.SetMaterial(material); 630 base.SetMaterial(material);
606 PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() 631 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
607 { 632 {
608 UpdatePhysicalParameters(); 633 UpdatePhysicalParameters();
609 }); 634 });
@@ -616,7 +641,7 @@ public class BSPrim : BSPhysObject
616 if (base.Friction != value) 641 if (base.Friction != value)
617 { 642 {
618 base.Friction = value; 643 base.Friction = value;
619 PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() 644 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
620 { 645 {
621 UpdatePhysicalParameters(); 646 UpdatePhysicalParameters();
622 }); 647 });
@@ -631,7 +656,7 @@ public class BSPrim : BSPhysObject
631 if (base.Restitution != value) 656 if (base.Restitution != value)
632 { 657 {
633 base.Restitution = value; 658 base.Restitution = value;
634 PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() 659 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
635 { 660 {
636 UpdatePhysicalParameters(); 661 UpdatePhysicalParameters();
637 }); 662 });
@@ -648,7 +673,7 @@ public class BSPrim : BSPhysObject
648 if (base.Density != value) 673 if (base.Density != value)
649 { 674 {
650 base.Density = value; 675 base.Density = value;
651 PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() 676 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
652 { 677 {
653 UpdatePhysicalParameters(); 678 UpdatePhysicalParameters();
654 }); 679 });
@@ -663,93 +688,66 @@ public class BSPrim : BSPhysObject
663 if (base.GravModifier != value) 688 if (base.GravModifier != value)
664 { 689 {
665 base.GravModifier = value; 690 base.GravModifier = value;
666 PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() 691 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
667 { 692 {
668 UpdatePhysicalParameters(); 693 UpdatePhysicalParameters();
669 }); 694 });
670 } 695 }
671 } 696 }
672 } 697 }
673 public override OMV.Vector3 RawVelocity
674 {
675 get { return _velocity; }
676 set { _velocity = value; }
677 }
678 public override OMV.Vector3 Velocity { 698 public override OMV.Vector3 Velocity {
679 get { return _velocity; } 699 get { return RawVelocity; }
680 set { 700 set {
681 _velocity = value; 701 RawVelocity = value;
682 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 702 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
683 { 703 {
684 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 704 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
685 ForceVelocity = _velocity; 705 ForceVelocity = RawVelocity;
686 }); 706 });
687 } 707 }
688 } 708 }
689 public override OMV.Vector3 ForceVelocity { 709 public override OMV.Vector3 ForceVelocity {
690 get { return _velocity; } 710 get { return RawVelocity; }
691 set { 711 set {
692 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); 712 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
693 713
694 _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); 714 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
695 if (PhysBody.HasPhysicalBody) 715 if (PhysBody.HasPhysicalBody)
696 { 716 {
697 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); 717 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
698 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 718 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
699 ActivateIfPhysical(false); 719 ActivateIfPhysical(false);
700 } 720 }
701 } 721 }
702 } 722 }
703 public override OMV.Vector3 Torque { 723 public override OMV.Vector3 Torque {
704 get { return _torque; } 724 get { return RawTorque; }
705 set { 725 set {
706 _torque = value; 726 RawTorque = value;
707 if (_torque != OMV.Vector3.Zero) 727 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
708 {
709 // If the torque is non-zero, it must be reapplied each tick because
710 // Bullet clears the forces applied last frame.
711 RegisterPreStepAction("BSPrim.setTorque", LocalID,
712 delegate(float timeStep)
713 {
714 if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
715 {
716 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
717 return;
718 }
719
720 if (PhysBody.HasPhysicalBody)
721 AddAngularForce(_torque, false, true);
722 }
723 );
724 }
725 else
726 { 728 {
727 UnRegisterPreStepAction("BSPrim.setTorque", LocalID); 729 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
728 } 730 });
729 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 731 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
730 } 732 }
731 } 733 }
732 public override OMV.Vector3 Acceleration { 734 public override OMV.Vector3 Acceleration {
733 get { return _acceleration; } 735 get { return _acceleration; }
734 set { _acceleration = value; } 736 set { _acceleration = value; }
735 } 737 }
736 public override OMV.Quaternion RawOrientation 738
737 {
738 get { return _orientation; }
739 set { _orientation = value; }
740 }
741 public override OMV.Quaternion Orientation { 739 public override OMV.Quaternion Orientation {
742 get { 740 get {
743 return _orientation; 741 return RawOrientation;
744 } 742 }
745 set { 743 set {
746 if (_orientation == value) 744 if (RawOrientation == value)
747 return; 745 return;
748 _orientation = value; 746 RawOrientation = value;
749 747
750 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 748 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
751 { 749 {
752 ForceOrientation = _orientation; 750 ForceOrientation = RawOrientation;
753 }); 751 });
754 } 752 }
755 } 753 }
@@ -758,14 +756,14 @@ public class BSPrim : BSPhysObject
758 { 756 {
759 get 757 get
760 { 758 {
761 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 759 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
762 return _orientation; 760 return RawOrientation;
763 } 761 }
764 set 762 set
765 { 763 {
766 _orientation = value; 764 RawOrientation = value;
767 if (PhysBody.HasPhysicalBody) 765 if (PhysBody.HasPhysicalBody)
768 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 766 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
769 } 767 }
770 } 768 }
771 public override int PhysicsActorType { 769 public override int PhysicsActorType {
@@ -778,7 +776,7 @@ public class BSPrim : BSPhysObject
778 if (_isPhysical != value) 776 if (_isPhysical != value)
779 { 777 {
780 _isPhysical = value; 778 _isPhysical = value;
781 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 779 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
782 { 780 {
783 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 781 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
784 SetObjectDynamic(true); 782 SetObjectDynamic(true);
@@ -822,24 +820,24 @@ public class BSPrim : BSPhysObject
822 // isSolid: other objects bounce off of this object 820 // isSolid: other objects bounce off of this object
823 // isVolumeDetect: other objects pass through but can generate collisions 821 // isVolumeDetect: other objects pass through but can generate collisions
824 // collisionEvents: whether this object returns collision events 822 // collisionEvents: whether this object returns collision events
823 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
825 public virtual void UpdatePhysicalParameters() 824 public virtual void UpdatePhysicalParameters()
826 { 825 {
827 if (!PhysBody.HasPhysicalBody) 826 if (!PhysBody.HasPhysicalBody)
828 { 827 {
829 // This would only happen if updates are called for during initialization when the body is not set up yet. 828 // This would only happen if updates are called for during initialization when the body is not set up yet.
830 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); 829 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
831 return; 830 return;
832 } 831 }
833 832
834 // Mangling all the physical properties requires the object not be in the physical world. 833 // Mangling all the physical properties requires the object not be in the physical world.
835 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 834 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
836 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 835 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
837 836
838 // Set up the object physicalness (does gravity and collisions move this object) 837 // Set up the object physicalness (does gravity and collisions move this object)
839 MakeDynamic(IsStatic); 838 MakeDynamic(IsStatic);
840 839
841 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) 840 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
842 VehicleActor.Refresh();
843 PhysicalActors.Refresh(); 841 PhysicalActors.Refresh();
844 842
845 // Arrange for collision events if the simulator wants them 843 // Arrange for collision events if the simulator wants them
@@ -851,10 +849,11 @@ public class BSPrim : BSPhysObject
851 AddObjectToPhysicalWorld(); 849 AddObjectToPhysicalWorld();
852 850
853 // Rebuild its shape 851 // Rebuild its shape
854 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 852 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
855 853
856 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", 854 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
857 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); 855 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
856 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
858 } 857 }
859 858
860 // "Making dynamic" means changing to and from static. 859 // "Making dynamic" means changing to and from static.
@@ -867,28 +866,28 @@ public class BSPrim : BSPhysObject
867 if (makeStatic) 866 if (makeStatic)
868 { 867 {
869 // Become a Bullet 'static' object type 868 // Become a Bullet 'static' object type
870 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 869 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
871 // Stop all movement 870 // Stop all movement
872 ZeroMotion(true); 871 ZeroMotion(true);
873 872
874 // Set various physical properties so other object interact properly 873 // Set various physical properties so other object interact properly
875 PhysicsScene.PE.SetFriction(PhysBody, Friction); 874 PhysScene.PE.SetFriction(PhysBody, Friction);
876 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 875 PhysScene.PE.SetRestitution(PhysBody, Restitution);
877 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 876 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
878 877
879 // Mass is zero which disables a bunch of physics stuff in Bullet 878 // Mass is zero which disables a bunch of physics stuff in Bullet
880 UpdatePhysicalMassProperties(0f, false); 879 UpdatePhysicalMassProperties(0f, false);
881 // Set collision detection parameters 880 // Set collision detection parameters
882 if (BSParam.CcdMotionThreshold > 0f) 881 if (BSParam.CcdMotionThreshold > 0f)
883 { 882 {
884 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 883 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
885 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 884 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
886 } 885 }
887 886
888 // The activation state is 'disabled' so Bullet will not try to act on it. 887 // The activation state is 'disabled' so Bullet will not try to act on it.
889 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); 888 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
890 // Start it out sleeping and physical actions could wake it up. 889 // Start it out sleeping and physical actions could wake it up.
891 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); 890 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
892 891
893 // This collides like a static object 892 // This collides like a static object
894 PhysBody.collisionType = CollisionType.Static; 893 PhysBody.collisionType = CollisionType.Static;
@@ -896,11 +895,11 @@ public class BSPrim : BSPhysObject
896 else 895 else
897 { 896 {
898 // Not a Bullet static object 897 // Not a Bullet static object
899 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); 898 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
900 899
901 // Set various physical properties so other object interact properly 900 // Set various physical properties so other object interact properly
902 PhysicsScene.PE.SetFriction(PhysBody, Friction); 901 PhysScene.PE.SetFriction(PhysBody, Friction);
903 PhysicsScene.PE.SetRestitution(PhysBody, Restitution); 902 PhysScene.PE.SetRestitution(PhysBody, Restitution);
904 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); 903 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
905 904
906 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 905 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
@@ -908,8 +907,8 @@ public class BSPrim : BSPhysObject
908 // PhysicsScene.PE.ClearAllForces(BSBody); 907 // PhysicsScene.PE.ClearAllForces(BSBody);
909 908
910 // For good measure, make sure the transform is set through to the motion state 909 // For good measure, make sure the transform is set through to the motion state
911 ForcePosition = _position; 910 ForcePosition = RawPosition;
912 ForceVelocity = _velocity; 911 ForceVelocity = RawVelocity;
913 ForceRotationalVelocity = _rotationalVelocity; 912 ForceRotationalVelocity = _rotationalVelocity;
914 913
915 // A dynamic object has mass 914 // A dynamic object has mass
@@ -918,22 +917,22 @@ public class BSPrim : BSPhysObject
918 // Set collision detection parameters 917 // Set collision detection parameters
919 if (BSParam.CcdMotionThreshold > 0f) 918 if (BSParam.CcdMotionThreshold > 0f)
920 { 919 {
921 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 920 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
922 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 921 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
923 } 922 }
924 923
925 // Various values for simulation limits 924 // Various values for simulation limits
926 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); 925 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
927 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); 926 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
928 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); 927 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
929 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 928 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
930 929
931 // This collides like an object. 930 // This collides like an object.
932 PhysBody.collisionType = CollisionType.Dynamic; 931 PhysBody.collisionType = CollisionType.Dynamic;
933 932
934 // Force activation of the object so Bullet will act on it. 933 // Force activation of the object so Bullet will act on it.
935 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 934 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
936 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 935 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
937 } 936 }
938 } 937 }
939 938
@@ -943,7 +942,7 @@ public class BSPrim : BSPhysObject
943 // the functions after this one set up the state of a possibly newly created collision body. 942 // the functions after this one set up the state of a possibly newly created collision body.
944 private void MakeSolid(bool makeSolid) 943 private void MakeSolid(bool makeSolid)
945 { 944 {
946 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); 945 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
947 if (makeSolid) 946 if (makeSolid)
948 { 947 {
949 // Verify the previous code created the correct shape for this type of thing. 948 // Verify the previous code created the correct shape for this type of thing.
@@ -951,7 +950,7 @@ public class BSPrim : BSPhysObject
951 { 950 {
952 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 951 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
953 } 952 }
954 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 953 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
955 } 954 }
956 else 955 else
957 { 956 {
@@ -959,32 +958,23 @@ public class BSPrim : BSPhysObject
959 { 958 {
960 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 959 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
961 } 960 }
962 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); 961 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
963 962
964 // Change collision info from a static object to a ghosty collision object 963 // Change collision info from a static object to a ghosty collision object
965 PhysBody.collisionType = CollisionType.VolumeDetect; 964 PhysBody.collisionType = CollisionType.VolumeDetect;
966 } 965 }
967 } 966 }
968 967
969 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
970 // they need waking up when parameters are changed.
971 // Called in taint-time!!
972 private void ActivateIfPhysical(bool forceIt)
973 {
974 if (IsPhysical && PhysBody.HasPhysicalBody)
975 PhysicsScene.PE.Activate(PhysBody, forceIt);
976 }
977
978 // Turn on or off the flag controlling whether collision events are returned to the simulator. 968 // Turn on or off the flag controlling whether collision events are returned to the simulator.
979 private void EnableCollisions(bool wantsCollisionEvents) 969 private void EnableCollisions(bool wantsCollisionEvents)
980 { 970 {
981 if (wantsCollisionEvents) 971 if (wantsCollisionEvents)
982 { 972 {
983 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 973 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
984 } 974 }
985 else 975 else
986 { 976 {
987 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 977 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
988 } 978 }
989 } 979 }
990 980
@@ -995,7 +985,7 @@ public class BSPrim : BSPhysObject
995 { 985 {
996 if (PhysBody.HasPhysicalBody) 986 if (PhysBody.HasPhysicalBody)
997 { 987 {
998 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 988 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
999 } 989 }
1000 else 990 else
1001 { 991 {
@@ -1030,12 +1020,12 @@ public class BSPrim : BSPhysObject
1030 public override bool FloatOnWater { 1020 public override bool FloatOnWater {
1031 set { 1021 set {
1032 _floatOnWater = value; 1022 _floatOnWater = value;
1033 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 1023 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1034 { 1024 {
1035 if (_floatOnWater) 1025 if (_floatOnWater)
1036 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 1026 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1037 else 1027 else
1038 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 1028 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1039 }); 1029 });
1040 } 1030 }
1041 } 1031 }
@@ -1047,7 +1037,7 @@ public class BSPrim : BSPhysObject
1047 _rotationalVelocity = value; 1037 _rotationalVelocity = value;
1048 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); 1038 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1049 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 1039 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1050 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 1040 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1051 { 1041 {
1052 ForceRotationalVelocity = _rotationalVelocity; 1042 ForceRotationalVelocity = _rotationalVelocity;
1053 }); 1043 });
@@ -1062,7 +1052,7 @@ public class BSPrim : BSPhysObject
1062 if (PhysBody.HasPhysicalBody) 1052 if (PhysBody.HasPhysicalBody)
1063 { 1053 {
1064 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 1054 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1065 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); 1055 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1066 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); 1056 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1067 ActivateIfPhysical(false); 1057 ActivateIfPhysical(false);
1068 } 1058 }
@@ -1078,7 +1068,7 @@ public class BSPrim : BSPhysObject
1078 get { return _buoyancy; } 1068 get { return _buoyancy; }
1079 set { 1069 set {
1080 _buoyancy = value; 1070 _buoyancy = value;
1081 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() 1071 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1082 { 1072 {
1083 ForceBuoyancy = _buoyancy; 1073 ForceBuoyancy = _buoyancy;
1084 }); 1074 });
@@ -1096,179 +1086,54 @@ public class BSPrim : BSPhysObject
1096 } 1086 }
1097 } 1087 }
1098 1088
1099 // Used for MoveTo
1100 public override OMV.Vector3 PIDTarget {
1101 set
1102 {
1103 // TODO: add a sanity check -- don't move more than a region or something like that.
1104 _PIDTarget = value;
1105 }
1106 }
1107 public override float PIDTau {
1108 set { _PIDTau = value; }
1109 }
1110 public override bool PIDActive { 1089 public override bool PIDActive {
1111 set { 1090 set {
1112 if (value) 1091 base.MoveToTargetActive = value;
1092 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1113 { 1093 {
1114 // We're taking over after this. 1094 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1115 ZeroMotion(true); 1095 });
1116 1096 }
1117 _targetMotor = new BSVMotor("BSPrim.PIDTarget", 1097 }
1118 _PIDTau, // timeScale
1119 BSMotor.Infinite, // decay time scale
1120 BSMotor.InfiniteVector, // friction timescale
1121 1f // efficiency
1122 );
1123 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1124 _targetMotor.SetTarget(_PIDTarget);
1125 _targetMotor.SetCurrent(RawPosition);
1126 /*
1127 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1128 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1129
1130 _targetMotor.SetTarget(_PIDTarget);
1131 _targetMotor.SetCurrent(RawPosition);
1132 _targetMotor.TimeScale = _PIDTau;
1133 _targetMotor.Efficiency = 1f;
1134 */
1135
1136 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1137 {
1138 if (!IsPhysicallyActive)
1139 {
1140 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1141 return;
1142 }
1143
1144 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1145
1146 // 'movePosition' is where we'd like the prim to be at this moment.
1147 OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
1148 1098
1149 // If we are very close to our target, turn off the movement motor. 1099 public override OMV.Vector3 PIDTarget
1150 if (_targetMotor.ErrorIsZero()) 1100 {
1151 { 1101 set
1152 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", 1102 {
1153 LocalID, movePosition, RawPosition, Mass); 1103 base.PIDTarget = value;
1154 ForcePosition = _targetMotor.TargetValue; 1104 BSActor actor;
1155 _targetMotor.Enabled = false; 1105 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1156 }
1157 else
1158 {
1159 _position = movePosition;
1160 PositionSanityCheck(true /* intaintTime */);
1161 ForcePosition = _position;
1162 }
1163 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1164 });
1165 }
1166 else
1167 { 1106 {
1168 // Stop any targetting 1107 // if the actor exists, tell it to refresh its values.
1169 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); 1108 actor.Refresh();
1170 } 1109 }
1110
1171 } 1111 }
1172 } 1112 }
1173
1174 // Used for llSetHoverHeight and maybe vehicle height 1113 // Used for llSetHoverHeight and maybe vehicle height
1175 // Hover Height will override MoveTo target's Z 1114 // Hover Height will override MoveTo target's Z
1176 public override bool PIDHoverActive { 1115 public override bool PIDHoverActive {
1177 set { 1116 set {
1178 if (value) 1117 base.HoverActive = value;
1118 EnableActor(HoverActive, HoverActorName, delegate()
1179 { 1119 {
1180 // Turning the target on 1120 return new BSActorHover(PhysScene, this, HoverActorName);
1181 _hoverMotor = new BSFMotor("BSPrim.Hover", 1121 });
1182 _PIDHoverTau, // timeScale
1183 BSMotor.Infinite, // decay time scale
1184 BSMotor.Infinite, // friction timescale
1185 1f // efficiency
1186 );
1187 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1188 _hoverMotor.SetCurrent(RawPosition.Z);
1189 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1190
1191 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1192 {
1193 // Don't do hovering while the object is selected.
1194 if (!IsPhysicallyActive)
1195 return;
1196
1197 _hoverMotor.SetCurrent(RawPosition.Z);
1198 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1199 float targetHeight = _hoverMotor.Step(timeStep);
1200
1201 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1202 // Compute the amount of force to push us there.
1203 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1204 // Undo anything the object thinks it's doing at the moment
1205 moveForce = -RawVelocity.Z * Mass;
1206
1207 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1208 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1209 });
1210 }
1211 else
1212 {
1213 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1214 }
1215 }
1216 }
1217 public override float PIDHoverHeight {
1218 set { _PIDHoverHeight = value; }
1219 }
1220 public override PIDHoverType PIDHoverType {
1221 set { _PIDHoverType = value; }
1222 }
1223 public override float PIDHoverTau {
1224 set { _PIDHoverTau = value; }
1225 }
1226 // Based on current position, determine what we should be hovering at now.
1227 // Must recompute often. What if we walked offa cliff>
1228 private float ComputeCurrentPIDHoverHeight()
1229 {
1230 float ret = _PIDHoverHeight;
1231 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1232
1233 switch (_PIDHoverType)
1234 {
1235 case PIDHoverType.Ground:
1236 ret = groundHeight + _PIDHoverHeight;
1237 break;
1238 case PIDHoverType.GroundAndWater:
1239 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1240 if (groundHeight > waterHeight)
1241 {
1242 ret = groundHeight + _PIDHoverHeight;
1243 }
1244 else
1245 {
1246 ret = waterHeight + _PIDHoverHeight;
1247 }
1248 break;
1249 } 1122 }
1250 return ret;
1251 } 1123 }
1252 1124
1253
1254 // For RotLookAt
1255 public override OMV.Quaternion APIDTarget { set { return; } }
1256 public override bool APIDActive { set { return; } }
1257 public override float APIDStrength { set { return; } }
1258 public override float APIDDamping { set { return; } }
1259
1260 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1125 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1261 // Per documentation, max force is limited. 1126 // Per documentation, max force is limited.
1262 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 1127 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1263 1128
1264 // Since this force is being applied in only one step, make this a force per second. 1129 // Since this force is being applied in only one step, make this a force per second.
1265 addForce /= PhysicsScene.LastTimeStep; 1130 addForce /= PhysScene.LastTimeStep;
1266 AddForce(addForce, pushforce, false /* inTaintTime */); 1131 AddForce(addForce, pushforce, false /* inTaintTime */);
1267 } 1132 }
1268 1133
1269 // Applying a force just adds this to the total force on the object. 1134 // Applying a force just adds this to the total force on the object.
1270 // This added force will only last the next simulation tick. 1135 // This added force will only last the next simulation tick.
1271 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1136 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1272 // for an object, doesn't matter if force is a pushforce or not 1137 // for an object, doesn't matter if force is a pushforce or not
1273 if (IsPhysicallyActive) 1138 if (IsPhysicallyActive)
1274 { 1139 {
@@ -1277,13 +1142,15 @@ public class BSPrim : BSPhysObject
1277 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); 1142 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1278 1143
1279 OMV.Vector3 addForce = force; 1144 OMV.Vector3 addForce = force;
1280 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() 1145 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1281 { 1146 {
1282 // Bullet adds this central force to the total force for this tick 1147 // Bullet adds this central force to the total force for this tick.
1148 // Deep down in Bullet:
1149 // linearVelocity += totalForce / mass * timeStep;
1283 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); 1150 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1284 if (PhysBody.HasPhysicalBody) 1151 if (PhysBody.HasPhysicalBody)
1285 { 1152 {
1286 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 1153 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1287 ActivateIfPhysical(false); 1154 ActivateIfPhysical(false);
1288 } 1155 }
1289 }); 1156 });
@@ -1305,13 +1172,13 @@ public class BSPrim : BSPhysObject
1305 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); 1172 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1306 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); 1173 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1307 1174
1308 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() 1175 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1309 { 1176 {
1310 // Bullet adds this impulse immediately to the velocity 1177 // Bullet adds this impulse immediately to the velocity
1311 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); 1178 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1312 if (PhysBody.HasPhysicalBody) 1179 if (PhysBody.HasPhysicalBody)
1313 { 1180 {
1314 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); 1181 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1315 ActivateIfPhysical(false); 1182 ActivateIfPhysical(false);
1316 } 1183 }
1317 }); 1184 });
@@ -1324,20 +1191,18 @@ public class BSPrim : BSPhysObject
1324 } 1191 }
1325 } 1192 }
1326 1193
1327 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1194 // BSPhysObject.AddAngularForce()
1328 AddAngularForce(force, pushforce, false); 1195 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1329 }
1330 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1331 { 1196 {
1332 if (force.IsFinite()) 1197 if (force.IsFinite())
1333 { 1198 {
1334 OMV.Vector3 angForce = force; 1199 OMV.Vector3 angForce = force;
1335 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() 1200 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1336 { 1201 {
1337 if (PhysBody.HasPhysicalBody) 1202 if (PhysBody.HasPhysicalBody)
1338 { 1203 {
1339 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); 1204 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1340 PhysicsScene.PE.ApplyTorque(PhysBody, angForce); 1205 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1341 ActivateIfPhysical(false); 1206 ActivateIfPhysical(false);
1342 } 1207 }
1343 }); 1208 });
@@ -1356,11 +1221,11 @@ public class BSPrim : BSPhysObject
1356 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1221 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1357 { 1222 {
1358 OMV.Vector3 applyImpulse = impulse; 1223 OMV.Vector3 applyImpulse = impulse;
1359 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1224 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1360 { 1225 {
1361 if (PhysBody.HasPhysicalBody) 1226 if (PhysBody.HasPhysicalBody)
1362 { 1227 {
1363 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); 1228 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1364 ActivateIfPhysical(false); 1229 ActivateIfPhysical(false);
1365 } 1230 }
1366 }); 1231 });
@@ -1649,6 +1514,8 @@ public class BSPrim : BSPhysObject
1649 1514
1650 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); 1515 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1651 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); 1516 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1517 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1518 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1652 1519
1653 return returnMass; 1520 return returnMass;
1654 }// end CalculateMass 1521 }// end CalculateMass
@@ -1661,13 +1528,14 @@ public class BSPrim : BSPhysObject
1661 { 1528 {
1662 // Create the correct physical representation for this type of object. 1529 // Create the correct physical representation for this type of object.
1663 // Updates base.PhysBody and base.PhysShape with the new information. 1530 // Updates base.PhysBody and base.PhysShape with the new information.
1664 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1531 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1665 PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1532 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1666 { 1533 {
1667 // Called if the current prim body is about to be destroyed. 1534 // Called if the current prim body is about to be destroyed.
1668 // Remove all the physical dependencies on the old body. 1535 // Remove all the physical dependencies on the old body.
1669 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) 1536 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1670 RemoveBodyDependencies(); 1537 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1538 RemoveDependencies();
1671 }); 1539 });
1672 1540
1673 // Make sure the properties are set on the new object 1541 // Make sure the properties are set on the new object
@@ -1675,27 +1543,45 @@ public class BSPrim : BSPhysObject
1675 return; 1543 return;
1676 } 1544 }
1677 1545
1678 protected virtual void RemoveBodyDependencies() 1546 // Called at taint-time
1547 protected virtual void RemoveDependencies()
1548 {
1549 PhysicalActors.RemoveDependencies();
1550 }
1551
1552 #region Extension
1553 public override object Extension(string pFunct, params object[] pParams)
1679 { 1554 {
1680 VehicleActor.RemoveBodyDependencies(); 1555 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1681 PhysicalActors.RemoveBodyDependencies(); 1556 object ret = null;
1557 switch (pFunct)
1558 {
1559 default:
1560 ret = base.Extension(pFunct, pParams);
1561 break;
1562 }
1563 return ret;
1682 } 1564 }
1565 #endregion // Extension
1683 1566
1684 // The physics engine says that properties have updated. Update same and inform 1567 // The physics engine says that properties have updated. Update same and inform
1685 // the world that things have changed. 1568 // the world that things have changed.
1569 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1570 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1686 public override void UpdateProperties(EntityProperties entprop) 1571 public override void UpdateProperties(EntityProperties entprop)
1687 { 1572 {
1573 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1688 TriggerPreUpdatePropertyAction(ref entprop); 1574 TriggerPreUpdatePropertyAction(ref entprop);
1689 1575
1690 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG 1576 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1691 1577
1692 // Assign directly to the local variables so the normal set actions do not happen 1578 // Assign directly to the local variables so the normal set actions do not happen
1693 _position = entprop.Position; 1579 RawPosition = entprop.Position;
1694 _orientation = entprop.Rotation; 1580 RawOrientation = entprop.Rotation;
1695 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be 1581 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1696 // very sensitive to velocity changes. 1582 // very sensitive to velocity changes.
1697 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) 1583 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1698 _velocity = entprop.Velocity; 1584 RawVelocity = entprop.Velocity;
1699 _acceleration = entprop.Acceleration; 1585 _acceleration = entprop.Acceleration;
1700 _rotationalVelocity = entprop.RotationalVelocity; 1586 _rotationalVelocity = entprop.RotationalVelocity;
1701 1587
@@ -1704,29 +1590,20 @@ public class BSPrim : BSPhysObject
1704 // The sanity check can change the velocity and/or position. 1590 // The sanity check can change the velocity and/or position.
1705 if (PositionSanityCheck(true /* inTaintTime */ )) 1591 if (PositionSanityCheck(true /* inTaintTime */ ))
1706 { 1592 {
1707 entprop.Position = _position; 1593 entprop.Position = RawPosition;
1708 entprop.Velocity = _velocity; 1594 entprop.Velocity = RawVelocity;
1709 entprop.RotationalVelocity = _rotationalVelocity; 1595 entprop.RotationalVelocity = _rotationalVelocity;
1710 entprop.Acceleration = _acceleration; 1596 entprop.Acceleration = _acceleration;
1711 } 1597 }
1712 1598
1713 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG 1599 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1714 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); 1600 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1715 1601
1716 // remember the current and last set values 1602 // remember the current and last set values
1717 LastEntityProperties = CurrentEntityProperties; 1603 LastEntityProperties = CurrentEntityProperties;
1718 CurrentEntityProperties = entprop; 1604 CurrentEntityProperties = entprop;
1719 1605
1720 base.RequestPhysicsterseUpdate(); 1606 PhysScene.PostUpdate(this);
1721 /*
1722 else
1723 {
1724 // For debugging, report the movement of children
1725 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1726 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1727 entprop.Acceleration, entprop.RotationalVelocity);
1728 }
1729 */
1730 } 1607 }
1731} 1608}
1732} 1609}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
index f1c3b5c..2eb1440 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs
@@ -23,11 +23,6 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * of Creative Commons Attribution-Share Alike 3.0
30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31 */ 26 */
32 27
33using System; 28using System;
@@ -44,14 +39,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
44{ 39{
45public class BSPrimDisplaced : BSPrim 40public class BSPrimDisplaced : BSPrim
46{ 41{
47 // The purpose of this module is to do any mapping between what the simulator thinks 42 // The purpose of this subclass is to do any mapping between what the simulator thinks
48 // the prim position and orientation is and what the physical position/orientation. 43 // the prim position and orientation is and what the physical position/orientation.
49 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> 44 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
50 // of the prim/linkset. The simulator tracks the location of the prim/linkset by 45 // of the prim/linkset. The simulator, on the other hand, tracks the location of
51 // the location of the root prim. So, if center-of-mass is anywhere but the origin 46 // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere
52 // of the root prim, the physical origin is displaced from the simulator origin. 47 // but the origin of the root prim, the physical origin is displaced from the simulator origin.
53 // 48 //
54 // This routine works by capturing the Force* setting of position/orientation/... and 49 // This routine works by capturing ForcePosition and
55 // adjusting the simulator values (being set) into the physical values. 50 // adjusting the simulator values (being set) into the physical values.
56 // The conversion is also done in the opposite direction (physical origin -> simulator origin). 51 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
57 // 52 //
@@ -59,8 +54,8 @@ public class BSPrimDisplaced : BSPrim
59 // are converted into simulator origin values before being passed to the base 54 // are converted into simulator origin values before being passed to the base
60 // class. 55 // class.
61 56
57 // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass.
62 public virtual OMV.Vector3 PositionDisplacement { get; set; } 58 public virtual OMV.Vector3 PositionDisplacement { get; set; }
63 public virtual OMV.Quaternion OrientationDisplacement { get; set; }
64 59
65 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 60 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
66 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 61 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -69,68 +64,96 @@ public class BSPrimDisplaced : BSPrim
69 ClearDisplacement(); 64 ClearDisplacement();
70 } 65 }
71 66
67 // Clears any center-of-mass displacement introduced by linksets, etc.
68 // Does not clear the displacement set by the user.
72 public void ClearDisplacement() 69 public void ClearDisplacement()
73 { 70 {
74 PositionDisplacement = OMV.Vector3.Zero; 71 if (UserSetCenterOfMassDisplacement.HasValue)
75 OrientationDisplacement = OMV.Quaternion.Identity; 72 PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement;
73 else
74 PositionDisplacement = OMV.Vector3.Zero;
76 } 75 }
77 76
78 // Set this sets and computes the displacement from the passed prim to the center-of-mass. 77 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
79 // A user set value for center-of-mass overrides whatever might be passed in here. 78 // A user set value for center-of-mass overrides whatever might be passed in here.
80 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). 79 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
81 public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) 80 // Returns the relative offset from the root position to the center-of-mass.
81 // Called at taint time.
82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
82 { 83 {
84 PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
83 Vector3 comDisp; 85 Vector3 comDisp;
84 if (UserSetCenterOfMass.HasValue) 86 if (UserSetCenterOfMassDisplacement.HasValue)
85 comDisp = (OMV.Vector3)UserSetCenterOfMass; 87 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
86 else 88 else
87 comDisp = centerOfMassDisplacement; 89 comDisp = centerOfMassDisplacement;
88 90
89 if (comDisp == Vector3.Zero) 91 // Eliminate any jitter caused be very slight differences in masses and positions
90 { 92 if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) )
91 // If there is no diplacement. Things get reset. 93 comDisp = Vector3.Zero;
92 PositionDisplacement = OMV.Vector3.Zero; 94
93 OrientationDisplacement = OMV.Quaternion.Identity; 95 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
94 } 96 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
95 else 97 if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) )
96 { 98 {
97 // Remember the displacement from root as well as the origional rotation of the 99 // Displacement setting is changing.
98 // new center-of-mass. 100 // The relationship between the physical object and simulated object must be aligned.
99 PositionDisplacement = comDisp; 101 PositionDisplacement = comDisp;
100 OrientationDisplacement = OMV.Quaternion.Identity; 102 this.ForcePosition = RawPosition;
101 } 103 }
104
105 return PositionDisplacement;
102 } 106 }
103 107
108 // 'ForcePosition' is the one way to set the physical position of the body in the physics engine.
109 // Displace the simulator idea of position (center of root prim) to the physical position.
104 public override Vector3 ForcePosition 110 public override Vector3 ForcePosition
105 { 111 {
106 get { return base.ForcePosition; } 112 get {
113 OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody);
114 if (PositionDisplacement != OMV.Vector3.Zero)
115 {
116 // If there is some displacement, return the physical position (center-of-mass)
117 // location minus the displacement to give the center of the root prim.
118 OMV.Vector3 displacement = PositionDisplacement * ForceOrientation;
119 DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}",
120 LocalID, physPosition, displacement, physPosition - displacement);
121 physPosition -= displacement;
122 }
123 RawPosition = physPosition;
124 return physPosition;
125 }
107 set 126 set
108 { 127 {
109 if (PositionDisplacement != OMV.Vector3.Zero) 128 if (PositionDisplacement != OMV.Vector3.Zero)
110 base.ForcePosition = value - (PositionDisplacement * RawOrientation); 129 {
130 // This value is the simulator's idea of where the prim is: the center of the root prim
131 RawPosition = value;
132
133 // Move the passed root prim postion to the center-of-mass position and set in the physics engine.
134 OMV.Vector3 displacement = PositionDisplacement * RawOrientation;
135 OMV.Vector3 displacedPos = RawPosition + displacement;
136 DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}",
137 LocalID, RawPosition, displacement, displacedPos);
138 if (PhysBody.HasPhysicalBody)
139 {
140 PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation);
141 ActivateIfPhysical(false);
142 }
143 }
111 else 144 else
145 {
112 base.ForcePosition = value; 146 base.ForcePosition = value;
147 }
113 } 148 }
114 } 149 }
115 150
116 public override Quaternion ForceOrientation 151 // These are also overridden by BSPrimLinkable if the prim can be part of a linkset
117 {
118 get { return base.ForceOrientation; }
119 set
120 {
121 base.ForceOrientation = value;
122 }
123 }
124
125 // TODO: decide if this is the right place for these variables.
126 // Somehow incorporate the optional settability by the user.
127 // Is this used?
128 public override OMV.Vector3 CenterOfMass 152 public override OMV.Vector3 CenterOfMass
129 { 153 {
130 get { return RawPosition; } 154 get { return RawPosition; }
131 } 155 }
132 156
133 // Is this used?
134 public override OMV.Vector3 GeometricCenter 157 public override OMV.Vector3 GeometricCenter
135 { 158 {
136 get { return RawPosition; } 159 get { return RawPosition; }
@@ -139,12 +162,18 @@ public class BSPrimDisplaced : BSPrim
139 public override void UpdateProperties(EntityProperties entprop) 162 public override void UpdateProperties(EntityProperties entprop)
140 { 163 {
141 // Undo any center-of-mass displacement that might have been done. 164 // Undo any center-of-mass displacement that might have been done.
142 if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) 165 if (PositionDisplacement != OMV.Vector3.Zero)
143 { 166 {
144 // Correct for any rotation around the center-of-mass 167 // The origional shape was offset from 'zero' by PositionDisplacement.
145 // TODO!!! 168 // These physical location must be back converted to be centered around the displaced
146 entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); 169 // root shape.
147 // entprop.Rotation = something; 170
171 // Move the returned center-of-mass location to the root prim location.
172 OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation;
173 OMV.Vector3 displacedPos = entprop.Position - displacement;
174 DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}",
175 LocalID, entprop.Position, displacement, displacedPos);
176 entprop.Position = displacedPos;
148 } 177 }
149 178
150 base.UpdateProperties(entprop); 179 base.UpdateProperties(entprop);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
index d65d407..126b146 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs
@@ -30,6 +30,7 @@ using System.Linq;
30using System.Text; 30using System.Text;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.OptionalModules.Scripting;
33 34
34using OMV = OpenMetaverse; 35using OMV = OpenMetaverse;
35 36
@@ -37,44 +38,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin
37{ 38{
38public class BSPrimLinkable : BSPrimDisplaced 39public class BSPrimLinkable : BSPrimDisplaced
39{ 40{
41 // The purpose of this subclass is to add linkset functionality to the prim. This overrides
42 // operations necessary for keeping the linkset created and, additionally, this
43 // calls the linkset implementation for its creation and management.
44
45 private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
46
47 // This adds the overrides for link() and delink() so the prim is linkable.
48
40 public BSLinkset Linkset { get; set; } 49 public BSLinkset Linkset { get; set; }
41 // The index of this child prim. 50 // The index of this child prim.
42 public int LinksetChildIndex { get; set; } 51 public int LinksetChildIndex { get; set; }
43 52
44 public BSLinksetInfo LinksetInfo { get; set; } 53 public BSLinkset.LinksetImplementation LinksetType { get; set; }
45 54
46 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 55 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
47 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 56 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
48 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) 57 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
49 { 58 {
50 Linkset = BSLinkset.Factory(PhysicsScene, this); 59 // Default linkset implementation for this prim
60 LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
51 61
52 PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() 62 Linkset = BSLinkset.Factory(PhysScene, this);
53 { 63
54 Linkset.Refresh(this); 64 Linkset.Refresh(this);
55 });
56 } 65 }
57 66
58 public override void Destroy() 67 public override void Destroy()
59 { 68 {
60 Linkset = Linkset.RemoveMeFromLinkset(this); 69 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
61 base.Destroy(); 70 base.Destroy();
62 } 71 }
63 72
64 public override BSPhysicsShapeType PreferredPhysicalShape
65 { get { return Linkset.PreferredPhysicalShape(this); } }
66
67 public override void link(Manager.PhysicsActor obj) 73 public override void link(Manager.PhysicsActor obj)
68 { 74 {
69 BSPrimLinkable parent = obj as BSPrimLinkable; 75 BSPrimLinkable parent = obj as BSPrimLinkable;
70 if (parent != null) 76 if (parent != null)
71 { 77 {
72 BSPhysObject parentBefore = Linkset.LinksetRoot; 78 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
73 int childrenBefore = Linkset.NumberOfChildren; 79 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
74 80
75 Linkset = parent.Linkset.AddMeToLinkset(this); 81 Linkset = parent.Linkset.AddMeToLinkset(this);
76 82
77 DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 83 DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
78 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 84 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
79 } 85 }
80 return; 86 return;
@@ -85,12 +91,12 @@ public class BSPrimLinkable : BSPrimDisplaced
85 // TODO: decide if this parent checking needs to happen at taint time 91 // TODO: decide if this parent checking needs to happen at taint time
86 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 92 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
87 93
88 BSPhysObject parentBefore = Linkset.LinksetRoot; 94 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
89 int childrenBefore = Linkset.NumberOfChildren; 95 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
90 96
91 Linkset = Linkset.RemoveMeFromLinkset(this); 97 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
92 98
93 DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 99 DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
94 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 100 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
95 return; 101 return;
96 } 102 }
@@ -102,7 +108,7 @@ public class BSPrimLinkable : BSPrimDisplaced
102 set 108 set
103 { 109 {
104 base.Position = value; 110 base.Position = value;
105 PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() 111 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
106 { 112 {
107 Linkset.UpdateProperties(UpdatedProperties.Position, this); 113 Linkset.UpdateProperties(UpdatedProperties.Position, this);
108 }); 114 });
@@ -116,7 +122,7 @@ public class BSPrimLinkable : BSPrimDisplaced
116 set 122 set
117 { 123 {
118 base.Orientation = value; 124 base.Orientation = value;
119 PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() 125 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
120 { 126 {
121 Linkset.UpdateProperties(UpdatedProperties.Orientation, this); 127 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
122 }); 128 });
@@ -128,6 +134,17 @@ public class BSPrimLinkable : BSPrimDisplaced
128 get { return Linkset.LinksetMass; } 134 get { return Linkset.LinksetMass; }
129 } 135 }
130 136
137 public override OMV.Vector3 CenterOfMass
138 {
139 get { return Linkset.CenterOfMass; }
140 }
141
142 public override OMV.Vector3 GeometricCenter
143 {
144 get { return Linkset.GeometricCenter; }
145 }
146
147 // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
131 public override void UpdatePhysicalParameters() 148 public override void UpdatePhysicalParameters()
132 { 149 {
133 base.UpdatePhysicalParameters(); 150 base.UpdatePhysicalParameters();
@@ -139,44 +156,193 @@ public class BSPrimLinkable : BSPrimDisplaced
139 Linkset.Refresh(this); 156 Linkset.Refresh(this);
140 } 157 }
141 158
159 // When the prim is made dynamic or static, the linkset needs to change.
142 protected override void MakeDynamic(bool makeStatic) 160 protected override void MakeDynamic(bool makeStatic)
143 { 161 {
144 base.MakeDynamic(makeStatic); 162 base.MakeDynamic(makeStatic);
145 if (makeStatic) 163 if (Linkset != null) // null can happen during initialization
146 Linkset.MakeStatic(this); 164 {
147 else 165 if (makeStatic)
148 Linkset.MakeDynamic(this); 166 Linkset.MakeStatic(this);
167 else
168 Linkset.MakeDynamic(this);
169 }
149 } 170 }
150 171
151 // Body is being taken apart. Remove physical dependencies and schedule a rebuild. 172 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
152 protected override void RemoveBodyDependencies() 173 protected override void RemoveDependencies()
153 { 174 {
154 Linkset.RemoveBodyDependencies(this); 175 Linkset.RemoveDependencies(this);
155 base.RemoveBodyDependencies(); 176 base.RemoveDependencies();
156 } 177 }
157 178
179 // Called after a simulation step for the changes in physical object properties.
180 // Do any filtering/modification needed for linksets.
158 public override void UpdateProperties(EntityProperties entprop) 181 public override void UpdateProperties(EntityProperties entprop)
159 { 182 {
160 if (Linkset.IsRoot(this)) 183 if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
161 { 184 {
162 // Properties are only updated for the roots of a linkset. 185 // Properties are only updated for the roots of a linkset.
163 // TODO: this will have to change when linksets are articulated. 186 // TODO: this will have to change when linksets are articulated.
164 base.UpdateProperties(entprop); 187 base.UpdateProperties(entprop);
165 } 188 }
189 /*
190 else
191 {
192 // For debugging, report the movement of children
193 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
194 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
195 entprop.Acceleration, entprop.RotationalVelocity);
196 }
197 */
166 // The linkset might like to know about changing locations 198 // The linkset might like to know about changing locations
167 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); 199 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
168 } 200 }
169 201
202 // Called after a simulation step to post a collision with this object.
203 // This returns 'true' if the collision has been queued and the SendCollisions call must
204 // be made at the end of the simulation step.
170 public override bool Collide(uint collidingWith, BSPhysObject collidee, 205 public override bool Collide(uint collidingWith, BSPhysObject collidee,
171 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 206 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
172 { 207 {
173 // prims in the same linkset cannot collide with each other 208 bool ret = false;
174 BSPrimLinkable convCollidee = collidee as BSPrimLinkable; 209 // Ask the linkset if it wants to handle the collision
175 if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) 210 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
211 {
212 // The linkset didn't handle it so pass the collision through normal processing
213 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
214 }
215 return ret;
216 }
217
218 // A linkset reports any collision on any part of the linkset.
219 public long SomeCollisionSimulationStep = 0;
220 public override bool HasSomeCollision
221 {
222 get
223 {
224 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
225 }
226 set
176 { 227 {
177 return false; 228 if (value)
229 SomeCollisionSimulationStep = PhysScene.SimulationStep;
230 else
231 SomeCollisionSimulationStep = 0;
232
233 base.HasSomeCollision = value;
234 }
235 }
236
237 // Convert the existing linkset of this prim into a new type.
238 public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
239 {
240 bool ret = false;
241 if (LinksetType != newType)
242 {
243 DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
244
245 // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
246 this.LinksetType = newType;
247
248 BSLinkset oldLinkset = this.Linkset;
249 BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
250
251 this.Linkset = newLinkset;
252
253 // Pick up any physical dependencies this linkset might have in the physics engine.
254 oldLinkset.RemoveDependencies(this);
255
256 // Create a list of the children (mainly because can't interate through a list that's changing)
257 List<BSPrimLinkable> children = new List<BSPrimLinkable>();
258 oldLinkset.ForEachMember((child) =>
259 {
260 if (!oldLinkset.IsRoot(child))
261 children.Add(child);
262 return false; // 'false' says to continue to next member
263 });
264
265 // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
266 foreach (BSPrimLinkable child in children)
267 {
268 oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
269 }
270 foreach (BSPrimLinkable child in children)
271 {
272 newLinkset.AddMeToLinkset(child);
273 child.Linkset = newLinkset;
274 }
275
276 // Force the shape and linkset to get reconstructed
277 newLinkset.Refresh(this);
278 this.ForceBodyShapeRebuild(true /* inTaintTime */);
279 }
280 return ret;
281 }
282
283 #region Extension
284 public override object Extension(string pFunct, params object[] pParams)
285 {
286 DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
287 object ret = null;
288 switch (pFunct)
289 {
290 // physGetLinksetType();
291 // pParams = [ BSPhysObject root, null ]
292 case ExtendedPhysics.PhysFunctGetLinksetType:
293 {
294 ret = (object)LinksetType;
295 DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
296 break;
297 }
298 // physSetLinksetType(type);
299 // pParams = [ BSPhysObject root, null, integer type ]
300 case ExtendedPhysics.PhysFunctSetLinksetType:
301 {
302 if (pParams.Length > 2)
303 {
304 BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
305 if (Linkset.IsRoot(this))
306 {
307 PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
308 {
309 // Cause the linkset type to change
310 DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
311 LocalID, Linkset.LinksetImpl, linksetType);
312 ConvertLinkset(linksetType);
313 });
314 }
315 ret = (object)(int)linksetType;
316 }
317 break;
318 }
319 // physChangeLinkType(linknum, typeCode);
320 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
321 case ExtendedPhysics.PhysFunctChangeLinkType:
322 {
323 ret = Linkset.Extension(pFunct, pParams);
324 break;
325 }
326 // physGetLinkType(linknum);
327 // pParams = [ BSPhysObject root, BSPhysObject child ]
328 case ExtendedPhysics.PhysFunctGetLinkType:
329 {
330 ret = Linkset.Extension(pFunct, pParams);
331 break;
332 }
333 // physChangeLinkParams(linknum, [code, value, code, value, ...]);
334 // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
335 case ExtendedPhysics.PhysFunctChangeLinkParams:
336 {
337 ret = Linkset.Extension(pFunct, pParams);
338 break;
339 }
340 default:
341 ret = base.Extension(pFunct, pParams);
342 break;
178 } 343 }
179 return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); 344 return ret;
180 } 345 }
346 #endregion // Extension
181} 347}
182} 348}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 9818b05..b3dfa41 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -56,12 +56,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
56 public string BulletEngineName { get; private set; } 56 public string BulletEngineName { get; private set; }
57 public BSAPITemplate PE; 57 public BSAPITemplate PE;
58 58
59 // If the physics engine is running on a separate thread
60 public Thread m_physicsThread;
61
59 public Dictionary<uint, BSPhysObject> PhysObjects; 62 public Dictionary<uint, BSPhysObject> PhysObjects;
60 public BSShapeCollection Shapes; 63 public BSShapeCollection Shapes;
61 64
62 // Keeping track of the objects with collisions so we can report begin and end of a collision 65 // Keeping track of the objects with collisions so we can report begin and end of a collision
63 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>(); 66 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
64 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>(); 67 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
68
69 // All the collision processing is protected with this lock object
70 public Object CollisionLock = new Object();
71
72 // Properties are updated here
73 public Object UpdateLock = new Object();
74 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
75
65 // Keep track of all the avatars so we can send them a collision event 76 // Keep track of all the avatars so we can send them a collision event
66 // every tick so OpenSim will update its animation. 77 // every tick so OpenSim will update its animation.
67 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 78 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
@@ -77,12 +88,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
77 public BSConstraintCollection Constraints { get; private set; } 88 public BSConstraintCollection Constraints { get; private set; }
78 89
79 // Simulation parameters 90 // Simulation parameters
91 internal float m_physicsStepTime; // if running independently, the interval simulated by default
92
80 internal int m_maxSubSteps; 93 internal int m_maxSubSteps;
81 internal float m_fixedTimeStep; 94 internal float m_fixedTimeStep;
82 internal long m_simulationStep = 0; 95
83 internal float NominalFrameRate { get; set; } 96 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
97
98 internal long m_simulationStep = 0; // The current simulation step.
84 public long SimulationStep { get { return m_simulationStep; } } 99 public long SimulationStep { get { return m_simulationStep; } }
85 internal float LastTimeStep { get; private set; } 100 // A number to use for SimulationStep that is probably not any step value
101 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
102 public static long NotASimulationStep = -1234;
103
104 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
105
106 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
86 107
87 // Physical objects can register for prestep or poststep events 108 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep); 109 public delegate void PreStepAction(float timeStep);
@@ -90,7 +111,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
90 public event PreStepAction BeforeStep; 111 public event PreStepAction BeforeStep;
91 public event PostStepAction AfterStep; 112 public event PostStepAction AfterStep;
92 113
93 // A value of the time now so all the collision and update routines do not have to get their own 114 // A value of the time 'now' so all the collision and update routines do not have to get their own
94 // Set to 'now' just before all the prims and actors are called for collisions and updates 115 // Set to 'now' just before all the prims and actors are called for collisions and updates
95 public int SimulationNowTime { get; private set; } 116 public int SimulationNowTime { get; private set; }
96 117
@@ -136,12 +157,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
136 public delegate void TaintCallback(); 157 public delegate void TaintCallback();
137 private struct TaintCallbackEntry 158 private struct TaintCallbackEntry
138 { 159 {
160 public String originator;
139 public String ident; 161 public String ident;
140 public TaintCallback callback; 162 public TaintCallback callback;
141 public TaintCallbackEntry(string i, TaintCallback c) 163 public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
164 {
165 originator = BSScene.DetailLogZero;
166 ident = pIdent;
167 callback = pCallBack;
168 }
169 public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
142 { 170 {
143 ident = i; 171 originator = pOrigin;
144 callback = c; 172 ident = pIdent;
173 callback = pCallBack;
145 } 174 }
146 } 175 }
147 private Object _taintLock = new Object(); // lock for using the next object 176 private Object _taintLock = new Object(); // lock for using the next object
@@ -188,6 +217,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
188 PhysObjects = new Dictionary<uint, BSPhysObject>(); 217 PhysObjects = new Dictionary<uint, BSPhysObject>();
189 Shapes = new BSShapeCollection(this); 218 Shapes = new BSShapeCollection(this);
190 219
220 m_simulatedTime = 0f;
221 LastTimeStep = 0.1f;
222
191 // Allocate pinned memory to pass parameters. 223 // Allocate pinned memory to pass parameters.
192 UnmanagedParams = new ConfigurationParameters[1]; 224 UnmanagedParams = new ConfigurationParameters[1];
193 225
@@ -202,8 +234,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
202 // can be left in and every call doesn't have to check for null. 234 // can be left in and every call doesn't have to check for null.
203 if (m_physicsLoggingEnabled) 235 if (m_physicsLoggingEnabled)
204 { 236 {
205 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 237 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
206 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. 238 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
207 } 239 }
208 else 240 else
209 { 241 {
@@ -227,10 +259,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
227 TerrainManager = new BSTerrainManager(this); 259 TerrainManager = new BSTerrainManager(this);
228 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 260 TerrainManager.CreateInitialGroundPlaneAndTerrain();
229 261
230 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); 262 // Put some informational messages into the log file.
263 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
231 264
232 InTaintTime = false; 265 InTaintTime = false;
233 m_initialized = true; 266 m_initialized = true;
267
268 // If the physics engine runs on its own thread, start same.
269 if (BSParam.UseSeparatePhysicsThread)
270 {
271 // The physics simulation should happen independently of the heartbeat loop
272 m_physicsThread = new Thread(BulletSPluginPhysicsThread);
273 m_physicsThread.Name = BulletEngineName;
274 m_physicsThread.Start();
275 }
234 } 276 }
235 277
236 // All default parameter values are set here. There should be no values set in the 278 // All default parameter values are set here. There should be no values set in the
@@ -268,6 +310,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
268 // Do any replacements in the parameters 310 // Do any replacements in the parameters
269 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 311 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
270 } 312 }
313 else
314 {
315 // Nothing in the configuration INI file so assume unmanaged and other defaults.
316 BulletEngineName = "BulletUnmanaged";
317 m_physicsLoggingEnabled = false;
318 VehicleLoggingEnabled = false;
319 }
271 320
272 // The material characteristics. 321 // The material characteristics.
273 BSMaterials.InitializeFromDefaults(Params); 322 BSMaterials.InitializeFromDefaults(Params);
@@ -311,11 +360,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
311 360
312 switch (selectionName) 361 switch (selectionName)
313 { 362 {
363 case "bullet":
314 case "bulletunmanaged": 364 case "bulletunmanaged":
315 ret = new BSAPIUnman(engineName, this); 365 ret = new BSAPIUnman(engineName, this);
316 break; 366 break;
317 case "bulletxna": 367 case "bulletxna":
318 ret = new BSAPIXNA(engineName, this); 368 ret = new BSAPIXNA(engineName, this);
369 // Disable some features that are not implemented in BulletXNA
370 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
371 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
372 BSParam.ShouldUseBulletHACD = false;
373 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
374 BSParam.ShouldUseSingleConvexHullForPrims = false;
375 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
376 BSParam.ShouldUseGImpactShapeForPrims = false;
377 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
378 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
319 break; 379 break;
320 } 380 }
321 381
@@ -325,7 +385,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
325 } 385 }
326 else 386 else
327 { 387 {
328 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); 388 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
329 } 389 }
330 390
331 return ret; 391 return ret;
@@ -478,25 +538,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
478 #endregion // Prim and Avatar addition and removal 538 #endregion // Prim and Avatar addition and removal
479 539
480 #region Simulation 540 #region Simulation
481 // Simulate one timestep 541
542 // Call from the simulator to send physics information to the simulator objects.
543 // This pushes all the collision and property update events into the objects in
544 // the simulator and, since it is on the heartbeat thread, there is an implicit
545 // locking of those data structures from other heartbeat events.
546 // If the physics engine is running on a separate thread, the update information
547 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
482 public override float Simulate(float timeStep) 548 public override float Simulate(float timeStep)
483 { 549 {
550 if (!BSParam.UseSeparatePhysicsThread)
551 {
552 DoPhysicsStep(timeStep);
553 }
554 return SendUpdatesToSimulator(timeStep);
555 }
556
557 // Call the physics engine to do one 'timeStep' and collect collisions and updates
558 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
559 private void DoPhysicsStep(float timeStep)
560 {
484 // prevent simulation until we've been initialized 561 // prevent simulation until we've been initialized
485 if (!m_initialized) return 5.0f; 562 if (!m_initialized) return;
486 563
487 LastTimeStep = timeStep; 564 LastTimeStep = timeStep;
488 565
489 int updatedEntityCount = 0; 566 int updatedEntityCount = 0;
490 int collidersCount = 0; 567 int collidersCount = 0;
491 568
492 int beforeTime = 0; 569 int beforeTime = Util.EnvironmentTickCount();
493 int simTime = 0; 570 int simTime = 0;
494 571
495 // update the prim states while we know the physics engine is not busy
496 int numTaints = _taintOperations.Count; 572 int numTaints = _taintOperations.Count;
497
498 InTaintTime = true; // Only used for debugging so locking is not necessary. 573 InTaintTime = true; // Only used for debugging so locking is not necessary.
499 574
575 // update the prim states while we know the physics engine is not busy
500 ProcessTaints(); 576 ProcessTaints();
501 577
502 // Some of the physical objects requre individual, pre-step calls 578 // Some of the physical objects requre individual, pre-step calls
@@ -519,18 +595,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
519 int numSubSteps = 0; 595 int numSubSteps = 0;
520 try 596 try
521 { 597 {
522 if (PhysicsLogging.Enabled)
523 beforeTime = Util.EnvironmentTickCount();
524
525 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); 598 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
526 599
527 if (PhysicsLogging.Enabled)
528 {
529 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
530 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
531 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
532 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
533 }
534 } 600 }
535 catch (Exception e) 601 catch (Exception e)
536 { 602 {
@@ -542,77 +608,63 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
542 collidersCount = 0; 608 collidersCount = 0;
543 } 609 }
544 610
611 // Make the physics engine dump useful statistics periodically
545 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) 612 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
546 PE.DumpPhysicsStatistics(World); 613 PE.DumpPhysicsStatistics(World);
547 614
548 // Get a value for 'now' so all the collision and update routines don't have to get their own. 615 // Get a value for 'now' so all the collision and update routines don't have to get their own.
549 SimulationNowTime = Util.EnvironmentTickCount(); 616 SimulationNowTime = Util.EnvironmentTickCount();
550 617
551 // If there were collisions, process them by sending the event to the prim. 618 // Send collision information to the colliding objects. The objects decide if the collision
552 // Collisions must be processed before updates. 619 // is 'real' (like linksets don't collide with themselves) and the individual objects
553 if (collidersCount > 0) 620 // know if the simulator has subscribed to collisions.
621 lock (CollisionLock)
554 { 622 {
555 for (int ii = 0; ii < collidersCount; ii++) 623 if (collidersCount > 0)
556 { 624 {
557 uint cA = m_collisionArray[ii].aID; 625 for (int ii = 0; ii < collidersCount; ii++)
558 uint cB = m_collisionArray[ii].bID;
559 Vector3 point = m_collisionArray[ii].point;
560 Vector3 normal = m_collisionArray[ii].normal;
561 float penetration = m_collisionArray[ii].penetration;
562 SendCollision(cA, cB, point, normal, penetration);
563 SendCollision(cB, cA, point, -normal, penetration);
564 }
565 }
566
567 // The above SendCollision's batch up the collisions on the objects.
568 // Now push the collisions into the simulator.
569 if (ObjectsWithCollisions.Count > 0)
570 {
571 foreach (BSPhysObject bsp in ObjectsWithCollisions)
572 if (!bsp.SendCollisions())
573 { 626 {
574 // If the object is done colliding, see that it's removed from the colliding list 627 uint cA = m_collisionArray[ii].aID;
575 ObjectsWithNoMoreCollisions.Add(bsp); 628 uint cB = m_collisionArray[ii].bID;
629 Vector3 point = m_collisionArray[ii].point;
630 Vector3 normal = m_collisionArray[ii].normal;
631 float penetration = m_collisionArray[ii].penetration;
632 SendCollision(cA, cB, point, normal, penetration);
633 SendCollision(cB, cA, point, -normal, penetration);
576 } 634 }
635 }
577 } 636 }
578 637
579 // This is a kludge to get avatar movement updates. 638 // If any of the objects had updated properties, tell the managed objects about the update
580 // The simulator expects collisions for avatars even if there are have been no collisions. 639 // and remember that there was a change so it will be passed to the simulator.
581 // The event updates avatar animations and stuff. 640 lock (UpdateLock)
582 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
583 foreach (BSPhysObject bsp in m_avatars)
584 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
585 bsp.SendCollisions();
586
587 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
588 // Not done above because it is inside an iteration of ObjectWithCollisions.
589 // This complex collision processing is required to create an empty collision
590 // event call after all real collisions have happened on an object. This enables
591 // the simulator to generate the 'collision end' event.
592 if (ObjectsWithNoMoreCollisions.Count > 0)
593 {
594 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
595 ObjectsWithCollisions.Remove(po);
596 ObjectsWithNoMoreCollisions.Clear();
597 }
598 // Done with collisions.
599
600 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
601 if (updatedEntityCount > 0)
602 { 641 {
603 for (int ii = 0; ii < updatedEntityCount; ii++) 642 if (updatedEntityCount > 0)
604 { 643 {
605 EntityProperties entprop = m_updateArray[ii]; 644 for (int ii = 0; ii < updatedEntityCount; ii++)
606 BSPhysObject pobj;
607 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
608 { 645 {
609 pobj.UpdateProperties(entprop); 646 EntityProperties entprop = m_updateArray[ii];
647 BSPhysObject pobj;
648 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
649 {
650 if (pobj.IsInitialized)
651 pobj.UpdateProperties(entprop);
652 }
610 } 653 }
611 } 654 }
612 } 655 }
613 656
657 // Some actors want to know when the simulation step is complete.
614 TriggerPostStepEvent(timeStep); 658 TriggerPostStepEvent(timeStep);
615 659
660 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
661 if (PhysicsLogging.Enabled)
662 {
663 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
664 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
665 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
666 }
667
616 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. 668 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
617 // Only enable this in a limited test world with few objects. 669 // Only enable this in a limited test world with few objects.
618 if (m_physicsPhysicalDumpEnabled) 670 if (m_physicsPhysicalDumpEnabled)
@@ -621,7 +673,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
621 // The physics engine returns the number of milliseconds it simulated this call. 673 // The physics engine returns the number of milliseconds it simulated this call.
622 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 674 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
623 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55). 675 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
624 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; 676 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
677 }
678
679 // Called by a BSPhysObject to note that it has changed properties and this information
680 // should be passed up to the simulator at the proper time.
681 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
682 // this is is under UpdateLock.
683 public void PostUpdate(BSPhysObject updatee)
684 {
685 ObjectsWithUpdates.Add(updatee);
686 }
687
688 // The simulator thinks it is physics time so return all the collisions and position
689 // updates that were collected in actual physics simulation.
690 private float SendUpdatesToSimulator(float timeStep)
691 {
692 if (!m_initialized) return 5.0f;
693
694 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
695 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
696 // Push the collisions into the simulator.
697 lock (CollisionLock)
698 {
699 if (ObjectsWithCollisions.Count > 0)
700 {
701 foreach (BSPhysObject bsp in ObjectsWithCollisions)
702 if (!bsp.SendCollisions())
703 {
704 // If the object is done colliding, see that it's removed from the colliding list
705 ObjectsWithNoMoreCollisions.Add(bsp);
706 }
707 }
708
709 // This is a kludge to get avatar movement updates.
710 // The simulator expects collisions for avatars even if there are have been no collisions.
711 // The event updates avatar animations and stuff.
712 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
713 foreach (BSPhysObject bsp in m_avatars)
714 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
715 bsp.SendCollisions();
716
717 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
718 // Not done above because it is inside an iteration of ObjectWithCollisions.
719 // This complex collision processing is required to create an empty collision
720 // event call after all real collisions have happened on an object. This allows
721 // the simulator to generate the 'collision end' event.
722 if (ObjectsWithNoMoreCollisions.Count > 0)
723 {
724 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
725 ObjectsWithCollisions.Remove(po);
726 ObjectsWithNoMoreCollisions.Clear();
727 }
728 }
729
730 // Call the simulator for each object that has physics property updates.
731 HashSet<BSPhysObject> updatedObjects = null;
732 lock (UpdateLock)
733 {
734 if (ObjectsWithUpdates.Count > 0)
735 {
736 updatedObjects = ObjectsWithUpdates;
737 ObjectsWithUpdates = new HashSet<BSPhysObject>();
738 }
739 }
740 if (updatedObjects != null)
741 {
742 foreach (BSPhysObject obj in updatedObjects)
743 {
744 obj.RequestPhysicsterseUpdate();
745 }
746 updatedObjects.Clear();
747 }
748
749 // Return the framerate simulated to give the above returned results.
750 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
751 float simTime = m_simulatedTime;
752 m_simulatedTime = 0f;
753 return simTime;
625 } 754 }
626 755
627 // Something has collided 756 // Something has collided
@@ -640,21 +769,49 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
640 return; 769 return;
641 } 770 }
642 771
643 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. 772 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
644 BSPhysObject collidee = null; 773 BSPhysObject collidee = null;
645 PhysObjects.TryGetValue(collidingWith, out collidee); 774 PhysObjects.TryGetValue(collidingWith, out collidee);
646 775
647 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); 776 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
648 777
649 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 778 if (collider.IsInitialized)
650 { 779 {
651 // If a collision was posted, remember to send it to the simulator 780 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
652 ObjectsWithCollisions.Add(collider); 781 {
782 // If a collision was 'good', remember to send it to the simulator
783 ObjectsWithCollisions.Add(collider);
784 }
653 } 785 }
654 786
655 return; 787 return;
656 } 788 }
657 789
790 public void BulletSPluginPhysicsThread()
791 {
792 while (m_initialized)
793 {
794 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
795 DoPhysicsStep(BSParam.PhysicsTimeStep);
796 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
797 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
798
799 if (simulationTimeVsRealtimeDifferenceMS > 0)
800 {
801 // The simulation of the time interval took less than realtime.
802 // Do a sleep for the rest of realtime.
803 Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
804 }
805 else
806 {
807 // The simulation took longer than realtime.
808 // Do some scaling of simulation time.
809 // TODO.
810 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
811 }
812 }
813 }
814
658 #endregion // Simulation 815 #endregion // Simulation
659 816
660 public override void GetResults() { } 817 public override void GetResults() { }
@@ -717,6 +874,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
717 874
718 public override bool IsThreaded { get { return false; } } 875 public override bool IsThreaded { get { return false; } }
719 876
877 #region Extensions
878 public override object Extension(string pFunct, params object[] pParams)
879 {
880 DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
881 return base.Extension(pFunct, pParams);
882 }
883 #endregion // Extensions
884
720 #region Taints 885 #region Taints
721 // The simulation execution order is: 886 // The simulation execution order is:
722 // Simulate() 887 // Simulate()
@@ -731,26 +896,37 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
731 // Calls to the PhysicsActors can't directly call into the physics engine 896 // Calls to the PhysicsActors can't directly call into the physics engine
732 // because it might be busy. We delay changes to a known time. 897 // because it might be busy. We delay changes to a known time.
733 // We rely on C#'s closure to save and restore the context for the delegate. 898 // We rely on C#'s closure to save and restore the context for the delegate.
734 public void TaintedObject(String ident, TaintCallback callback) 899 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
735 { 900 {
736 if (!m_initialized) return; 901 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
737 902 }
738 lock (_taintLock) 903 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
739 { 904 {
740 _taintOperations.Add(new TaintCallbackEntry(ident, callback)); 905 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
741 } 906 }
742 907 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
743 return; 908 {
909 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
910 }
911 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
912 {
913 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
744 } 914 }
745
746 // Sometimes a potentially tainted operation can be used in and out of taint time. 915 // Sometimes a potentially tainted operation can be used in and out of taint time.
747 // This routine executes the command immediately if in taint-time otherwise it is queued. 916 // This routine executes the command immediately if in taint-time otherwise it is queued.
748 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) 917 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
749 { 918 {
919 if (!m_initialized) return;
920
750 if (inTaintTime) 921 if (inTaintTime)
751 callback(); 922 pCallback();
752 else 923 else
753 TaintedObject(ident, callback); 924 {
925 lock (_taintLock)
926 {
927 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
928 }
929 }
754 } 930 }
755 931
756 private void TriggerPreStepEvent(float timeStep) 932 private void TriggerPreStepEvent(float timeStep)
@@ -780,7 +956,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
780 956
781 private void ProcessRegularTaints() 957 private void ProcessRegularTaints()
782 { 958 {
783 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 959 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
784 { 960 {
785 // swizzle a new list into the list location so we can process what's there 961 // swizzle a new list into the list location so we can process what's there
786 List<TaintCallbackEntry> oldList; 962 List<TaintCallbackEntry> oldList;
@@ -794,7 +970,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
794 { 970 {
795 try 971 try
796 { 972 {
797 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG 973 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
798 tcbe.callback(); 974 tcbe.callback();
799 } 975 }
800 catch (Exception e) 976 catch (Exception e)
@@ -811,10 +987,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
811 // will replace any previous operation by the same object. 987 // will replace any previous operation by the same object.
812 public void PostTaintObject(String ident, uint ID, TaintCallback callback) 988 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
813 { 989 {
814 string uniqueIdent = ident + "-" + ID.ToString(); 990 string IDAsString = ID.ToString();
991 string uniqueIdent = ident + "-" + IDAsString;
815 lock (_taintLock) 992 lock (_taintLock)
816 { 993 {
817 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); 994 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
818 } 995 }
819 996
820 return; 997 return;
@@ -823,7 +1000,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
823 // Taints that happen after the normal taint processing but before the simulation step. 1000 // Taints that happen after the normal taint processing but before the simulation step.
824 private void ProcessPostTaintTaints() 1001 private void ProcessPostTaintTaints()
825 { 1002 {
826 if (_postTaintOperations.Count > 0) 1003 if (m_initialized && _postTaintOperations.Count > 0)
827 { 1004 {
828 Dictionary<string, TaintCallbackEntry> oldList; 1005 Dictionary<string, TaintCallbackEntry> oldList;
829 lock (_taintLock) 1006 lock (_taintLock)
@@ -924,7 +1101,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
924 string xval = val; 1101 string xval = val;
925 List<uint> xlIDs = lIDs; 1102 List<uint> xlIDs = lIDs;
926 string xparm = parm; 1103 string xparm = parm;
927 TaintedObject("BSScene.UpdateParameterSet", delegate() { 1104 TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
928 BSParam.ParameterDefnBase thisParam; 1105 BSParam.ParameterDefnBase thisParam;
929 if (BSParam.TryGetParameter(xparm, out thisParam)) 1106 if (BSParam.TryGetParameter(xparm, out thisParam))
930 { 1107 {
@@ -963,8 +1140,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
963 public void DetailLog(string msg, params Object[] args) 1140 public void DetailLog(string msg, params Object[] args)
964 { 1141 {
965 PhysicsLogging.Write(msg, args); 1142 PhysicsLogging.Write(msg, args);
966 // Add the Flush() if debugging crashes. Gets all the messages written out.
967 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
968 } 1143 }
969 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 1144 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
970 public const string DetailLogZero = "0000000000"; 1145 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 220fbbc..32bbc8f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -38,38 +38,15 @@ public sealed class BSShapeCollection : IDisposable
38{ 38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 private BSScene PhysicsScene { get; set; } 41 private BSScene m_physicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public BulletShape shape;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public BulletShape shape;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 private bool DDetail = false; 45 private bool DDetail = false;
69 46
70 public BSShapeCollection(BSScene physScene) 47 public BSShapeCollection(BSScene physScene)
71 { 48 {
72 PhysicsScene = physScene; 49 m_physicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) 50 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the 51 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging 52 // DetailLog statements. When debugging slows down, this and the protected logging
@@ -86,22 +63,18 @@ public sealed class BSShapeCollection : IDisposable
86 // Mostly used for changing bodies out from under Linksets. 63 // Mostly used for changing bodies out from under Linksets.
87 // Useful for other cases where parameters need saving. 64 // Useful for other cases where parameters need saving.
88 // Passing 'null' says no callback. 65 // Passing 'null' says no callback.
89 public delegate void ShapeDestructionCallback(BulletShape shape); 66 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
90 public delegate void BodyDestructionCallback(BulletBody body);
91 67
92 // Called to update/change the body and shape for an object. 68 // Called to update/change the body and shape for an object.
93 // First checks the shape and updates that if necessary then makes 69 // The object has some shape and body on it. Here we decide if that is the correct shape
94 // sure the body is of the right type. 70 // for the current state of the object (static/dynamic/...).
71 // If bodyCallback is not null, it is called if either the body or the shape are changed
72 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
95 // Return 'true' if either the body or the shape changed. 73 // Return 'true' if either the body or the shape changed.
96 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before 74 // Called at taint-time.
97 // the current shape or body is destroyed. This allows the caller to remove any 75 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
99 // remove the physical constraints before the body is destroyed.
100 // Called at taint-time!!
101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
103 { 76 {
104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 77 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
105 78
106 bool ret = false; 79 bool ret = false;
107 80
@@ -111,12 +84,12 @@ public sealed class BSShapeCollection : IDisposable
111 // Do we have the correct geometry for this type of object? 84 // Do we have the correct geometry for this type of object?
112 // Updates prim.BSShape with information/pointers to shape. 85 // Updates prim.BSShape with information/pointers to shape.
113 // Returns 'true' of BSShape is changed to a new shape. 86 // Returns 'true' of BSShape is changed to a new shape.
114 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback); 87 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
115 // If we had to select a new shape geometry for the object, 88 // If we had to select a new shape geometry for the object,
116 // rebuild the body around it. 89 // rebuild the body around it.
117 // Updates prim.BSBody with information/pointers to requested body 90 // Updates prim.BSBody with information/pointers to requested body
118 // Returns 'true' if BSBody was changed. 91 // Returns 'true' if BSBody was changed.
119 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, bodyCallback); 92 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
120 ret = newGeom || newBody; 93 ret = newGeom || newBody;
121 } 94 }
122 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", 95 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
@@ -127,274 +100,20 @@ public sealed class BSShapeCollection : IDisposable
127 100
128 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
129 { 102 {
130 return GetBodyAndShape(forceRebuild, sim, prim, null, null); 103 return GetBodyAndShape(forceRebuild, sim, prim, null);
131 }
132
133 // Track another user of a body.
134 // We presume the caller has allocated the body.
135 // Bodies only have one user so the body is just put into the world if not already there.
136 private void ReferenceBody(BulletBody body)
137 {
138 lock (m_collectionActivityLock)
139 {
140 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
141 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
142 {
143 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
144 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
145 }
146 }
147 }
148
149 // Release the usage of a body.
150 // Called when releasing use of a BSBody. BSShape is handled separately.
151 // Called in taint time.
152 public void DereferenceBody(BulletBody body, BodyDestructionCallback bodyCallback )
153 {
154 if (!body.HasPhysicalBody)
155 return;
156
157 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
158
159 lock (m_collectionActivityLock)
160 {
161 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
162 // If the caller needs to know the old body is going away, pass the event up.
163 if (bodyCallback != null) bodyCallback(body);
164
165 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
166 {
167 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
168 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
169 }
170
171 // Zero any reference to the shape so it is not freed when the body is deleted.
172 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
173 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
174 }
175 }
176
177 // Track the datastructures and use count for a shape.
178 // When creating a hull, this is called first to reference the mesh
179 // and then again to reference the hull.
180 // Meshes and hulls for the same shape have the same hash key.
181 // NOTE that native shapes are not added to the mesh list or removed.
182 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
183 public bool ReferenceShape(BulletShape shape)
184 {
185 bool ret = false;
186 switch (shape.type)
187 {
188 case BSPhysicsShapeType.SHAPE_MESH:
189 MeshDesc meshDesc;
190 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
191 {
192 // There is an existing instance of this mesh.
193 meshDesc.referenceCount++;
194 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
195 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
196 }
197 else
198 {
199 // This is a new reference to a mesh
200 meshDesc.shape = shape.Clone();
201 meshDesc.shapeKey = shape.shapeKey;
202 // We keep a reference to the underlying IMesh data so a hull can be built
203 meshDesc.referenceCount = 1;
204 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
205 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
206 ret = true;
207 }
208 meshDesc.lastReferenced = System.DateTime.Now;
209 Meshes[shape.shapeKey] = meshDesc;
210 break;
211 case BSPhysicsShapeType.SHAPE_HULL:
212 HullDesc hullDesc;
213 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
214 {
215 // There is an existing instance of this hull.
216 hullDesc.referenceCount++;
217 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
218 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
219 }
220 else
221 {
222 // This is a new reference to a hull
223 hullDesc.shape = shape.Clone();
224 hullDesc.shapeKey = shape.shapeKey;
225 hullDesc.referenceCount = 1;
226 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
227 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
228 ret = true;
229
230 }
231 hullDesc.lastReferenced = System.DateTime.Now;
232 Hulls[shape.shapeKey] = hullDesc;
233 break;
234 case BSPhysicsShapeType.SHAPE_UNKNOWN:
235 break;
236 default:
237 // Native shapes are not tracked and they don't go into any list
238 break;
239 }
240 return ret;
241 } 104 }
242 105
243 // Release the usage of a shape. 106 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
244 public void DereferenceShape(BulletShape shape, ShapeDestructionCallback shapeCallback) 107 // before replacing it.
108 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
245 { 109 {
246 if (!shape.HasPhysicalShape) 110 if (prim.PhysShape.HasPhysicalShape)
247 return;
248
249 PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceShape");
250
251 if (shape.HasPhysicalShape)
252 {
253 if (shape.isNativeShape)
254 {
255 // Native shapes are not tracked and are released immediately
256 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1}",
257 BSScene.DetailLogZero, shape.AddrString);
258 if (shapeCallback != null) shapeCallback(shape);
259 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
260 }
261 else
262 {
263 switch (shape.type)
264 {
265 case BSPhysicsShapeType.SHAPE_HULL:
266 DereferenceHull(shape, shapeCallback);
267 break;
268 case BSPhysicsShapeType.SHAPE_MESH:
269 DereferenceMesh(shape, shapeCallback);
270 break;
271 case BSPhysicsShapeType.SHAPE_COMPOUND:
272 DereferenceCompound(shape, shapeCallback);
273 break;
274 case BSPhysicsShapeType.SHAPE_UNKNOWN:
275 break;
276 default:
277 break;
278 }
279 }
280 }
281 }
282
283 // Count down the reference count for a mesh shape
284 // Called at taint-time.
285 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
286 {
287 MeshDesc meshDesc;
288 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
289 { 111 {
290 meshDesc.referenceCount--; 112 if (shapeCallback != null)
291 // TODO: release the Bullet storage 113 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
292 if (shapeCallback != null) shapeCallback(shape); 114 prim.PhysShape.Dereference(m_physicsScene);
293 meshDesc.lastReferenced = System.DateTime.Now;
294 Meshes[shape.shapeKey] = meshDesc;
295 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
296 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
297
298 }
299 }
300
301 // Count down the reference count for a hull shape
302 // Called at taint-time.
303 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
304 {
305 HullDesc hullDesc;
306 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
307 {
308 hullDesc.referenceCount--;
309 // TODO: release the Bullet storage (aging old entries?)
310
311 // Tell upper layers that, if they have dependencies on this shape, this link is going away
312 if (shapeCallback != null) shapeCallback(shape);
313
314 hullDesc.lastReferenced = System.DateTime.Now;
315 Hulls[shape.shapeKey] = hullDesc;
316 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
317 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
318 }
319 }
320
321 // Remove a reference to a compound shape.
322 // Taking a compound shape apart is a little tricky because if you just delete the
323 // physical shape, it will free all the underlying children. We can't do that because
324 // they could be shared. So, this removes each of the children from the compound and
325 // dereferences them separately before destroying the compound collision object itself.
326 // Called at taint-time.
327 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
328 {
329 if (!PhysicsScene.PE.IsCompound(shape))
330 {
331 // Failed the sanity check!!
332 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
333 LogHeader, shape.type, shape.AddrString);
334 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
335 BSScene.DetailLogZero, shape.type, shape.AddrString);
336 return;
337 }
338
339 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
341
342 for (int ii = numChildren - 1; ii >= 0; ii--)
343 {
344 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
345 DereferenceAnonCollisionShape(childShape);
346 }
347 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
348 }
349
350 // Sometimes we have a pointer to a collision shape but don't know what type it is.
351 // Figure out type and call the correct dereference routine.
352 // Called at taint-time.
353 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
354 {
355 MeshDesc meshDesc;
356 HullDesc hullDesc;
357
358 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
359 {
360 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
361 shapeInfo.shapeKey = meshDesc.shapeKey;
362 }
363 else
364 {
365 if (TryGetHullByPtr(shapeInfo, out hullDesc))
366 {
367 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
368 shapeInfo.shapeKey = hullDesc.shapeKey;
369 }
370 else
371 {
372 if (PhysicsScene.PE.IsCompound(shapeInfo))
373 {
374 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
375 }
376 else
377 {
378 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
379 {
380 shapeInfo.isNativeShape = true;
381 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
382 }
383 }
384 }
385 }
386
387 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
388
389 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
390 {
391 DereferenceShape(shapeInfo, null);
392 }
393 else
394 {
395 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
396 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
397 } 115 }
116 prim.PhysShape = new BSShapeNull();
398 } 117 }
399 118
400 // Create the geometry information in Bullet for later use. 119 // Create the geometry information in Bullet for later use.
@@ -405,60 +124,41 @@ public sealed class BSShapeCollection : IDisposable
405 // Info in prim.BSShape is updated to the new shape. 124 // Info in prim.BSShape is updated to the new shape.
406 // Returns 'true' if the geometry was rebuilt. 125 // Returns 'true' if the geometry was rebuilt.
407 // Called at taint-time! 126 // Called at taint-time!
408 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 127 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
409 { 128 {
410 bool ret = false; 129 bool ret = false;
411 bool haveShape = false; 130 bool haveShape = false;
131 bool nativeShapePossible = true;
132 PrimitiveBaseShape pbs = prim.BaseShape;
412 133
413 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 134 // Kludge to create the capsule for the avatar.
135 // TDOD: Remove/redo this when BSShapeAvatar is working!!
136 BSCharacter theChar = prim as BSCharacter;
137 if (theChar != null)
414 { 138 {
415 // an avatar capsule is close to a native shape (it is not shared) 139 DereferenceExistingShape(prim, shapeCallback);
416 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); 140 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
417 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); 141 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
418 ret = true; 142 ret = true;
419 haveShape = true; 143 haveShape = true;
420 } 144 }
421 145
422 // Compound shapes are handled special as they are rebuilt from scratch.
423 // This isn't too great a hardship since most of the child shapes will have already been created.
424 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
425 {
426 ret = GetReferenceToCompoundShape(prim, shapeCallback);
427 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
428 haveShape = true;
429 }
430
431 if (!haveShape)
432 {
433 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
434 }
435
436 return ret;
437 }
438
439 // Create a mesh, hull or native shape.
440 // Return 'true' if the prim's shape was changed.
441 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
442 {
443 bool ret = false;
444 bool haveShape = false;
445 bool nativeShapePossible = true;
446 PrimitiveBaseShape pbs = prim.BaseShape;
447
448 // If the prim attributes are simple, this could be a simple Bullet native shape 146 // If the prim attributes are simple, this could be a simple Bullet native shape
147 // Native shapes work whether to object is static or physical.
449 if (!haveShape 148 if (!haveShape
450 && nativeShapePossible 149 && nativeShapePossible
451 && pbs != null 150 && pbs != null
452 && !pbs.SculptEntry 151 && PrimHasNoCuts(pbs)
453 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) || PrimHasNoCuts(pbs)) ) 152 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
153 )
454 { 154 {
455 // Get the scale of any existing shape so we can see if the new shape is same native type and same size. 155 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
456 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; 156 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
457 if (prim.PhysShape.HasPhysicalShape) 157 if (prim.PhysShape.HasPhysicalShape)
458 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); 158 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
459 159
460 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", 160 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
461 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); 161 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
462 162
463 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal 163 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
464 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 164 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
@@ -466,26 +166,30 @@ public sealed class BSShapeCollection : IDisposable
466 { 166 {
467 haveShape = true; 167 haveShape = true;
468 if (forceRebuild 168 if (forceRebuild
469 || prim.Scale != scaleOfExistingShape 169 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
470 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 170 )
471 )
472 { 171 {
473 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 172 DereferenceExistingShape(prim, shapeCallback);
474 FixedShapeKey.KEY_SPHERE, shapeCallback); 173 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
174 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
175 ret = true;
475 } 176 }
476 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", 177 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
477 prim.LocalID, forceRebuild, ret, prim.PhysShape); 178 prim.LocalID, forceRebuild, ret, prim.PhysShape);
478 } 179 }
180 // If we didn't make a sphere, maybe a box will work.
479 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 181 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
480 { 182 {
481 haveShape = true; 183 haveShape = true;
482 if (forceRebuild 184 if (forceRebuild
483 || prim.Scale != scaleOfExistingShape 185 || prim.Scale != scaleOfExistingShape
484 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 186 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
485 ) 187 )
486 { 188 {
487 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 189 DereferenceExistingShape(prim, shapeCallback);
488 FixedShapeKey.KEY_BOX, shapeCallback); 190 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
191 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
192 ret = true;
489 } 193 }
490 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", 194 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
491 prim.LocalID, forceRebuild, ret, prim.PhysShape); 195 prim.LocalID, forceRebuild, ret, prim.PhysShape);
@@ -502,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable
502 } 206 }
503 207
504 // return 'true' if this shape description does not include any cutting or twisting. 208 // return 'true' if this shape description does not include any cutting or twisting.
505 private bool PrimHasNoCuts(PrimitiveBaseShape pbs) 209 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
506 { 210 {
507 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 211 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
508 && pbs.ProfileHollow == 0 212 && pbs.ProfileHollow == 0
@@ -514,7 +218,7 @@ public sealed class BSShapeCollection : IDisposable
514 } 218 }
515 219
516 // return 'true' if the prim's shape was changed. 220 // return 'true' if the prim's shape was changed.
517 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 221 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
518 { 222 {
519 223
520 bool ret = false; 224 bool ret = false;
@@ -522,503 +226,121 @@ public sealed class BSShapeCollection : IDisposable
522 // made. Native shapes work in either case. 226 // made. Native shapes work in either case.
523 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) 227 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
524 { 228 {
525 // Update prim.BSShape to reference a hull of this shape. 229 // Use a simple, single mesh convex hull shape if the object is simple enough
526 ret = GetReferenceToHull(prim, shapeCallback); 230 BSShape potentialHull = null;
527 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
528 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
529 }
530 else
531 {
532 ret = GetReferenceToMesh(prim, shapeCallback);
533 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
534 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
535 }
536 return ret;
537 }
538
539 // Creates a native shape and assignes it to prim.BSShape.
540 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
541 private bool GetReferenceToNativeShape(BSPhysObject prim,
542 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
543 ShapeDestructionCallback shapeCallback)
544 {
545 // release any previous shape
546 DereferenceShape(prim.PhysShape, shapeCallback);
547
548 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
549
550 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
551 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
552 prim.LocalID, newShape, prim.Scale);
553
554 // native shapes are scaled by Bullet
555 prim.PhysShape = newShape;
556 return true;
557 }
558
559 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
560 FixedShapeKey shapeKey)
561 {
562 BulletShape newShape;
563 // Need to make sure the passed shape information is for the native type.
564 ShapeData nativeShapeData = new ShapeData();
565 nativeShapeData.Type = shapeType;
566 nativeShapeData.ID = prim.LocalID;
567 nativeShapeData.Scale = prim.Scale;
568 nativeShapeData.Size = prim.Scale; // unneeded, I think.
569 nativeShapeData.MeshKey = (ulong)shapeKey;
570 nativeShapeData.HullKey = (ulong)shapeKey;
571
572 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
573 {
574 231
575 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); 232 PrimitiveBaseShape pbs = prim.BaseShape;
576 if (DDetail) DetailLog("{0},BSShapeCollection.BuildPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 233 // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
577 } 234 if (BSParam.ShouldUseSingleConvexHullForPrims
578 else 235 && pbs != null
579 { 236 && !pbs.SculptEntry
580 // Native shapes are scaled in Bullet so set the scaling to the size 237 && PrimHasNoCuts(pbs)
581 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); 238 )
582 239 {
583 } 240 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
584 if (!newShape.HasPhysicalShape) 241 }
585 { 242 // Use the GImpact shape if it is a prim that has some concaveness
586 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 243 if (potentialHull == null
587 LogHeader, prim.LocalID, shapeType); 244 && BSParam.ShouldUseGImpactShapeForPrims
588 } 245 && pbs != null
589 newShape.shapeKey = (System.UInt64)shapeKey; 246 && !pbs.SculptEntry
590 newShape.isNativeShape = true; 247 )
591 248 {
592 return newShape; 249 potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
593 } 250 }
594 251 // If not any of the simple cases, just make a hull
595 // Builds a mesh shape in the physical world and updates prim.BSShape. 252 if (potentialHull == null)
596 // Dereferences previous shape in BSShape and adds a reference for this new shape. 253 {
597 // Returns 'true' of a mesh was actually built. Otherwise . 254 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
598 // Called at taint-time! 255 }
599 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
600 {
601 BulletShape newShape = new BulletShape();
602
603 float lod;
604 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
605
606 // if this new shape is the same as last time, don't recreate the mesh
607 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
608 return false;
609
610 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2},size={3},lod={4}",
611 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"), prim.Size, lod);
612
613 // Since we're recreating new, get rid of the reference to the previous shape
614 DereferenceShape(prim.PhysShape, shapeCallback);
615
616 newShape = CreatePhysicalMesh(prim, newMeshKey, prim.BaseShape, prim.Size, lod);
617 // Take evasive action if the mesh was not constructed.
618 newShape = VerifyMeshCreated(newShape, prim);
619
620 ReferenceShape(newShape);
621
622 prim.PhysShape = newShape;
623
624 return true; // 'true' means a new shape has been added to this prim
625 }
626
627 private BulletShape CreatePhysicalMesh(BSPhysObject prim, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
628 {
629 BulletShape newShape = new BulletShape();
630 256
631 MeshDesc meshDesc; 257 // If the current shape is not what is on the prim at the moment, time to change.
632 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 258 if (!prim.PhysShape.HasPhysicalShape
633 { 259 || potentialHull.ShapeType != prim.PhysShape.ShapeType
634 // If the mesh has already been built just use it. 260 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
635 newShape = meshDesc.shape.Clone(); 261 {
262 DereferenceExistingShape(prim, shapeCallback);
263 prim.PhysShape = potentialHull;
264 ret = true;
265 }
266 else
267 {
268 // The current shape on the prim is the correct one. We don't need the potential reference.
269 potentialHull.Dereference(m_physicsScene);
270 }
271 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
636 } 272 }
637 else 273 else
638 { 274 {
639 IMesh meshData = PhysicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, 275 // Non-physical objects should be just meshes.
640 true, 276 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
641 false, // say it is not physical so a bounding box is not built 277 // If the current shape is not what is on the prim at the moment, time to change.
642 false, // do not cache the mesh and do not use previously built versions 278 if (!prim.PhysShape.HasPhysicalShape
643 false // It's NOT for ODE 279 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
644 ); 280 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
645
646 if (meshData != null)
647 { 281 {
648 282 DereferenceExistingShape(prim, shapeCallback);
649 int[] indices = meshData.getIndexListAsInt(); 283 prim.PhysShape = potentialMesh;
650 int realIndicesIndex = indices.Length; 284 ret = true;
651 float[] verticesAsFloats = meshData.getVertexListAsFloat();
652
653 if (BSParam.ShouldRemoveZeroWidthTriangles)
654 {
655 // Remove degenerate triangles. These are triangles with two of the vertices
656 // are the same. This is complicated by the problem that vertices are not
657 // made unique in sculpties so we have to compare the values in the vertex.
658 realIndicesIndex = 0;
659 for (int tri = 0; tri < indices.Length; tri += 3)
660 {
661 // Compute displacements into vertex array for each vertex of the triangle
662 int v1 = indices[tri + 0] * 3;
663 int v2 = indices[tri + 1] * 3;
664 int v3 = indices[tri + 2] * 3;
665 // Check to see if any two of the vertices are the same
666 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
667 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
668 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
669 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
670 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
671 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
672 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
673 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
674 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
675 )
676 {
677 // None of the vertices of the triangles are the same. This is a good triangle;
678 indices[realIndicesIndex + 0] = indices[tri + 0];
679 indices[realIndicesIndex + 1] = indices[tri + 1];
680 indices[realIndicesIndex + 2] = indices[tri + 2];
681 realIndicesIndex += 3;
682 }
683 }
684 }
685 DetailLog("{0},BSShapeCollection.CreatePhysicalMesh,origTri={1},realTri={2},numVerts={3}",
686 BSScene.DetailLogZero, indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
687
688 if (realIndicesIndex != 0)
689 {
690 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
691 realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
692 }
693 else
694 {
695 PhysicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}",
696 LogHeader, prim.PhysObjectName, prim.RawPosition, PhysicsScene.Name);
697 }
698 } 285 }
286 else
287 {
288 // We don't need this reference to the mesh that is already being using.
289 potentialMesh.Dereference(m_physicsScene);
290 }
291 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
699 } 292 }
700 newShape.shapeKey = newMeshKey; 293 return ret;
701
702 return newShape;
703 }
704
705 // See that hull shape exists in the physical world and update prim.BSShape.
706 // We could be creating the hull because scale changed or whatever.
707 // Return 'true' if a new hull was built. Otherwise, returning a shared hull instance.
708 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
709 {
710 BulletShape newShape;
711
712 float lod;
713 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
714
715 // if the hull hasn't changed, don't rebuild it
716 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
717 return false;
718
719 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
720 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
721
722 // Remove usage of the previous shape.
723 DereferenceShape(prim.PhysShape, shapeCallback);
724
725 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
726 // It might not have been created if we're waiting for an asset.
727 newShape = VerifyMeshCreated(newShape, prim);
728
729 ReferenceShape(newShape);
730
731 prim.PhysShape = newShape;
732 return true; // 'true' means a new shape has been added to this prim
733 } 294 }
734 295
735 List<ConvexResult> m_hulls; 296 // Track another user of a body.
736 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 297 // We presume the caller has allocated the body.
298 // Bodies only have one user so the body is just put into the world if not already there.
299 private void ReferenceBody(BulletBody body)
737 { 300 {
738 301 lock (m_collectionActivityLock)
739 BulletShape newShape = new BulletShape();
740 IntPtr hullPtr = IntPtr.Zero;
741
742 HullDesc hullDesc;
743 if (Hulls.TryGetValue(newHullKey, out hullDesc))
744 {
745 // If the hull shape already has been created, just use the one shared instance.
746 newShape = hullDesc.shape.Clone();
747 }
748 else
749 { 302 {
750 // Build a new hull in the physical world. 303 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
751 // Pass true for physicalness as this prevents the creation of bounding box which is not needed 304 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
752 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
753 if (meshData != null)
754 { 305 {
755 306 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
756 int[] indices = meshData.getIndexListAsInt(); 307 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
757 List<OMV.Vector3> vertices = meshData.getVertexList();
758
759 //format conversion from IMesh format to DecompDesc format
760 List<int> convIndices = new List<int>();
761 List<float3> convVertices = new List<float3>();
762 for (int ii = 0; ii < indices.GetLength(0); ii++)
763 {
764 convIndices.Add(indices[ii]);
765 }
766 foreach (OMV.Vector3 vv in vertices)
767 {
768 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
769 }
770
771 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
772 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
773 {
774 // Simple primitive shapes we know are convex so they are better implemented with
775 // fewer hulls.
776 // Check for simple shape (prim without cuts) and reduce split parameter if so.
777 if (PrimHasNoCuts(pbs))
778 {
779 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
780 }
781 }
782
783 // setup and do convex hull conversion
784 m_hulls = new List<ConvexResult>();
785 DecompDesc dcomp = new DecompDesc();
786 dcomp.mIndices = convIndices;
787 dcomp.mVertices = convVertices;
788 dcomp.mDepth = maxDepthSplit;
789 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
790 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
791 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
792 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
793 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
794 // create the hull into the _hulls variable
795 convexBuilder.process(dcomp);
796
797 DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
798 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
799
800 // Convert the vertices and indices for passing to unmanaged.
801 // The hull information is passed as a large floating point array.
802 // The format is:
803 // convHulls[0] = number of hulls
804 // convHulls[1] = number of vertices in first hull
805 // convHulls[2] = hull centroid X coordinate
806 // convHulls[3] = hull centroid Y coordinate
807 // convHulls[4] = hull centroid Z coordinate
808 // convHulls[5] = first hull vertex X
809 // convHulls[6] = first hull vertex Y
810 // convHulls[7] = first hull vertex Z
811 // convHulls[8] = second hull vertex X
812 // ...
813 // convHulls[n] = number of vertices in second hull
814 // convHulls[n+1] = second hull centroid X coordinate
815 // ...
816 //
817 // TODO: is is very inefficient. Someday change the convex hull generator to return
818 // data structures that do not need to be converted in order to pass to Bullet.
819 // And maybe put the values directly into pinned memory rather than marshaling.
820 int hullCount = m_hulls.Count;
821 int totalVertices = 1; // include one for the count of the hulls
822 foreach (ConvexResult cr in m_hulls)
823 {
824 totalVertices += 4; // add four for the vertex count and centroid
825 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
826 }
827 float[] convHulls = new float[totalVertices];
828
829 convHulls[0] = (float)hullCount;
830 int jj = 1;
831 foreach (ConvexResult cr in m_hulls)
832 {
833 // copy vertices for index access
834 float3[] verts = new float3[cr.HullVertices.Count];
835 int kk = 0;
836 foreach (float3 ff in cr.HullVertices)
837 {
838 verts[kk++] = ff;
839 }
840
841 // add to the array one hull's worth of data
842 convHulls[jj++] = cr.HullIndices.Count;
843 convHulls[jj++] = 0f; // centroid x,y,z
844 convHulls[jj++] = 0f;
845 convHulls[jj++] = 0f;
846 foreach (int ind in cr.HullIndices)
847 {
848 convHulls[jj++] = verts[ind].x;
849 convHulls[jj++] = verts[ind].y;
850 convHulls[jj++] = verts[ind].z;
851 }
852 }
853 // create the hull data structure in Bullet
854 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
855 } 308 }
856 } 309 }
857
858 newShape.shapeKey = newHullKey;
859
860 return newShape;
861 }
862
863 // Callback from convex hull creater with a newly created hull.
864 // Just add it to our collection of hulls for this shape.
865 private void HullReturn(ConvexResult result)
866 {
867 m_hulls.Add(result);
868 return;
869 } 310 }
870 311
871 // Compound shapes are always built from scratch. 312 // Release the usage of a body.
872 // This shouldn't be to bad since most of the parts will be meshes that had been built previously. 313 // Called when releasing use of a BSBody. BSShape is handled separately.
873 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 314 // Called in taint time.
874 { 315 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
875 // Remove reference to the old shape
876 // Don't need to do this as the shape is freed when the new root shape is created below.
877 // DereferenceShape(prim.PhysShape, true, shapeCallback);
878
879 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
880
881 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
882 CreateGeomMeshOrHull(prim, shapeCallback);
883 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
884 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
885 prim.LocalID, cShape, prim.PhysShape);
886
887 prim.PhysShape = cShape;
888
889 return true;
890 }
891
892 // Create a hash of all the shape parameters to be used as a key
893 // for this particular shape.
894 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
895 {
896 // level of detail based on size and type of the object
897 float lod = BSParam.MeshLOD;
898
899 // prims with curvy internal cuts need higher lod
900 if (pbs.HollowShape == HollowShape.Circle)
901 lod = BSParam.MeshCircularLOD;
902
903 if (pbs.SculptEntry)
904 lod = BSParam.SculptLOD;
905
906 // Mega prims usually get more detail because one can interact with shape approximations at this size.
907 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
908 if (maxAxis > BSParam.MeshMegaPrimThreshold)
909 lod = BSParam.MeshMegaPrimLOD;
910
911 retLod = lod;
912 return pbs.GetMeshKey(size, lod);
913 }
914 // For those who don't want the LOD
915 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
916 { 316 {
917 float lod; 317 if (!body.HasPhysicalBody)
918 return ComputeShapeKey(size, pbs, out lod); 318 return;
919 }
920 319
921 // The creation of a mesh or hull can fail if an underlying asset is not available. 320 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
922 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
923 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
924 // The first case causes the asset to be fetched. The second case requires
925 // us to not loop forever.
926 // Called after creating a physical mesh or hull. If the physical shape was created,
927 // just return.
928 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
929 {
930 // If the shape was successfully created, nothing more to do
931 if (newShape.HasPhysicalShape)
932 return newShape;
933 321
934 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been 322 lock (m_collectionActivityLock)
935 // fetched but we end up here again, the meshing of the asset must have failed.
936 // Prevent trying to keep fetching the mesh by declaring failure.
937 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
938 {
939 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
940 PhysicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
941 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
942 }
943 else
944 { 323 {
945 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 324 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
946 if (prim.BaseShape.SculptEntry 325 // If the caller needs to know the old body is going away, pass the event up.
947 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed 326 if (bodyCallback != null)
948 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting 327 bodyCallback(body, null);
949 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
950 )
951 {
952 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
953 // Multiple requestors will know we're waiting for this asset
954 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
955
956 BSPhysObject xprim = prim;
957 Util.FireAndForget(delegate
958 {
959 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
960 if (assetProvider != null)
961 {
962 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
963 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
964 {
965 bool assetFound = false;
966 string mismatchIDs = String.Empty; // DEBUG DEBUG
967 if (asset != null && yprim.BaseShape.SculptEntry)
968 {
969 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
970 {
971 yprim.BaseShape.SculptData = asset.Data;
972 // This will cause the prim to see that the filler shape is not the right
973 // one and try again to build the object.
974 // No race condition with the normal shape setting since the rebuild is at taint time.
975 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
976 assetFound = true;
977 }
978 else
979 {
980 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
981 }
982 }
983 if (assetFound)
984 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
985 else
986 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
987 DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
988 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
989 328
990 }); 329 // Removing an object not in the world is a NOOP
991 } 330 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
992 else
993 {
994 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
995 PhysicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
996 LogHeader, PhysicsScene.Name);
997 }
998 });
999 }
1000 else
1001 {
1002 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
1003 {
1004 PhysicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
1005 LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
1006 }
1007 }
1008 }
1009 331
1010 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. 332 // Zero any reference to the shape so it is not freed when the body is deleted.
1011 BulletShape fillinShape = BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); 333 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
1012 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,boxTempShape", prim.LocalID);
1013 334
1014 return fillinShape; 335 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
336 }
1015 } 337 }
1016 338
1017 // Create a body object in Bullet. 339 // Create a body object in Bullet.
1018 // Updates prim.BSBody with the information about the new body if one is created. 340 // Updates prim.BSBody with the information about the new body if one is created.
1019 // Returns 'true' if an object was actually created. 341 // Returns 'true' if an object was actually created.
1020 // Called at taint-time. 342 // Called at taint-time.
1021 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BodyDestructionCallback bodyCallback) 343 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
1022 { 344 {
1023 bool ret = false; 345 bool ret = false;
1024 346
@@ -1029,7 +351,7 @@ public sealed class BSShapeCollection : IDisposable
1029 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 351 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
1030 if (!mustRebuild) 352 if (!mustRebuild)
1031 { 353 {
1032 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); 354 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
1033 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 355 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
1034 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 356 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
1035 { 357 {
@@ -1047,12 +369,12 @@ public sealed class BSShapeCollection : IDisposable
1047 BulletBody aBody; 369 BulletBody aBody;
1048 if (prim.IsSolid) 370 if (prim.IsSolid)
1049 { 371 {
1050 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 372 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1051 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); 373 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
1052 } 374 }
1053 else 375 else
1054 { 376 {
1055 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape, prim.LocalID, prim.RawPosition, prim.RawOrientation); 377 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1056 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); 378 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
1057 } 379 }
1058 380
@@ -1066,46 +388,10 @@ public sealed class BSShapeCollection : IDisposable
1066 return ret; 388 return ret;
1067 } 389 }
1068 390
1069 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
1070 {
1071 bool ret = false;
1072 MeshDesc foundDesc = new MeshDesc();
1073 foreach (MeshDesc md in Meshes.Values)
1074 {
1075 if (md.shape.ReferenceSame(shape))
1076 {
1077 foundDesc = md;
1078 ret = true;
1079 break;
1080 }
1081
1082 }
1083 outDesc = foundDesc;
1084 return ret;
1085 }
1086
1087 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
1088 {
1089 bool ret = false;
1090 HullDesc foundDesc = new HullDesc();
1091 foreach (HullDesc hd in Hulls.Values)
1092 {
1093 if (hd.shape.ReferenceSame(shape))
1094 {
1095 foundDesc = hd;
1096 ret = true;
1097 break;
1098 }
1099
1100 }
1101 outDesc = foundDesc;
1102 return ret;
1103 }
1104
1105 private void DetailLog(string msg, params Object[] args) 391 private void DetailLog(string msg, params Object[] args)
1106 { 392 {
1107 if (PhysicsScene.PhysicsLogging.Enabled) 393 if (m_physicsScene.PhysicsLogging.Enabled)
1108 PhysicsScene.DetailLog(msg, args); 394 m_physicsScene.DetailLog(msg, args);
1109 } 395 }
1110} 396}
1111} 397}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index ee18379..fe5ff6c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -29,115 +29,312 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.Meshing;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
32using OMV = OpenMetaverse; 37using OMV = OpenMetaverse;
33 38
34namespace OpenSim.Region.Physics.BulletSPlugin 39namespace OpenSim.Region.Physics.BulletSPlugin
35{ 40{
36public abstract class BSShape 41public abstract class BSShape
37{ 42{
43 private static string LogHeader = "[BULLETSIM SHAPE]";
44
38 public int referenceCount { get; set; } 45 public int referenceCount { get; set; }
39 public DateTime lastReferenced { get; set; } 46 public DateTime lastReferenced { get; set; }
47 public BulletShape physShapeInfo { get; set; }
40 48
41 public BSShape() 49 public BSShape()
42 { 50 {
43 referenceCount = 0; 51 referenceCount = 1;
44 lastReferenced = DateTime.Now; 52 lastReferenced = DateTime.Now;
53 physShapeInfo = new BulletShape();
45 } 54 }
46 55 public BSShape(BulletShape pShape)
47 // Get a reference to a physical shape. Create if it doesn't exist
48 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
49 { 56 {
50 BSShape ret = null; 57 referenceCount = 1;
51 58 lastReferenced = DateTime.Now;
52 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 59 physShapeInfo = pShape;
53 { 60 }
54 // an avatar capsule is close to a native shape (it is not shared)
55 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
56 FixedShapeKey.KEY_CAPSULE);
57 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
58 }
59
60 // Compound shapes are handled special as they are rebuilt from scratch.
61 // This isn't too great a hardship since most of the child shapes will have already been created.
62 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
63 {
64 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
65 ret = BSShapeCompound.GetReference(prim);
66 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
67 }
68
69 // Avatars have their own unique shape
70 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
71 {
72 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
73 ret = BSShapeAvatar.GetReference(prim);
74 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
75 }
76 61
77 if (ret == null) 62 // Get another reference to this shape.
78 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); 63 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
79 64
80 return ret; 65 // Called when this shape is being used again.
81 } 66 // Used internally. External callers should call instance.GetReference() to properly copy/reference
82 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 67 // the shape.
68 protected virtual void IncrementReference()
83 { 69 {
84 return null; 70 referenceCount++;
71 lastReferenced = DateTime.Now;
85 } 72 }
86 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) 73
74 // Called when this shape is done being used.
75 protected virtual void DecrementReference()
87 { 76 {
88 return null; 77 referenceCount--;
78 lastReferenced = DateTime.Now;
89 } 79 }
90 80
91 // Release the use of a physical shape. 81 // Release the use of a physical shape.
92 public abstract void Dereference(BSScene physicsScene); 82 public abstract void Dereference(BSScene physicsScene);
93 83
94 // All shapes have a static call to get a reference to the physical shape 84 // Return 'true' if there is an allocated physics physical shape under this class instance.
95 // protected abstract static BSShape GetReference(); 85 public virtual bool HasPhysicalShape
86 {
87 get
88 {
89 if (physShapeInfo != null)
90 return physShapeInfo.HasPhysicalShape;
91 return false;
92 }
93 }
94 public virtual BSPhysicsShapeType ShapeType
95 {
96 get
97 {
98 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
99 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
100 ret = physShapeInfo.shapeType;
101 return ret;
102 }
103 }
96 104
97 // Returns a string for debugging that uniquily identifies the memory used by this instance 105 // Returns a string for debugging that uniquily identifies the memory used by this instance
98 public virtual string AddrString 106 public virtual string AddrString
99 { 107 {
100 get { return "unknown"; } 108 get
109 {
110 if (physShapeInfo != null)
111 return physShapeInfo.AddrString;
112 return "unknown";
113 }
101 } 114 }
102 115
103 public override string ToString() 116 public override string ToString()
104 { 117 {
105 StringBuilder buff = new StringBuilder(); 118 StringBuilder buff = new StringBuilder();
106 buff.Append("<p="); 119 if (physShapeInfo == null)
107 buff.Append(AddrString); 120 {
121 buff.Append("<noPhys");
122 }
123 else
124 {
125 buff.Append("<phy=");
126 buff.Append(physShapeInfo.ToString());
127 }
108 buff.Append(",c="); 128 buff.Append(",c=");
109 buff.Append(referenceCount.ToString()); 129 buff.Append(referenceCount.ToString());
110 buff.Append(">"); 130 buff.Append(">");
111 return buff.ToString(); 131 return buff.ToString();
112 } 132 }
133
134 #region Common shape routines
135 // Create a hash of all the shape parameters to be used as a key for this particular shape.
136 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
137 {
138 // level of detail based on size and type of the object
139 float lod = BSParam.MeshLOD;
140 if (pbs.SculptEntry)
141 lod = BSParam.SculptLOD;
142
143 // Mega prims usually get more detail because one can interact with shape approximations at this size.
144 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
145 if (maxAxis > BSParam.MeshMegaPrimThreshold)
146 lod = BSParam.MeshMegaPrimLOD;
147
148 retLod = lod;
149 return pbs.GetMeshKey(size, lod);
150 }
151
152 // The creation of a mesh or hull can fail if an underlying asset is not available.
153 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
154 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
155 // The first case causes the asset to be fetched. The second case requires
156 // us to not loop forever.
157 // Called after creating a physical mesh or hull. If the physical shape was created,
158 // just return.
159 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
160 {
161 // If the shape was successfully created, nothing more to do
162 if (newShape.HasPhysicalShape)
163 return newShape;
164
165 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
166 // fetched but we end up here again, the meshing of the asset must have failed.
167 // Prevent trying to keep fetching the mesh by declaring failure.
168 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
169 {
170 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
171 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
172 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
173 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
174 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
175 }
176 else
177 {
178 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
179 if (prim.BaseShape.SculptEntry
180 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedAssetFetch
181 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.FailedMeshing
182 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
183 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
184 )
185 {
186 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
187 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
188 // Multiple requestors will know we're waiting for this asset
189 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
190
191 BSPhysObject xprim = prim;
192 Util.FireAndForget(delegate
193 {
194 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
195 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
196 if (assetProvider != null)
197 {
198 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
199 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
200 {
201 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
202 bool assetFound = false;
203 string mismatchIDs = String.Empty; // DEBUG DEBUG
204 if (asset != null && yprim.BaseShape.SculptEntry)
205 {
206 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
207 {
208 yprim.BaseShape.SculptData = asset.Data;
209 // This will cause the prim to see that the filler shape is not the right
210 // one and try again to build the object.
211 // No race condition with the normal shape setting since the rebuild is at taint time.
212 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
213 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
214 assetFound = true;
215 }
216 else
217 {
218 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
219 }
220 }
221 if (!assetFound)
222 {
223 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
224 }
225 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
226 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
227 });
228 }
229 else
230 {
231 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
232 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
233 LogHeader, physicsScene.Name);
234 }
235 });
236 }
237 else
238 {
239 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
240 {
241 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
242 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
243 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
244 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
245 }
246 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
247 {
248 physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
249 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
250 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
251 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
252 }
253 }
254 }
255
256 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
257 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
258 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
259
260 return fillShape.physShapeInfo;
261 }
262
263 public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
264 {
265 StringBuilder buff = new StringBuilder(prim.PhysObjectName);
266 buff.Append("/pos=");
267 buff.Append(prim.RawPosition.ToString());
268 if (pScene != null)
269 {
270 buff.Append("/rgn=");
271 buff.Append(pScene.Name);
272 }
273 return buff.ToString();
274 }
275
276 #endregion // Common shape routines
113} 277}
114 278
279// ============================================================================================================
115public class BSShapeNull : BSShape 280public class BSShapeNull : BSShape
116{ 281{
117 public BSShapeNull() : base() 282 public BSShapeNull() : base()
118 { 283 {
119 } 284 }
120 public static BSShape GetReference() { return new BSShapeNull(); } 285 public static BSShape GetReference() { return new BSShapeNull(); }
286 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
121 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } 287 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
122} 288}
123 289
290// ============================================================================================================
124public class BSShapeNative : BSShape 291public class BSShapeNative : BSShape
125{ 292{
126 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; 293 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
127 public BSShapeNative() : base() 294 public BSShapeNative(BulletShape pShape) : base(pShape)
128 { 295 {
129 } 296 }
130 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, 297
131 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 298 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
299 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
132 { 300 {
133 // Native shapes are not shared and are always built anew. 301 // Native shapes are not shared and are always built anew.
134 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 302 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
135 return null;
136 } 303 }
137 304
138 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 305 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
139 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
140 { 306 {
307 // Native shapes are not shared so we return a new shape.
308 BSShape ret = null;
309 lock (physShapeInfo)
310 {
311 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
312 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
313 }
314 return ret;
315 }
316
317 // Make this reference to the physical shape go away since native shapes are not shared.
318 public override void Dereference(BSScene physicsScene)
319 {
320 // Native shapes are not tracked and are released immediately
321 lock (physShapeInfo)
322 {
323 if (physShapeInfo.HasPhysicalShape)
324 {
325 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
326 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
327 }
328 physShapeInfo.Clear();
329 // Garbage collection will free up this instance.
330 }
331 }
332
333 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
334 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
335 {
336 BulletShape newShape;
337
141 ShapeData nativeShapeData = new ShapeData(); 338 ShapeData nativeShapeData = new ShapeData();
142 nativeShapeData.Type = shapeType; 339 nativeShapeData.Type = shapeType;
143 nativeShapeData.ID = prim.LocalID; 340 nativeShapeData.ID = prim.LocalID;
@@ -146,84 +343,880 @@ public class BSShapeNative : BSShape
146 nativeShapeData.MeshKey = (ulong)shapeKey; 343 nativeShapeData.MeshKey = (ulong)shapeKey;
147 nativeShapeData.HullKey = (ulong)shapeKey; 344 nativeShapeData.HullKey = (ulong)shapeKey;
148 345
149
150 /*
151 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 346 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
152 { 347 {
153 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); 348 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
154 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 349 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
155 } 350 }
156 else 351 else
157 { 352 {
158 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); 353 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
159 } 354 }
160 if (ptr == IntPtr.Zero) 355 if (!newShape.HasPhysicalShape)
161 { 356 {
162 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 357 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
163 LogHeader, prim.LocalID, shapeType); 358 LogHeader, prim.LocalID, shapeType);
164 } 359 }
165 type = shapeType; 360 newShape.shapeType = shapeType;
166 key = (UInt64)shapeKey; 361 newShape.isNativeShape = true;
167 */ 362 newShape.shapeKey = (UInt64)shapeKey;
168 } 363 return newShape;
169 // Make this reference to the physical shape go away since native shapes are not shared.
170 public override void Dereference(BSScene physicsScene)
171 {
172 /*
173 // Native shapes are not tracked and are released immediately
174 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
175 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
176 ptr = IntPtr.Zero;
177 // Garbage collection will free up this instance.
178 */
179 } 364 }
365
180} 366}
181 367
368// ============================================================================================================
182public class BSShapeMesh : BSShape 369public class BSShapeMesh : BSShape
183{ 370{
184 private static string LogHeader = "[BULLETSIM SHAPE MESH]"; 371 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
185 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); 372 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
186 373
187 public BSShapeMesh() : base() 374 public BSShapeMesh(BulletShape pShape) : base(pShape)
188 { 375 {
189 } 376 }
190 public static BSShape GetReference() { return new BSShapeNull(); } 377 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
191 public override void Dereference(BSScene physicsScene) { } 378 {
379 float lod;
380 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
381
382 BSShapeMesh retMesh = null;
383 lock (Meshes)
384 {
385 if (Meshes.TryGetValue(newMeshKey, out retMesh))
386 {
387 // The mesh has already been created. Return a new reference to same.
388 retMesh.IncrementReference();
389 }
390 else
391 {
392 retMesh = new BSShapeMesh(new BulletShape());
393 // An instance of this mesh has not been created. Build and remember same.
394 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
395
396 // Check to see if mesh was created (might require an asset).
397 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
398 if (!newShape.isNativeShape
399 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing
400 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
401 {
402 // If a mesh was what was created, remember the built shape for later sharing.
403 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
404 Meshes.Add(newMeshKey, retMesh);
405 }
406
407 retMesh.physShapeInfo = newShape;
408 }
409 }
410 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
411 return retMesh;
412 }
413 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
414 {
415 BSShape ret = null;
416 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
417 // and we must create a copy of the native shape since they are never shared.
418 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
419 {
420 // TODO: decide when the native shapes should be freed. Check in Dereference?
421 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
422 }
423 else
424 {
425 // Another reference to this shape is just counted.
426 IncrementReference();
427 ret = this;
428 }
429 return ret;
430 }
431 public override void Dereference(BSScene physicsScene)
432 {
433 lock (Meshes)
434 {
435 this.DecrementReference();
436 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
437 // TODO: schedule aging and destruction of unused meshes.
438 }
439 }
440 // Loop through all the known meshes and return the description based on the physical address.
441 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
442 {
443 bool ret = false;
444 BSShapeMesh foundDesc = null;
445 lock (Meshes)
446 {
447 foreach (BSShapeMesh sm in Meshes.Values)
448 {
449 if (sm.physShapeInfo.ReferenceSame(pShape))
450 {
451 foundDesc = sm;
452 ret = true;
453 break;
454 }
455
456 }
457 }
458 outMesh = foundDesc;
459 return ret;
460 }
461
462 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
463 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
464 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
465 {
466 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
467 (w, iC, i, vC, v) => physicsScene.PE.CreateMeshShape(w, iC, i, vC, v) );
468 }
469
470 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
471 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
472 // The actual build call is passed so this logic can be used by several of the shapes that use a
473 // simple mesh as their base shape.
474 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
475 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
476 {
477 BulletShape newShape = new BulletShape();
478
479 IMesh meshData = null;
480 lock (physicsScene.mesher)
481 {
482 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
483 false, // say it is not physical so a bounding box is not built
484 false, // do not cache the mesh and do not use previously built versions
485 false,
486 false
487 );
488 }
489
490 if (meshData != null)
491 {
492 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
493 {
494 // Release the fetched asset data once it has been used.
495 pbs.SculptData = new byte[0];
496 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
497 }
498
499 int[] indices = meshData.getIndexListAsInt();
500 int realIndicesIndex = indices.Length;
501 float[] verticesAsFloats = meshData.getVertexListAsFloat();
502
503 if (BSParam.ShouldRemoveZeroWidthTriangles)
504 {
505 // Remove degenerate triangles. These are triangles with two of the vertices
506 // are the same. This is complicated by the problem that vertices are not
507 // made unique in sculpties so we have to compare the values in the vertex.
508 realIndicesIndex = 0;
509 for (int tri = 0; tri < indices.Length; tri += 3)
510 {
511 // Compute displacements into vertex array for each vertex of the triangle
512 int v1 = indices[tri + 0] * 3;
513 int v2 = indices[tri + 1] * 3;
514 int v3 = indices[tri + 2] * 3;
515 // Check to see if any two of the vertices are the same
516 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
517 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
518 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
519 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
520 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
521 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
522 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
523 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
524 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
525 )
526 {
527 // None of the vertices of the triangles are the same. This is a good triangle;
528 indices[realIndicesIndex + 0] = indices[tri + 0];
529 indices[realIndicesIndex + 1] = indices[tri + 1];
530 indices[realIndicesIndex + 2] = indices[tri + 2];
531 realIndicesIndex += 3;
532 }
533 }
534 }
535 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
536 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
537
538 if (realIndicesIndex != 0)
539 {
540 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
541 }
542 else
543 {
544 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
545 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
546 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
547 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
548 }
549 }
550 newShape.shapeKey = newMeshKey;
551
552 return newShape;
553 }
192} 554}
193 555
556// ============================================================================================================
194public class BSShapeHull : BSShape 557public class BSShapeHull : BSShape
195{ 558{
196 private static string LogHeader = "[BULLETSIM SHAPE HULL]"; 559 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
197 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); 560 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
198 561
199 public BSShapeHull() : base() 562 public BSShapeHull(BulletShape pShape) : base(pShape)
200 { 563 {
201 } 564 }
202 public static BSShape GetReference() { return new BSShapeNull(); } 565 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
203 public override void Dereference(BSScene physicsScene) { } 566 {
567 float lod;
568 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
569
570 BSShapeHull retHull = null;
571 lock (Hulls)
572 {
573 if (Hulls.TryGetValue(newHullKey, out retHull))
574 {
575 // The mesh has already been created. Return a new reference to same.
576 retHull.IncrementReference();
577 }
578 else
579 {
580 retHull = new BSShapeHull(new BulletShape());
581 // An instance of this mesh has not been created. Build and remember same.
582 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
583
584 // Check to see if hull was created (might require an asset).
585 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
586 if (!newShape.isNativeShape
587 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing
588 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
589 {
590 // If a mesh was what was created, remember the built shape for later sharing.
591 Hulls.Add(newHullKey, retHull);
592 }
593 retHull.physShapeInfo = newShape;
594 }
595 }
596 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
597 return retHull;
598 }
599 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
600 {
601 BSShape ret = null;
602 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
603 // and we must create a copy of the native shape since they are never shared.
604 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
605 {
606 // TODO: decide when the native shapes should be freed. Check in Dereference?
607 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
608 }
609 else
610 {
611 // Another reference to this shape is just counted.
612 IncrementReference();
613 ret = this;
614 }
615 return ret;
616 }
617 public override void Dereference(BSScene physicsScene)
618 {
619 lock (Hulls)
620 {
621 this.DecrementReference();
622 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
623 // TODO: schedule aging and destruction of unused meshes.
624 }
625 }
626 List<ConvexResult> m_hulls;
627 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
628 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
629 {
630 BulletShape newShape = new BulletShape();
631
632 IMesh meshData = null;
633 List<List<OMV.Vector3>> allHulls = null;
634 lock (physicsScene.mesher)
635 {
636 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
637 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false);
638
639 // If we should use the asset's hull info, fetch it out of the locked mesher
640 if (meshData != null && BSParam.ShouldUseAssetHulls)
641 {
642 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
643 if (realMesher != null)
644 {
645 allHulls = realMesher.GetConvexHulls(size);
646 }
647 if (allHulls == null)
648 {
649 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
650 }
651 }
652 }
653
654 // If there is hull data in the mesh asset, build the hull from that
655 if (allHulls != null && BSParam.ShouldUseAssetHulls)
656 {
657 int hullCount = allHulls.Count;
658 int totalVertices = 1; // include one for the count of the hulls
659 // Using the structure described for HACD hulls, create the memory sturcture
660 // to pass the hull data to the creater.
661 foreach (List<OMV.Vector3> hullVerts in allHulls)
662 {
663 totalVertices += 4; // add four for the vertex count and centroid
664 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
665 }
666 float[] convHulls = new float[totalVertices];
667
668 convHulls[0] = (float)hullCount;
669 int jj = 1;
670 foreach (List<OMV.Vector3> hullVerts in allHulls)
671 {
672 convHulls[jj + 0] = hullVerts.Count;
673 convHulls[jj + 1] = 0f; // centroid x,y,z
674 convHulls[jj + 2] = 0f;
675 convHulls[jj + 3] = 0f;
676 jj += 4;
677 foreach (OMV.Vector3 oneVert in hullVerts)
678 {
679 convHulls[jj + 0] = oneVert.X;
680 convHulls[jj + 1] = oneVert.Y;
681 convHulls[jj + 2] = oneVert.Z;
682 jj += 3;
683 }
684 }
685
686 // create the hull data structure in Bullet
687 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
688
689 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
690 prim.LocalID, hullCount, totalVertices, newShape);
691 }
692
693 // If no hull specified in the asset and we should use Bullet's HACD approximation...
694 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
695 {
696 // Build the hull shape from an existing mesh shape.
697 // The mesh should have already been created in Bullet.
698 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
699 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
700
701 if (meshShape.physShapeInfo.HasPhysicalShape)
702 {
703 HACDParams parms;
704 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
705 parms.minClusters = BSParam.BHullMinClusters;
706 parms.compacityWeight = BSParam.BHullCompacityWeight;
707 parms.volumeWeight = BSParam.BHullVolumeWeight;
708 parms.concavity = BSParam.BHullConcavity;
709 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
710 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
711 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
712 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
713
714 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
715 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
716 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
717
718 // Now done with the mesh shape.
719 meshShape.Dereference(physicsScene);
720 }
721 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
722 }
723
724 // If no other hull specifications, use our HACD hull approximation.
725 if (!newShape.HasPhysicalShape && meshData != null)
726 {
727 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
728 {
729 // Release the fetched asset data once it has been used.
730 pbs.SculptData = new byte[0];
731 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
732 }
733
734 int[] indices = meshData.getIndexListAsInt();
735 List<OMV.Vector3> vertices = meshData.getVertexList();
736
737 //format conversion from IMesh format to DecompDesc format
738 List<int> convIndices = new List<int>();
739 List<float3> convVertices = new List<float3>();
740 for (int ii = 0; ii < indices.GetLength(0); ii++)
741 {
742 convIndices.Add(indices[ii]);
743 }
744 foreach (OMV.Vector3 vv in vertices)
745 {
746 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
747 }
748
749 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
750 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
751 {
752 // Simple primitive shapes we know are convex so they are better implemented with
753 // fewer hulls.
754 // Check for simple shape (prim without cuts) and reduce split parameter if so.
755 if (BSShapeCollection.PrimHasNoCuts(pbs))
756 {
757 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
758 }
759 }
760
761 // setup and do convex hull conversion
762 m_hulls = new List<ConvexResult>();
763 DecompDesc dcomp = new DecompDesc();
764 dcomp.mIndices = convIndices;
765 dcomp.mVertices = convVertices;
766 dcomp.mDepth = maxDepthSplit;
767 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
768 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
769 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
770 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
771 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
772 // create the hull into the _hulls variable
773 convexBuilder.process(dcomp);
774
775 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
776 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
777
778 // Convert the vertices and indices for passing to unmanaged.
779 // The hull information is passed as a large floating point array.
780 // The format is:
781 // convHulls[0] = number of hulls
782 // convHulls[1] = number of vertices in first hull
783 // convHulls[2] = hull centroid X coordinate
784 // convHulls[3] = hull centroid Y coordinate
785 // convHulls[4] = hull centroid Z coordinate
786 // convHulls[5] = first hull vertex X
787 // convHulls[6] = first hull vertex Y
788 // convHulls[7] = first hull vertex Z
789 // convHulls[8] = second hull vertex X
790 // ...
791 // convHulls[n] = number of vertices in second hull
792 // convHulls[n+1] = second hull centroid X coordinate
793 // ...
794 //
795 // TODO: is is very inefficient. Someday change the convex hull generator to return
796 // data structures that do not need to be converted in order to pass to Bullet.
797 // And maybe put the values directly into pinned memory rather than marshaling.
798 int hullCount = m_hulls.Count;
799 int totalVertices = 1; // include one for the count of the hulls
800 foreach (ConvexResult cr in m_hulls)
801 {
802 totalVertices += 4; // add four for the vertex count and centroid
803 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
804 }
805 float[] convHulls = new float[totalVertices];
806
807 convHulls[0] = (float)hullCount;
808 int jj = 1;
809 foreach (ConvexResult cr in m_hulls)
810 {
811 // copy vertices for index access
812 float3[] verts = new float3[cr.HullVertices.Count];
813 int kk = 0;
814 foreach (float3 ff in cr.HullVertices)
815 {
816 verts[kk++] = ff;
817 }
818
819 // add to the array one hull's worth of data
820 convHulls[jj++] = cr.HullIndices.Count;
821 convHulls[jj++] = 0f; // centroid x,y,z
822 convHulls[jj++] = 0f;
823 convHulls[jj++] = 0f;
824 foreach (int ind in cr.HullIndices)
825 {
826 convHulls[jj++] = verts[ind].x;
827 convHulls[jj++] = verts[ind].y;
828 convHulls[jj++] = verts[ind].z;
829 }
830 }
831 // create the hull data structure in Bullet
832 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
833 }
834 newShape.shapeKey = newHullKey;
835 return newShape;
836 }
837 // Callback from convex hull creater with a newly created hull.
838 // Just add it to our collection of hulls for this shape.
839 private void HullReturn(ConvexResult result)
840 {
841 m_hulls.Add(result);
842 return;
843 }
844 // Loop through all the known hulls and return the description based on the physical address.
845 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
846 {
847 bool ret = false;
848 BSShapeHull foundDesc = null;
849 lock (Hulls)
850 {
851 foreach (BSShapeHull sh in Hulls.Values)
852 {
853 if (sh.physShapeInfo.ReferenceSame(pShape))
854 {
855 foundDesc = sh;
856 ret = true;
857 break;
858 }
859
860 }
861 }
862 outHull = foundDesc;
863 return ret;
864 }
204} 865}
205 866
867// ============================================================================================================
206public class BSShapeCompound : BSShape 868public class BSShapeCompound : BSShape
207{ 869{
208 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; 870 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
209 public BSShapeCompound() : base() 871 public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
872
873 public BSShapeCompound(BulletShape pShape) : base(pShape)
210 { 874 {
211 } 875 }
212 public static BSShape GetReference(BSPhysObject prim) 876 public static BSShape GetReference(BSScene physicsScene)
213 { 877 {
214 return new BSShapeNull(); 878 // Base compound shapes are not shared so this returns a raw shape.
879 // A built compound shape can be reused in linksets.
880 BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
881 CompoundShapes.Add(ret.AddrString, ret);
882 return ret;
883 }
884 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
885 {
886 // Calling this reference means we want another handle to an existing compound shape
887 // (usually linksets) so return this copy.
888 IncrementReference();
889 return this;
890 }
891 // Dereferencing a compound shape releases the hold on all the child shapes.
892 public override void Dereference(BSScene physicsScene)
893 {
894 lock (physShapeInfo)
895 {
896 this.DecrementReference();
897 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
898 if (referenceCount <= 0)
899 {
900 if (!physicsScene.PE.IsCompound(physShapeInfo))
901 {
902 // Failed the sanity check!!
903 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
904 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
905 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
906 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
907 return;
908 }
909
910 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
911 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
912 BSScene.DetailLogZero, physShapeInfo, numChildren);
913
914 // Loop through all the children dereferencing each.
915 for (int ii = numChildren - 1; ii >= 0; ii--)
916 {
917 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
918 DereferenceAnonCollisionShape(physicsScene, childShape);
919 }
920
921 lock (CompoundShapes)
922 CompoundShapes.Remove(physShapeInfo.AddrString);
923 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
924 }
925 }
926 }
927 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
928 {
929 lock (CompoundShapes)
930 {
931 string addr = pShape.AddrString;
932 return CompoundShapes.TryGetValue(addr, out outCompound);
933 }
934 }
935 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
936 {
937 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
938 return cShape;
939 }
940 // Sometimes we have a pointer to a collision shape but don't know what type it is.
941 // Figure out type and call the correct dereference routine.
942 // Called at taint-time.
943 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
944 {
945 // TODO: figure a better way to go through all the shape types and find a possible instance.
946 physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
947 BSScene.DetailLogZero, pShape);
948 BSShapeMesh meshDesc;
949 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
950 {
951 meshDesc.Dereference(physicsScene);
952 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
953 }
954 else
955 {
956 BSShapeHull hullDesc;
957 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
958 {
959 hullDesc.Dereference(physicsScene);
960 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
961 }
962 else
963 {
964 BSShapeConvexHull chullDesc;
965 if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
966 {
967 chullDesc.Dereference(physicsScene);
968 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
969 }
970 else
971 {
972 BSShapeGImpact gImpactDesc;
973 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
974 {
975 gImpactDesc.Dereference(physicsScene);
976 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
977 }
978 else
979 {
980 // Didn't find it in the lists of specific types. It could be compound.
981 BSShapeCompound compoundDesc;
982 if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
983 {
984 compoundDesc.Dereference(physicsScene);
985 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
986 }
987 else
988 {
989 // If none of the above, maybe it is a simple native shape.
990 if (physicsScene.PE.IsNativeShape(pShape))
991 {
992 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
993 BSShapeNative nativeShape = new BSShapeNative(pShape);
994 nativeShape.Dereference(physicsScene);
995 }
996 }
997 }
998 }
999 }
1000 }
1001 }
1002}
1003
1004// ============================================================================================================
1005public class BSShapeConvexHull : BSShape
1006{
1007 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1008 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1009
1010 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1011 {
1012 }
1013 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1014 {
1015 float lod;
1016 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1017
1018 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1019 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1020
1021 BSShapeConvexHull retConvexHull = null;
1022 lock (ConvexHulls)
1023 {
1024 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1025 {
1026 // The mesh has already been created. Return a new reference to same.
1027 retConvexHull.IncrementReference();
1028 }
1029 else
1030 {
1031 retConvexHull = new BSShapeConvexHull(new BulletShape());
1032 BulletShape convexShape = null;
1033
1034 // Get a handle to a mesh to build the hull from
1035 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1036 if (baseMesh.physShapeInfo.isNativeShape)
1037 {
1038 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1039 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1040 // get back to this code with a buildable mesh.
1041 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1042 convexShape = baseMesh.physShapeInfo;
1043 }
1044 else
1045 {
1046 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1047 convexShape.shapeKey = newMeshKey;
1048 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1049 physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1050 BSScene.DetailLogZero, convexShape);
1051 }
1052
1053 // Done with the base mesh
1054 baseMesh.Dereference(physicsScene);
1055
1056 retConvexHull.physShapeInfo = convexShape;
1057 }
1058 }
1059 return retConvexHull;
1060 }
1061 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1062 {
1063 // Calling this reference means we want another handle to an existing shape
1064 // (usually linksets) so return this copy.
1065 IncrementReference();
1066 return this;
1067 }
1068 // Dereferencing a compound shape releases the hold on all the child shapes.
1069 public override void Dereference(BSScene physicsScene)
1070 {
1071 lock (ConvexHulls)
1072 {
1073 this.DecrementReference();
1074 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1075 // TODO: schedule aging and destruction of unused meshes.
1076 }
1077 }
1078 // Loop through all the known hulls and return the description based on the physical address.
1079 public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1080 {
1081 bool ret = false;
1082 BSShapeConvexHull foundDesc = null;
1083 lock (ConvexHulls)
1084 {
1085 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1086 {
1087 if (sh.physShapeInfo.ReferenceSame(pShape))
1088 {
1089 foundDesc = sh;
1090 ret = true;
1091 break;
1092 }
1093
1094 }
1095 }
1096 outHull = foundDesc;
1097 return ret;
1098 }
1099}
1100// ============================================================================================================
1101public class BSShapeGImpact : BSShape
1102{
1103 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1104 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1105
1106 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1107 {
1108 }
1109 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1110 {
1111 float lod;
1112 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1113
1114 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1115 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1116
1117 BSShapeGImpact retGImpact = null;
1118 lock (GImpacts)
1119 {
1120 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1121 {
1122 // The mesh has already been created. Return a new reference to same.
1123 retGImpact.IncrementReference();
1124 }
1125 else
1126 {
1127 retGImpact = new BSShapeGImpact(new BulletShape());
1128 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1129
1130 // Check to see if mesh was created (might require an asset).
1131 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1132 newShape.shapeKey = newMeshKey;
1133 if (!newShape.isNativeShape
1134 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing
1135 || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
1136 {
1137 // If a mesh was what was created, remember the built shape for later sharing.
1138 // Also note that if meshing failed we put it in the mesh list as there is nothing
1139 // else to do about the mesh.
1140 GImpacts.Add(newMeshKey, retGImpact);
1141 }
1142
1143 retGImpact.physShapeInfo = newShape;
1144 }
1145 }
1146 return retGImpact;
1147 }
1148
1149 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1150 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1151 {
1152 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1153 (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) );
1154 }
1155
1156 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1157 {
1158 BSShape ret = null;
1159 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1160 // and we must create a copy of the native shape since they are never shared.
1161 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1162 {
1163 // TODO: decide when the native shapes should be freed. Check in Dereference?
1164 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1165 }
1166 else
1167 {
1168 // Another reference to this shape is just counted.
1169 IncrementReference();
1170 ret = this;
1171 }
1172 return ret;
1173 }
1174 // Dereferencing a compound shape releases the hold on all the child shapes.
1175 public override void Dereference(BSScene physicsScene)
1176 {
1177 lock (GImpacts)
1178 {
1179 this.DecrementReference();
1180 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1181 // TODO: schedule aging and destruction of unused meshes.
1182 }
1183 }
1184 // Loop through all the known hulls and return the description based on the physical address.
1185 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1186 {
1187 bool ret = false;
1188 BSShapeGImpact foundDesc = null;
1189 lock (GImpacts)
1190 {
1191 foreach (BSShapeGImpact sh in GImpacts.Values)
1192 {
1193 if (sh.physShapeInfo.ReferenceSame(pShape))
1194 {
1195 foundDesc = sh;
1196 ret = true;
1197 break;
1198 }
1199
1200 }
1201 }
1202 outHull = foundDesc;
1203 return ret;
215 } 1204 }
216 public override void Dereference(BSScene physicsScene) { }
217} 1205}
218 1206
1207// ============================================================================================================
219public class BSShapeAvatar : BSShape 1208public class BSShapeAvatar : BSShape
220{ 1209{
221 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; 1210 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
222 public BSShapeAvatar() : base() 1211 public BSShapeAvatar() : base()
223 { 1212 {
224 } 1213 }
225 public static BSShape GetReference(BSPhysObject prim) 1214 public static BSShape GetReference(BSPhysObject prim)
226 { 1215 {
1216 return new BSShapeNull();
1217 }
1218 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1219 {
227 return new BSShapeNull(); 1220 return new BSShapeNull();
228 } 1221 }
229 public override void Dereference(BSScene physicsScene) { } 1222 public override void Dereference(BSScene physicsScene) { }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index e4fecc3..8888d6d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -68,7 +68,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
68 68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z 69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap). 70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords) 72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 73 : base(physicsScene, regionBase, id)
74 { 74 {
@@ -92,7 +92,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
92 private void BuildHeightmapTerrain() 92 private void BuildHeightmapTerrain()
93 { 93 {
94 // Create the terrain shape from the mapInfo 94 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, 95 m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, 96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); 97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98 98
@@ -103,26 +103,25 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105 105
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, 106 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity); 107 m_mapInfo.ID, centerPos, Quaternion.Identity);
108 108
109 // Set current terrain attributes 109 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); 110 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); 111 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); 112 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); 113 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
114
115 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
114 116
115 // Return the new terrain to the world of physical objects 117 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); 118 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
117 119
118 // redo its bounding box now that it is in the world 120 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); 121 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
123 122
124 // Make it so the terrain will not move or be considered for movement. 123 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); 124 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126 125
127 return; 126 return;
128 } 127 }
@@ -134,9 +133,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
134 { 133 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody) 134 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 { 135 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); 136 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape. 137 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); 138 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
140 } 139 }
141 } 140 }
142 m_mapInfo = null; 141 m_mapInfo = null;
@@ -155,7 +154,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
155 catch 154 catch
156 { 155 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 156 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
158 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 157 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos); 158 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 159 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 } 160 }
@@ -165,7 +164,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
165 // The passed position is relative to the base of the region. 164 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos) 165 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 { 166 {
168 return PhysicsScene.SimpleWaterLevel; 167 return m_physicsScene.SimpleWaterLevel;
169 } 168 }
170} 169}
171} 170}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index cd15850..441d2d3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -50,14 +50,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 50 Mesh = 1
51 } 51 }
52 52
53 public BSScene PhysicsScene { get; private set; } 53 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 56 public uint ID { get; private set; }
57 57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 59 {
60 PhysicsScene = physicsScene; 60 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 61 TerrainBase = regionBase;
62 ID = id; 62 ID = id;
63 } 63 }
@@ -86,7 +86,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
88 // The scene that I am part of 88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 89 private BSScene m_physicsScene { get; set; }
90 90
91 // The ground plane created to keep thing from falling to infinity. 91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 92 private BulletBody m_groundPlane;
@@ -113,7 +113,7 @@ public sealed class BSTerrainManager : IDisposable
113 113
114 public BSTerrainManager(BSScene physicsScene) 114 public BSTerrainManager(BSScene physicsScene)
115 { 115 {
116 PhysicsScene = physicsScene; 116 m_physicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 118
119 // Assume one region of default size 119 // Assume one region of default size
@@ -132,21 +132,22 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
134 { 134 {
135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 135 DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
136 // The ground plane is here to catch things that are trying to drop to negative infinity 136 // The ground plane is here to catch things that are trying to drop to negative infinity
137 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); 137 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
138 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 138 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 139 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
140 140
141 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
142 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
143 // Ground plane does not move
144 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
145 // Everything collides with the ground plane. 141 // Everything collides with the ground plane.
146 m_groundPlane.collisionType = CollisionType.Groundplane; 142 m_groundPlane.collisionType = CollisionType.Groundplane;
147 m_groundPlane.ApplyCollisionMask(PhysicsScene);
148 143
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
145 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
146
147 // Ground plane does not move
148 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
149
150 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
150 lock (m_terrains) 151 lock (m_terrains)
151 { 152 {
152 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 153 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
@@ -157,12 +158,12 @@ public sealed class BSTerrainManager : IDisposable
157 // Release all the terrain structures we might have allocated 158 // Release all the terrain structures we might have allocated
158 public void ReleaseGroundPlaneAndTerrain() 159 public void ReleaseGroundPlaneAndTerrain()
159 { 160 {
160 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); 161 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
161 if (m_groundPlane.HasPhysicalBody) 162 if (m_groundPlane.HasPhysicalBody)
162 { 163 {
163 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 164 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
164 { 165 {
165 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 166 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
166 } 167 }
167 m_groundPlane.Clear(); 168 m_groundPlane.Clear();
168 } 169 }
@@ -188,7 +189,7 @@ public sealed class BSTerrainManager : IDisposable
188 float[] localHeightMap = heightMap; 189 float[] localHeightMap = heightMap;
189 // If there are multiple requests for changes to the same terrain between ticks, 190 // If there are multiple requests for changes to the same terrain between ticks,
190 // only do that last one. 191 // only do that last one.
191 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 192 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
192 { 193 {
193 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 194 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
194 { 195 {
@@ -213,13 +214,13 @@ public sealed class BSTerrainManager : IDisposable
213 }); 214 });
214 } 215 }
215 216
216 // Another region is calling this region passing a terrain. 217 // Another region is calling this region and passing a terrain.
217 // A region that is not the mega-region root will pass its terrain to the root region so the root region 218 // A region that is not the mega-region root will pass its terrain to the root region so the root region
218 // physics engine will have all the terrains. 219 // physics engine will have all the terrains.
219 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 220 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
220 { 221 {
221 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. 222 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
222 PhysicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + m_worldOffset.ToString(), 0, delegate() 223 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
223 { 224 {
224 UpdateTerrain(id, heightMap, minCoords, maxCoords); 225 UpdateTerrain(id, heightMap, minCoords, maxCoords);
225 }); 226 });
@@ -306,7 +307,7 @@ public sealed class BSTerrainManager : IDisposable
306 newTerrainID = ++m_terrainCount; 307 newTerrainID = ++m_terrainCount;
307 308
308 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 309 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
309 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 310 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
310 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 311 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
311 m_terrains.Add(terrainRegionBase, newTerrainPhys); 312 m_terrains.Add(terrainRegionBase, newTerrainPhys);
312 313
@@ -318,26 +319,26 @@ public sealed class BSTerrainManager : IDisposable
318 // TODO: redo terrain implementation selection to allow other base types than heightMap. 319 // TODO: redo terrain implementation selection to allow other base types than heightMap.
319 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) 320 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
320 { 321 {
321 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 322 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
322 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 323 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
323 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 324 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
324 BSTerrainPhys newTerrainPhys = null; 325 BSTerrainPhys newTerrainPhys = null;
325 switch ((int)BSParam.TerrainImplementation) 326 switch ((int)BSParam.TerrainImplementation)
326 { 327 {
327 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 328 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
328 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 329 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
329 heightMap, minCoords, maxCoords); 330 heightMap, minCoords, maxCoords);
330 break; 331 break;
331 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 332 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
332 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 333 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
333 heightMap, minCoords, maxCoords); 334 heightMap, minCoords, maxCoords);
334 break; 335 break;
335 default: 336 default:
336 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 337 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
337 LogHeader, 338 LogHeader,
338 (int)BSParam.TerrainImplementation, 339 (int)BSParam.TerrainImplementation,
339 BSParam.TerrainImplementation, 340 BSParam.TerrainImplementation,
340 PhysicsScene.RegionName, terrainRegionBase); 341 m_physicsScene.RegionName, terrainRegionBase);
341 break; 342 break;
342 } 343 }
343 return newTerrainPhys; 344 return newTerrainPhys;
@@ -354,6 +355,8 @@ public sealed class BSTerrainManager : IDisposable
354 // Return a new position that is over known terrain if the position is outside our terrain. 355 // Return a new position that is over known terrain if the position is outside our terrain.
355 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) 356 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
356 { 357 {
358 float edgeEpsilon = 0.1f;
359
357 Vector3 ret = pPos; 360 Vector3 ret = pPos;
358 361
359 // First, base addresses are never negative so correct for that possible problem. 362 // First, base addresses are never negative so correct for that possible problem.
@@ -378,10 +381,19 @@ public sealed class BSTerrainManager : IDisposable
378 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. 381 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
379 382
380 // Must be off the top of a region. Find an adjacent region to move into. 383 // Must be off the top of a region. Find an adjacent region to move into.
384 // The returned terrain is always 'lower'. That is, closer to <0,0>.
381 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); 385 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
382 386
383 ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X)); 387 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
384 ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y)); 388 {
389 // moving down into a new region in the X dimension. New position will be the max in the new base.
390 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
391 }
392 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
393 {
394 // moving down into a new region in the X dimension. New position will be the max in the new base.
395 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
396 }
385 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", 397 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
386 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); 398 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
387 399
@@ -429,8 +441,8 @@ public sealed class BSTerrainManager : IDisposable
429 } 441 }
430 else 442 else
431 { 443 {
432 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 444 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
433 LogHeader, PhysicsScene.RegionName, tX, tY); 445 LogHeader, m_physicsScene.RegionName, tX, tY);
434 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 446 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
435 BSScene.DetailLogZero, pos, terrainBaseXYZ); 447 BSScene.DetailLogZero, pos, terrainBaseXYZ);
436 } 448 }
@@ -451,8 +463,8 @@ public sealed class BSTerrainManager : IDisposable
451 } 463 }
452 else 464 else
453 { 465 {
454 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 466 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
455 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 467 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
456 } 468 }
457 return ret; 469 return ret;
458 } 470 }
@@ -564,7 +576,7 @@ public sealed class BSTerrainManager : IDisposable
564 576
565 private void DetailLog(string msg, params Object[] args) 577 private void DetailLog(string msg, params Object[] args)
566 { 578 {
567 PhysicsScene.PhysicsLogging.Write(msg, args); 579 m_physicsScene.PhysicsLogging.Write(msg, args);
568 } 580 }
569} 581}
570} 582}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index 2ce1513..e4ca098 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -51,7 +51,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
51 BulletShape m_terrainShape; 51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody; 52 BulletBody m_terrainBody;
53 53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) 54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id) 55 : base(physicsScene, regionBase, id)
56 { 56 {
57 } 57 }
@@ -62,7 +62,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
62 } 62 }
63 63
64 // Create terrain mesh from a heightmap. 64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords) 66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id) 67 : base(physicsScene, regionBase, id)
68 { 68 {
@@ -80,7 +80,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
80 if (BSParam.TerrainMeshMagnification == 1) 80 if (BSParam.TerrainMeshMagnification == 1)
81 { 81 {
82 // If a magnification of one, use the old routine that is tried and true. 82 // If a magnification of one, use the old routine that is tried and true.
83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, 83 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
84 initialMap, m_sizeX, m_sizeY, // input size 84 initialMap, m_sizeX, m_sizeY, // input size
85 Vector3.Zero, // base for mesh 85 Vector3.Zero, // base for mesh
86 out indicesCount, out indices, out verticesCount, out vertices); 86 out indicesCount, out indices, out verticesCount, out vertices);
@@ -88,7 +88,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 else 88 else
89 { 89 {
90 // Other magnifications use the newer routine 90 // Other magnifications use the newer routine
91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene, 91 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
92 initialMap, m_sizeX, m_sizeY, // input size 92 initialMap, m_sizeX, m_sizeY, // input size
93 BSParam.TerrainMeshMagnification, 93 BSParam.TerrainMeshMagnification,
94 physicsScene.TerrainManager.DefaultRegionSize, 94 physicsScene.TerrainManager.DefaultRegionSize,
@@ -98,21 +98,21 @@ public sealed class BSTerrainMesh : BSTerrainPhys
98 if (!meshCreationSuccess) 98 if (!meshCreationSuccess)
99 { 99 {
100 // DISASTER!! 100 // DISASTER!!
101 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); 101 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
102 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); 102 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
103 // Something is very messed up and a crash is in our future. 103 // Something is very messed up and a crash is in our future.
104 return; 104 return;
105 } 105 }
106 106
107 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", 107 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); 108 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
109 109
110 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); 110 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
111 if (!m_terrainShape.HasPhysicalShape) 111 if (!m_terrainShape.HasPhysicalShape)
112 { 112 {
113 // DISASTER!! 113 // DISASTER!!
114 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); 114 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
115 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); 115 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
116 // Something is very messed up and a crash is in our future. 116 // Something is very messed up and a crash is in our future.
117 return; 117 return;
118 } 118 }
@@ -120,52 +120,52 @@ public sealed class BSTerrainMesh : BSTerrainPhys
120 Vector3 pos = regionBase; 120 Vector3 pos = regionBase;
121 Quaternion rot = Quaternion.Identity; 121 Quaternion rot = Quaternion.Identity;
122 122
123 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); 123 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
124 if (!m_terrainBody.HasPhysicalBody) 124 if (!m_terrainBody.HasPhysicalBody)
125 { 125 {
126 // DISASTER!! 126 // DISASTER!!
127 PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 127 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
128 // Something is very messed up and a crash is in our future. 128 // Something is very messed up and a crash is in our future.
129 return; 129 return;
130 } 130 }
131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); 131 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
132 132
133 // Set current terrain attributes 133 // Set current terrain attributes
134 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); 134 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
135 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); 135 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
136 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); 136 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
137 PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); 137 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
138 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); 138 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
139 139
140 // Static objects are not very massive. 140 // Static objects are not very massive.
141 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); 141 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
142 142
143 // Put the new terrain to the world of physical objects 143 // Put the new terrain to the world of physical objects
144 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); 144 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
145 145
146 // Redo its bounding box now that it is in the world 146 // Redo its bounding box now that it is in the world
147 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
148 148
149 m_terrainBody.collisionType = CollisionType.Terrain; 149 m_terrainBody.collisionType = CollisionType.Terrain;
150 m_terrainBody.ApplyCollisionMask(PhysicsScene); 150 m_terrainBody.ApplyCollisionMask(m_physicsScene);
151 151
152 if (BSParam.UseSingleSidedMeshes) 152 if (BSParam.UseSingleSidedMeshes)
153 { 153 {
154 PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); 154 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
155 PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); 155 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
156 } 156 }
157 157
158 // Make it so the terrain will not move or be considered for movement. 158 // Make it so the terrain will not move or be considered for movement.
159 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); 159 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
160 } 160 }
161 161
162 public override void Dispose() 162 public override void Dispose()
163 { 163 {
164 if (m_terrainBody.HasPhysicalBody) 164 if (m_terrainBody.HasPhysicalBody)
165 { 165 {
166 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); 166 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
167 // Frees both the body and the shape. 167 // Frees both the body and the shape.
168 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
169 m_terrainBody.Clear(); 169 m_terrainBody.Clear();
170 m_terrainShape.Clear(); 170 m_terrainShape.Clear();
171 } 171 }
@@ -185,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
185 catch 185 catch
186 { 186 {
187 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 187 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
188 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", 188 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
189 LogHeader, TerrainBase, pos); 189 LogHeader, TerrainBase, pos);
190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 190 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
191 } 191 }
@@ -195,7 +195,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
195 // The passed position is relative to the base of the region. 195 // The passed position is relative to the base of the region.
196 public override float GetWaterLevelAtXYZ(Vector3 pos) 196 public override float GetWaterLevelAtXYZ(Vector3 pos)
197 { 197 {
198 return PhysicsScene.SimpleWaterLevel; 198 return m_physicsScene.SimpleWaterLevel;
199 } 199 }
200 200
201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 201 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
index 8012d91..971ff9f 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -104,11 +104,11 @@ public class BulletShape
104{ 104{
105 public BulletShape() 105 public BulletShape()
106 { 106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN; 107 shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; 108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false; 109 isNativeShape = false;
110 } 110 }
111 public BSPhysicsShapeType type; 111 public BSPhysicsShapeType shapeType;
112 public System.UInt64 shapeKey; 112 public System.UInt64 shapeKey;
113 public bool isNativeShape; 113 public bool isNativeShape;
114 114
@@ -133,7 +133,7 @@ public class BulletShape
133 buff.Append("<p="); 133 buff.Append("<p=");
134 buff.Append(AddrString); 134 buff.Append(AddrString);
135 buff.Append(",s="); 135 buff.Append(",s=");
136 buff.Append(type.ToString()); 136 buff.Append(shapeType.ToString());
137 buff.Append(",k="); 137 buff.Append(",k=");
138 buff.Append(shapeKey.ToString("X")); 138 buff.Append(shapeKey.ToString("X"));
139 buff.Append(",n="); 139 buff.Append(",n=");
@@ -224,42 +224,43 @@ public static class BulletSimData
224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code 224// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
225// but, instead, use references to this dictionary. Finding and debugging 225// but, instead, use references to this dictionary. Finding and debugging
226// collision flag problems will be made easier. 226// collision flag problems will be made easier.
227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 227public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>() 228 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
229{ 229{
230 { CollisionType.Avatar, 230 { CollisionType.Avatar,
231 new CollisionTypeFilterGroup(CollisionType.Avatar, 231 new CollisionTypeFilterGroup(CollisionType.Avatar,
232 (uint)CollisionFilterGroups.BCharacterGroup, 232 (uint)CollisionFilterGroups.BCharacterGroup,
233 (uint)CollisionFilterGroups.BAllGroup) 233 (uint)CollisionFilterGroups.BAllGroup)
234 }, 234 },
235 { CollisionType.Groundplane, 235 { CollisionType.Groundplane,
236 new CollisionTypeFilterGroup(CollisionType.Groundplane, 236 new CollisionTypeFilterGroup(CollisionType.Groundplane,
237 (uint)CollisionFilterGroups.BGroundPlaneGroup, 237 (uint)CollisionFilterGroups.BGroundPlaneGroup,
238 (uint)CollisionFilterGroups.BAllGroup) 238 // (uint)CollisionFilterGroups.BAllGroup)
239 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
239 }, 240 },
240 { CollisionType.Terrain, 241 { CollisionType.Terrain,
241 new CollisionTypeFilterGroup(CollisionType.Terrain, 242 new CollisionTypeFilterGroup(CollisionType.Terrain,
242 (uint)CollisionFilterGroups.BTerrainGroup, 243 (uint)CollisionFilterGroups.BTerrainGroup,
243 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) 244 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
244 }, 245 },
245 { CollisionType.Static, 246 { CollisionType.Static,
246 new CollisionTypeFilterGroup(CollisionType.Static, 247 new CollisionTypeFilterGroup(CollisionType.Static,
247 (uint)CollisionFilterGroups.BStaticGroup, 248 (uint)CollisionFilterGroups.BStaticGroup,
248 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 249 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
249 }, 250 },
250 { CollisionType.Dynamic, 251 { CollisionType.Dynamic,
251 new CollisionTypeFilterGroup(CollisionType.Dynamic, 252 new CollisionTypeFilterGroup(CollisionType.Dynamic,
252 (uint)CollisionFilterGroups.BSolidGroup, 253 (uint)CollisionFilterGroups.BSolidGroup,
253 (uint)(CollisionFilterGroups.BAllGroup)) 254 (uint)(CollisionFilterGroups.BAllGroup))
254 }, 255 },
255 { CollisionType.VolumeDetect, 256 { CollisionType.VolumeDetect,
256 new CollisionTypeFilterGroup(CollisionType.VolumeDetect, 257 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
257 (uint)CollisionFilterGroups.BSensorTrigger, 258 (uint)CollisionFilterGroups.BSensorTrigger,
258 (uint)(~CollisionFilterGroups.BSensorTrigger)) 259 (uint)(~CollisionFilterGroups.BSensorTrigger))
259 }, 260 },
260 { CollisionType.LinksetChild, 261 { CollisionType.LinksetChild,
261 new CollisionTypeFilterGroup(CollisionType.LinksetChild, 262 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
262 (uint)CollisionFilterGroups.BLinksetChildGroup, 263 (uint)CollisionFilterGroups.BLinksetChildGroup,
263 (uint)(CollisionFilterGroups.BNoneGroup)) 264 (uint)(CollisionFilterGroups.BNoneGroup))
264 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 265 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
265 }, 266 },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
index 8a15abe..0453376 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -1,65 +1,61 @@
1CURRENT PRIORITIES 1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2================================================= 2=================================================
3Use the HACD convex hull routine in Bullet rather than the C# version. 3Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass.
4 Speed up hullifying large meshes. 4 Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive?
5 Negative buoyancy computed correctly
6Center-of-gravity
7Computation of mesh mass. How done? How should it be done?
5Enable vehicle border crossings (at least as poorly as ODE) 8Enable vehicle border crossings (at least as poorly as ODE)
6 Terrain skirts 9 Terrain skirts
7 Avatar created in previous region and not new region when crossing border 10 Avatar created in previous region and not new region when crossing border
8 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) 11 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
9Lock axis 12User settable terrain mesh
13 Allow specifying as convex or concave and use different getHeight functions depending
14Boats, when turning nose down into the water
15 Acts like rotation around Z is also effecting rotation around X and Y
10Deleting a linkset while standing on the root will leave the physical shape of the root behind. 16Deleting a linkset while standing on the root will leave the physical shape of the root behind.
11 Not sure if it is because standing on it. Done with large prim linksets. 17 Not sure if it is because standing on it. Done with large prim linksets.
12Linkset child rotations. 18Linkset child rotations.
13 Nebadon spiral tube has middle sections which are rotated wrong. 19 Nebadon spiral tube has middle sections which are rotated wrong.
14 Select linked spiral tube. Delink and note where the middle section ends up. 20 Select linked spiral tube. Delink and note where the middle section ends up.
15Vehicle angular vertical attraction
16vehicle angular banking
17Center-of-gravity
18Vehicle angular deflection
19 Preferred orientation angular correction fix
20when should angular and linear motor targets be zeroed? when selected?
21 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
22Teravus llMoveToTarget script debug 21Teravus llMoveToTarget script debug
23 Mixing of hover, buoyancy/gravity, moveToTarget, into one force 22 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
24 Setting hover height to zero disables hover even if hover flags are on (from SL wiki) 23 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
25limitMotorUp calibration (more down?) 24limitMotorUp calibration (more down?)
26llRotLookAt 25llRotLookAt
27llLookAt 26llLookAt
28Avatars walking up stairs (HALF DONE) 27Convert to avatar mesh capsule. Include rotation of capsule.
29Avatar movement
30 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
31 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
32 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
33Vehicle script tuning/debugging 28Vehicle script tuning/debugging
34 Avanti speed script 29 Avanti speed script
35 Weapon shooter script 30 Weapon shooter script
36Move material definitions (friction, ...) into simulator. 31Move material definitions (friction, ...) into simulator.
37Add material densities to the material types. 32osGetPhysicsEngineVerion() and create a version code for the C++ DLL
38Terrain detail: double terrain mesh detail
39One sided meshes? Should terrain be built into a closed shape? 33One sided meshes? Should terrain be built into a closed shape?
40 When meshes get partially wedged into the terrain, they cannot push themselves out. 34 When meshes get partially wedged into the terrain, they cannot push themselves out.
41 It is possible that Bullet processes collisions whether entering or leaving a mesh. 35 It is possible that Bullet processes collisions whether entering or leaving a mesh.
42 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 36 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
37Small physical objects do not interact correctly
38 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
39 The chain will fall apart and pairs will dance around on ground
40 Chains of 1x1x.2 will stay connected but will dance.
41 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
43 42
44VEHICLES TODO LIST: 43VEHICLES TODO LIST:
45================================================= 44=================================================
46Border crossing with linked vehicle causes crash 45LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
47 20121129.1411: editting/moving phys object across region boundries causes crash 46 What are the limits in SL?
48 getPos-> btRigidBody::upcast -> getBodyType -> BOOM 47 Same for other velocity settings.
49Vehicles (Move smoothly) 48UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
49 https://github.com/UbitUmarov/Ubit-opensim
50Some vehicles should not be able to turn if no speed or off ground. 50Some vehicles should not be able to turn if no speed or off ground.
51What to do if vehicle and prim buoyancy differ?
52Cannot edit/move a vehicle being ridden: it jumps back to the origional position. 51Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
53Neb car jiggling left and right 52Neb car jiggling left and right
54 Happens on terrain and any other mesh object. Flat cubes are much smoother. 53 Happens on terrain and any other mesh object. Flat cubes are much smoother.
55 This has been reduced but not eliminated. 54 This has been reduced but not eliminated.
56Implement referenceFrame for all the motion routines. 55Implement referenceFrame for all the motion routines.
57For limitMotorUp, use raycast down to find if vehicle is in the air.
58Verify llGetVel() is returning a smooth and good value for vehicle movement. 56Verify llGetVel() is returning a smooth and good value for vehicle movement.
59llGetVel() should return the root's velocity if requested in a child prim. 57llGetVel() should return the root's velocity if requested in a child prim.
60Implement function efficiency for lineaar and angular motion. 58Implement function efficiency for lineaar and angular motion.
61After getting off a vehicle, the root prim is phantom (can be walked through)
62 Need to force a position update for the root prim after compound shape destruction
63Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) 59Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
64Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). 60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
65 A kludge that isn't fixing the real problem of Bullet adding extra motion. 61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
@@ -68,11 +64,10 @@ Incorporate inter-relationship of angular corrections. For instance, angularDefl
68 creates over-correction and over-shoot and wabbling. 64 creates over-correction and over-shoot and wabbling.
69Vehicle attributes are not restored when a vehicle is rezzed on region creation 65Vehicle attributes are not restored when a vehicle is rezzed on region creation
70 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. 66 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
67What to do if vehicle and prim buoyancy differ?
71 68
72GENERAL TODO LIST: 69GENERAL TODO LIST:
73================================================= 70=================================================
74Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
75 Regular triangle meshes don't do physical collisions.
76Resitution of a prim works on another prim but not on terrain. 71Resitution of a prim works on another prim but not on terrain.
77 The dropped prim doesn't bounce properly on the terrain. 72 The dropped prim doesn't bounce properly on the terrain.
78Add a sanity check for PIDTarget location. 73Add a sanity check for PIDTarget location.
@@ -98,29 +93,15 @@ Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
98Duplicating a physical prim causes old prim to jump away 93Duplicating a physical prim causes old prim to jump away
99 Dup a phys prim and the original become unselected and thus interacts w/ selected prim. 94 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
100Scenes with hundred of thousands of static objects take a lot of physics CPU time. 95Scenes with hundred of thousands of static objects take a lot of physics CPU time.
101BSPrim.Force should set a continious force on the prim. The force should be
102 applied each tick. Some limits?
103Gun sending shooter flying. 96Gun sending shooter flying.
104Collision margin (gap between physical objects lying on each other) 97Collision margin (gap between physical objects lying on each other)
105Boundry checking (crashes related to crossing boundry) 98Boundry checking (crashes related to crossing boundry)
106 Add check for border edge position for avatars and objects. 99 Add check for border edge position for avatars and objects.
107 Verify the events are created for border crossings. 100 Verify the events are created for border crossings.
108Avatar rotation (check out changes to ScenePresence for physical rotation)
109Avatar running (what does phys engine need to do?)
110Small physical objects do not interact correctly
111 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
112 The chain will fall apart and pairs will dance around on ground
113 Chains of 1x1x.2 will stay connected but will dance.
114 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
115Add PID motor for avatar movement (slow to stop, ...)
116setForce should set a constant force. Different than AddImpulse.
117Implement raycast.
118Implement ShapeCollection.Dispose() 101Implement ShapeCollection.Dispose()
119Implement water as a plain so raycasting and collisions can happen with same. 102Implement water as a plain or mesh so raycasting and collisions can happen with same.
120Add collision penetration return 103Add collision penetration return
121 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() 104 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
122Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
123 Also osGetPhysicsEngineVerion() maybe.
124Linkset.Position and Linkset.Orientation requre rewrite to properly return 105Linkset.Position and Linkset.Orientation requre rewrite to properly return
125 child position. LinksetConstraint acts like it's at taint time!! 106 child position. LinksetConstraint acts like it's at taint time!!
126Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) 107Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
@@ -132,9 +113,6 @@ Selecting and deselecting physical objects causes CPU processing time to jump
132Re-implement buoyancy as a separate force on the object rather than diddling gravity. 113Re-implement buoyancy as a separate force on the object rather than diddling gravity.
133 Register a pre-step event to add the force. 114 Register a pre-step event to add the force.
134More efficient memory usage when passing hull information from BSPrim to BulletSim 115More efficient memory usage when passing hull information from BSPrim to BulletSim
135Avatar movement motor check for zero or small movement. Somehow suppress small movements
136 when avatar has stopped and is just standing. Simple test for near zero has
137 the problem of preventing starting up (increase from zero) especially when falling.
138Physical and phantom will drop through the terrain 116Physical and phantom will drop through the terrain
139 117
140 118
@@ -168,6 +146,7 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint)
168 146
169MORE 147MORE
170====================================================== 148======================================================
149Compute avatar size and scale correctly. Now it is a bit off from the capsule size.
171Create tests for different interface components 150Create tests for different interface components
172 Have test objects/scripts measure themselves and turn color if correct/bad 151 Have test objects/scripts measure themselves and turn color if correct/bad
173 Test functions in SL and calibrate correctness there 152 Test functions in SL and calibrate correctness there
@@ -176,7 +155,6 @@ Do we need to do convex hulls all the time? Can complex meshes be left meshes?
176 There is some problem with meshes and collisions 155 There is some problem with meshes and collisions
177 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. 156 Hulls are not as detailed as meshes. Hulled vehicles insides are different shape.
178Debounce avatar contact so legs don't keep folding up when standing. 157Debounce avatar contact so legs don't keep folding up when standing.
179Implement LSL physics controls. Like STATUS_ROTATE_X.
180Add border extensions to terrain to help region crossings and objects leaving region. 158Add border extensions to terrain to help region crossings and objects leaving region.
181Use a different capsule shape for avatar when sitting 159Use a different capsule shape for avatar when sitting
182 LL uses a pyrimidal shape scaled by the avatar's bounding box 160 LL uses a pyrimidal shape scaled by the avatar's bounding box
@@ -209,8 +187,6 @@ Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale
209 187
210INTERNAL IMPROVEMENT/CLEANUP 188INTERNAL IMPROVEMENT/CLEANUP
211================================================= 189=================================================
212Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
213 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
214Create the physical wrapper classes (BulletBody, BulletShape) by methods on 190Create the physical wrapper classes (BulletBody, BulletShape) by methods on
215 BSAPITemplate and make their actual implementation Bullet engine specific. 191 BSAPITemplate and make their actual implementation Bullet engine specific.
216 For the short term, just call the existing functions in ShapeCollection. 192 For the short term, just call the existing functions in ShapeCollection.
@@ -344,3 +320,60 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
344 Verify that angular motion specified around Z moves in the vehicle coordinates. 320 Verify that angular motion specified around Z moves in the vehicle coordinates.
345 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. 321 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
346Nebadon vehicles turning funny in arena (DONE) 322Nebadon vehicles turning funny in arena (DONE)
323Lock axis (DONE 20130401)
324Terrain detail: double terrain mesh detail (DONE)
325Use the HACD convex hull routine in Bullet rather than the C# version.
326 Speed up hullifying large meshes. (DONE)
327Vehicle ride, get up, ride again. Second time vehicle does not act correctly.
328 Have to rez new vehicle and delete the old to fix situation.
329 (DONE 20130520: normalize rotations)
330Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
331 position state where it will not settle onto ground properly, etc
332 (DONE 20130520: normalize rotations)
333Two of Nebadon vehicles in a sim max the CPU. This is new.
334 (DONE 20130520: two problems: if asset failed to mesh, constantly refetched
335 asset; vehicle was sending too many messages to all linkset members)
336Add material densities to the material types. (WILL NOT BE DONE: not how it is done)
337Avatars walking up stairs (DONE)
338Avatar movement
339 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
340 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
341 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
342After getting off a vehicle, the root prim is phantom (can be walked through)
343 Need to force a position update for the root prim after compound shape destruction
344 (DONE)
345Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
346 Regular triangle meshes don't do physical collisions.
347 (DONE: discovered GImpact is VERY CPU intensive)
348Script changing rotation of child prim while vehicle moving (eg turning wheel) causes
349 the wheel to appear to jump back. Looks like sending position from previous update.
350 (DONE: redo of compound linksets fixed problem)
351Refarb compound linkset creation to create a pseudo-root for center-of-mass
352 Let children change their shape to physical indendently and just add shapes to compound
353 (DONE: redo of compound linkset fixed problem)
354Vehicle angular vertical attraction (DONE: vegaslon code)
355vehicle angular banking (DONE: vegaslon code)
356Vehicle angular deflection (DONE: vegaslon code)
357 Preferred orientation angular correction fix
358Vehicles (Move smoothly)
359For limitMotorUp, use raycast down to find if vehicle is in the air.
360 (WILL NOT BE DONE: gravity does the job well enough)
361BSPrim.Force should set a continious force on the prim. The force should be
362 applied each tick. Some limits?
363 (DONE: added physical actors. Implemented SetForce, SetTorque, ...)
364Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE)
365Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
366Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE)
367Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force)
368setForce should set a constant force. Different than AddImpulse. (DONE)
369Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok)
370Avatar movement motor check for zero or small movement. Somehow suppress small movements
371 when avatar has stopped and is just standing. Simple test for near zero has
372 the problem of preventing starting up (increase from zero) especially when falling.
373 (DONE: avatar movement actor knows if standing on stationary object and zeros motion)
374Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
375 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
376 (DONE)
377
378
379
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
index 02b03a8..d069178 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
index b040e21..48e74eb 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs
@@ -57,6 +57,8 @@ public class BasicVehicles : OpenSimTestCase
57 public void Init() 57 public void Init()
58 { 58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>(); 59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 engineParams.Add("VehicleEnableAngularVerticalAttraction", "true");
61 engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1");
60 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams); 62 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
61 63
62 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere(); 64 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
@@ -114,21 +116,25 @@ public class BasicVehicles : OpenSimTestCase
114 // Instead the appropriate values are set and calls are made just the parts of the 116 // Instead the appropriate values are set and calls are made just the parts of the
115 // controller we want to exercise. Stepping the physics engine then applies 117 // controller we want to exercise. Stepping the physics engine then applies
116 // the actions of that one feature. 118 // the actions of that one feature.
117 TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); 119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
118 TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); 120 if (vehicleActor != null)
119 TestVehicle.VehicleActor.enableAngularVerticalAttraction = true;
120
121 TestVehicle.IsPhysical = true;
122 PhysicsScene.ProcessTaints();
123
124 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
125 for (int ii = 0; ii < simSteps; ii++)
126 { 121 {
127 TestVehicle.VehicleActor.ForgetKnownVehicleProperties(); 122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
128 TestVehicle.VehicleActor.ComputeAngularVerticalAttraction(); 123 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
129 TestVehicle.VehicleActor.PushKnownChanged(); 124 // vehicleActor.enableAngularVerticalAttraction = true;
130 125
131 PhysicsScene.Simulate(simulationTimeStep); 126 TestVehicle.IsPhysical = true;
127 PhysicsScene.ProcessTaints();
128
129 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
130 for (int ii = 0; ii < simSteps; ii++)
131 {
132 vehicleActor.ForgetKnownVehicleProperties();
133 vehicleActor.ComputeAngularVerticalAttraction();
134 vehicleActor.PushKnownChanged();
135
136 PhysicsScene.Simulate(simulationTimeStep);
137 }
132 } 138 }
133 139
134 TestVehicle.IsPhysical = false; 140 TestVehicle.IsPhysical = false;
diff --git a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
index f611b9a..b8cf624 100644
--- a/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
32// You can specify all the values or you can default the Build and Revision Numbers 32// You can specify all the values or you can default the Build and Revision Numbers
33// by using the '*' as shown below: 33// by using the '*' as shown below:
34// [assembly: AssemblyVersion("1.0.*")] 34// [assembly: AssemblyVersion("1.0.*")]
35[assembly: AssemblyVersion("0.7.6.*")] 35[assembly: AssemblyVersion("0.8.0.*")]
36 36
diff --git a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
index 5da3956..10e850e 100644
--- a/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/Manager/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.6.*")] 58[assembly : AssemblyVersion("0.8.0.*")]
diff --git a/OpenSim/Region/Physics/Manager/PhysicsActor.cs b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
index 7cd364b..44bfd42 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsActor.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsActor.cs
@@ -415,6 +415,12 @@ namespace OpenSim.Region.Physics.Manager
415 public virtual PhysicsActor ParentActor { get { return this; } } 415 public virtual PhysicsActor ParentActor { get { return this; } }
416 416
417 417
418 // Extendable interface for new, physics engine specific operations
419 public virtual object Extension(string pFunct, params object[] pParams)
420 {
421 // A NOP of the physics engine does not implement this feature
422 return null;
423 }
418 } 424 }
419 425
420 public class NullPhysicsActor : PhysicsActor 426 public class NullPhysicsActor : PhysicsActor
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index 20a70b4..dd9bbc1 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -25,10 +25,13 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.Collections.Generic; 29using System.Collections.Generic;
29using System.Reflection; 30using System.Reflection;
31
30using log4net; 32using log4net;
31using Nini.Config; 33using Nini.Config;
34
32using OpenSim.Framework; 35using OpenSim.Framework;
33using OpenMetaverse; 36using OpenMetaverse;
34 37
@@ -386,5 +389,12 @@ namespace OpenSim.Region.Physics.Manager
386 { 389 {
387 return 0; 390 return 0;
388 } 391 }
392
393 // Extendable interface for new, physics engine specific operations
394 public virtual object Extension(string pFunct, params object[] pParams)
395 {
396 // A NOP if the extension thing is not implemented by the physics engine
397 return null;
398 }
389 } 399 }
390} 400}
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index d181b78..6938e55 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -40,7 +40,6 @@ using log4net;
40using Nini.Config; 40using Nini.Config;
41using System.Reflection; 41using System.Reflection;
42using System.IO; 42using System.IO;
43using ComponentAce.Compression.Libs.zlib;
44 43
45namespace OpenSim.Region.Physics.Meshing 44namespace OpenSim.Region.Physics.Meshing
46{ 45{
@@ -64,6 +63,7 @@ namespace OpenSim.Region.Physics.Meshing
64 public class Meshmerizer : IMesher 63 public class Meshmerizer : IMesher
65 { 64 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 65 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
66 private static string LogHeader = "[MESH]";
67 67
68 // Setting baseDir to a path will enable the dumping of raw files 68 // Setting baseDir to a path will enable the dumping of raw files
69 // raw files can be imported by blender so a visual inspection of the results can be done 69 // raw files can be imported by blender so a visual inspection of the results can be done
@@ -72,6 +72,8 @@ namespace OpenSim.Region.Physics.Meshing
72#else 72#else
73 private const string baseDir = null; //"rawFiles"; 73 private const string baseDir = null; //"rawFiles";
74#endif 74#endif
75 // If 'true', lots of DEBUG logging of asset parsing details
76 private bool debugDetail = false;
75 77
76 private bool cacheSculptMaps = true; 78 private bool cacheSculptMaps = true;
77 private string decodedSculptMapPath = null; 79 private string decodedSculptMapPath = null;
@@ -79,6 +81,9 @@ namespace OpenSim.Region.Physics.Meshing
79 81
80 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh 82 private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh
81 83
84 private List<List<Vector3>> mConvexHulls = null;
85 private List<Vector3> mBoundingHull = null;
86
82 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); 87 private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>();
83 88
84 public Meshmerizer(IConfigSource config) 89 public Meshmerizer(IConfigSource config)
@@ -88,8 +93,11 @@ namespace OpenSim.Region.Physics.Meshing
88 93
89 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); 94 decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache");
90 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); 95 cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps);
91 if(mesh_config != null) 96 if (mesh_config != null)
97 {
92 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); 98 useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh);
99 debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail);
100 }
93 101
94 try 102 try
95 { 103 {
@@ -319,6 +327,9 @@ namespace OpenSim.Region.Physics.Meshing
319 faces = new List<Face>(); 327 faces = new List<Face>();
320 OSD meshOsd = null; 328 OSD meshOsd = null;
321 329
330 mConvexHulls = null;
331 mBoundingHull = null;
332
322 if (primShape.SculptData.Length <= 0) 333 if (primShape.SculptData.Length <= 0)
323 { 334 {
324 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this 335 // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
@@ -355,9 +366,139 @@ namespace OpenSim.Region.Physics.Meshing
355 OSDMap physicsParms = null; 366 OSDMap physicsParms = null;
356 OSDMap map = (OSDMap)meshOsd; 367 OSDMap map = (OSDMap)meshOsd;
357 if (map.ContainsKey("physics_shape")) 368 if (map.ContainsKey("physics_shape"))
369 {
358 physicsParms = (OSDMap)map["physics_shape"]; // old asset format 370 physicsParms = (OSDMap)map["physics_shape"]; // old asset format
371 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName);
372 }
359 else if (map.ContainsKey("physics_mesh")) 373 else if (map.ContainsKey("physics_mesh"))
374 {
360 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format 375 physicsParms = (OSDMap)map["physics_mesh"]; // new asset format
376 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName);
377 }
378 else if (map.ContainsKey("medium_lod"))
379 {
380 physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh
381 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName);
382 }
383 else if (map.ContainsKey("high_lod"))
384 {
385 physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :)
386 if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName);
387 }
388
389 if (map.ContainsKey("physics_convex"))
390 { // pull this out also in case physics engine can use it
391 OSD convexBlockOsd = null;
392 try
393 {
394 OSDMap convexBlock = (OSDMap)map["physics_convex"];
395 {
396 int convexOffset = convexBlock["offset"].AsInteger() + (int)start;
397 int convexSize = convexBlock["size"].AsInteger();
398
399 byte[] convexBytes = new byte[convexSize];
400
401 System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize);
402
403 try
404 {
405 convexBlockOsd = DecompressOsd(convexBytes);
406 }
407 catch (Exception e)
408 {
409 m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e);
410 //return false;
411 }
412 }
413
414 if (convexBlockOsd != null && convexBlockOsd is OSDMap)
415 {
416 convexBlock = convexBlockOsd as OSDMap;
417
418 if (debugDetail)
419 {
420 string keys = LogHeader + " keys found in convexBlock: ";
421 foreach (KeyValuePair<string, OSD> kvp in convexBlock)
422 keys += "'" + kvp.Key + "' ";
423 m_log.Debug(keys);
424 }
425
426 Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f);
427 if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3();
428 Vector3 max = new Vector3(0.5f, 0.5f, 0.5f);
429 if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3();
430
431 List<Vector3> boundingHull = null;
432
433 if (convexBlock.ContainsKey("BoundingVerts"))
434 {
435 byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary();
436 boundingHull = new List<Vector3>();
437 for (int i = 0; i < boundingVertsBytes.Length; )
438 {
439 ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
440 ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
441 ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2;
442
443 Vector3 pos = new Vector3(
444 Utils.UInt16ToFloat(uX, min.X, max.X),
445 Utils.UInt16ToFloat(uY, min.Y, max.Y),
446 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
447 );
448
449 boundingHull.Add(pos);
450 }
451
452 mBoundingHull = boundingHull;
453 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count);
454 }
455
456 if (convexBlock.ContainsKey("HullList"))
457 {
458 byte[] hullList = convexBlock["HullList"].AsBinary();
459
460 byte[] posBytes = convexBlock["Positions"].AsBinary();
461
462 List<List<Vector3>> hulls = new List<List<Vector3>>();
463 int posNdx = 0;
464
465 foreach (byte cnt in hullList)
466 {
467 int count = cnt == 0 ? 256 : cnt;
468 List<Vector3> hull = new List<Vector3>();
469
470 for (int i = 0; i < count; i++)
471 {
472 ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
473 ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
474 ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2;
475
476 Vector3 pos = new Vector3(
477 Utils.UInt16ToFloat(uX, min.X, max.X),
478 Utils.UInt16ToFloat(uY, min.Y, max.Y),
479 Utils.UInt16ToFloat(uZ, min.Z, max.Z)
480 );
481
482 hull.Add(pos);
483 }
484
485 hulls.Add(hull);
486 }
487
488 mConvexHulls = hulls;
489 if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count);
490 }
491 else
492 {
493 if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName);
494 }
495 }
496 }
497 catch (Exception e)
498 {
499 m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e);
500 }
501 }
361 502
362 if (physicsParms == null) 503 if (physicsParms == null)
363 { 504 {
@@ -374,34 +515,14 @@ namespace OpenSim.Region.Physics.Meshing
374 OSD decodedMeshOsd = new OSD(); 515 OSD decodedMeshOsd = new OSD();
375 byte[] meshBytes = new byte[physSize]; 516 byte[] meshBytes = new byte[physSize];
376 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); 517 System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize);
377// byte[] decompressed = new byte[physSize * 5]; 518 // byte[] decompressed = new byte[physSize * 5];
378 try 519 try
379 { 520 {
380 using (MemoryStream inMs = new MemoryStream(meshBytes)) 521 decodedMeshOsd = DecompressOsd(meshBytes);
381 {
382 using (MemoryStream outMs = new MemoryStream())
383 {
384 using (ZOutputStream zOut = new ZOutputStream(outMs))
385 {
386 byte[] readBuffer = new byte[2048];
387 int readLen = 0;
388 while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0)
389 {
390 zOut.Write(readBuffer, 0, readLen);
391 }
392 zOut.Flush();
393 outMs.Seek(0, SeekOrigin.Begin);
394
395 byte[] decompressedBuf = outMs.GetBuffer();
396
397 decodedMeshOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
398 }
399 }
400 }
401 } 522 }
402 catch (Exception e) 523 catch (Exception e)
403 { 524 {
404 m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); 525 m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e);
405 return false; 526 return false;
406 } 527 }
407 528
@@ -410,7 +531,7 @@ namespace OpenSim.Region.Physics.Meshing
410 // physics_shape is an array of OSDMaps, one for each submesh 531 // physics_shape is an array of OSDMaps, one for each submesh
411 if (decodedMeshOsd is OSDArray) 532 if (decodedMeshOsd is OSDArray)
412 { 533 {
413// Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); 534 // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd));
414 535
415 decodedMeshOsdArray = (OSDArray)decodedMeshOsd; 536 decodedMeshOsdArray = (OSDArray)decodedMeshOsd;
416 foreach (OSD subMeshOsd in decodedMeshOsdArray) 537 foreach (OSD subMeshOsd in decodedMeshOsdArray)
@@ -418,6 +539,9 @@ namespace OpenSim.Region.Physics.Meshing
418 if (subMeshOsd is OSDMap) 539 if (subMeshOsd is OSDMap)
419 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); 540 AddSubMesh(subMeshOsd as OSDMap, size, coords, faces);
420 } 541 }
542 if (debugDetail)
543 m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}",
544 LogHeader, primName, physOffset, physSize, coords.Count, faces.Count);
421 } 545 }
422 } 546 }
423 547
@@ -425,6 +549,42 @@ namespace OpenSim.Region.Physics.Meshing
425 } 549 }
426 550
427 /// <summary> 551 /// <summary>
552 /// decompresses a gzipped OSD object
553 /// </summary>
554 /// <param name="decodedOsd"></param> the OSD object
555 /// <param name="meshBytes"></param>
556 /// <returns></returns>
557 private static OSD DecompressOsd(byte[] meshBytes)
558 {
559 OSD decodedOsd = null;
560
561 using (MemoryStream inMs = new MemoryStream(meshBytes))
562 {
563 using (MemoryStream outMs = new MemoryStream())
564 {
565 using (DeflateStream decompressionStream = new DeflateStream(inMs, CompressionMode.Decompress))
566 {
567 byte[] readBuffer = new byte[2048];
568 inMs.Read(readBuffer, 0, 2); // skip first 2 bytes in header
569 int readLen = 0;
570
571 while ((readLen = decompressionStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
572 outMs.Write(readBuffer, 0, readLen);
573
574 outMs.Flush();
575
576 outMs.Seek(0, SeekOrigin.Begin);
577
578 byte[] decompressedBuf = outMs.GetBuffer();
579
580 decodedOsd = OSDParser.DeserializeLLSDBinary(decompressedBuf);
581 }
582 }
583 }
584 return decodedOsd;
585 }
586
587 /// <summary>
428 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim. 588 /// Generate the co-ords and faces necessary to construct a mesh from the sculpt data the accompanies a prim.
429 /// </summary> 589 /// </summary>
430 /// <param name="primName"></param> 590 /// <param name="primName"></param>
@@ -469,10 +629,11 @@ namespace OpenSim.Region.Physics.Meshing
469 629
470 try 630 try
471 { 631 {
472 OpenMetaverse.Imaging.ManagedImage unusedData; 632 OpenMetaverse.Imaging.ManagedImage managedImage;
473 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out unusedData, out idata); 633
634 OpenMetaverse.Imaging.OpenJPEG.DecodeToImage(primShape.SculptData, out managedImage);
474 635
475 if (idata == null) 636 if (managedImage == null)
476 { 637 {
477 // In some cases it seems that the decode can return a null bitmap without throwing 638 // In some cases it seems that the decode can return a null bitmap without throwing
478 // an exception 639 // an exception
@@ -481,9 +642,12 @@ namespace OpenSim.Region.Physics.Meshing
481 return false; 642 return false;
482 } 643 }
483 644
484 unusedData = null; 645 if ((managedImage.Channels & OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha) != 0)
646 managedImage.ConvertChannels(managedImage.Channels & ~OpenMetaverse.Imaging.ManagedImage.ImageChannels.Alpha);
485 647
486 //idata = CSJ2K.J2kImage.FromBytes(primShape.SculptData); 648 Bitmap imgData = OpenMetaverse.Imaging.LoadTGAClass.LoadTGA(new MemoryStream(managedImage.ExportTGA()));
649 idata = (Image)imgData;
650 managedImage = null;
487 651
488 if (cacheSculptMaps) 652 if (cacheSculptMaps)
489 { 653 {
@@ -700,6 +864,45 @@ namespace OpenSim.Region.Physics.Meshing
700 return true; 864 return true;
701 } 865 }
702 866
867 /// <summary>
868 /// temporary prototype code - please do not use until the interface has been finalized!
869 /// </summary>
870 /// <param name="size">value to scale the hull points by</param>
871 /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns>
872 public List<Vector3> GetBoundingHull(Vector3 size)
873 {
874 if (mBoundingHull == null)
875 return null;
876
877 List<Vector3> verts = new List<Vector3>();
878 foreach (var vert in mBoundingHull)
879 verts.Add(vert * size);
880
881 return verts;
882 }
883
884 /// <summary>
885 /// temporary prototype code - please do not use until the interface has been finalized!
886 /// </summary>
887 /// <param name="size">value to scale the hull points by</param>
888 /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns>
889 public List<List<Vector3>> GetConvexHulls(Vector3 size)
890 {
891 if (mConvexHulls == null)
892 return null;
893
894 List<List<Vector3>> hulls = new List<List<Vector3>>();
895 foreach (var hull in mConvexHulls)
896 {
897 List<Vector3> verts = new List<Vector3>();
898 foreach (var vert in hull)
899 verts.Add(vert * size);
900 hulls.Add(verts);
901 }
902
903 return hulls;
904 }
905
703 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) 906 public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod)
704 { 907 {
705 return CreateMesh(primName, primShape, size, lod, false, true); 908 return CreateMesh(primName, primShape, size, lod, false, true);
diff --git a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
index 3de061a..8542753 100644
--- a/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/Meshing/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.6.*")] 32[assembly: AssemblyVersion("0.8.0.*")]
33 33
diff --git a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
index f477ed1..288cab5 100644
--- a/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/OdePlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.6.*")] 58[assembly : AssemblyVersion("0.8.0.*")]
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index d09aa62..b4b7e7f 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -108,7 +108,6 @@ namespace OpenSim.Region.Physics.OdePlugin
108 private Vector3 m_taintAngularLock = Vector3.One; 108 private Vector3 m_taintAngularLock = Vector3.One;
109 private IntPtr Amotor = IntPtr.Zero; 109 private IntPtr Amotor = IntPtr.Zero;
110 110
111 private object m_assetsLock = new object();
112 private bool m_assetFailed = false; 111 private bool m_assetFailed = false;
113 112
114 private Vector3 m_PIDTarget; 113 private Vector3 m_PIDTarget;
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
index 07663b3..7e652fc 100644
--- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
+++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs
@@ -46,7 +46,7 @@ namespace OpenSim.Region.Physics.OdePlugin
46 /// </summary> 46 /// </summary>
47 public class OdePlugin : IPhysicsPlugin 47 public class OdePlugin : IPhysicsPlugin
48 { 48 {
49 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 49// private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 private OdeScene m_scene; 51 private OdeScene m_scene;
52 52
diff --git a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
index 4289863..83be103 100644
--- a/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
+++ b/OpenSim/Region/Physics/POSPlugin/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.6.*")] 58[assembly : AssemblyVersion("0.8.0.*")]