diff options
Diffstat (limited to 'OpenSim/Region/Physics')
38 files changed, 5561 insertions, 3251 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 77ea3ed..12a0c17 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs | |||
@@ -75,11 +75,11 @@ private sealed class BulletBodyUnman : BulletBody | |||
75 | private sealed class BulletShapeUnman : BulletShape | 75 | private 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,23 +251,52 @@ public override BulletShape CreateMeshShape(BulletWorld world, | |||
251 | BSPhysicsShapeType.SHAPE_MESH); | 251 | BSPhysicsShapeType.SHAPE_MESH); |
252 | } | 252 | } |
253 | 253 | ||
254 | public 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 | |||
254 | public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) | 264 | public 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 | ||
262 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 272 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
263 | { | 273 | { |
264 | BulletWorldUnman worldu = world as BulletWorldUnman; | 274 | BulletWorldUnman worldu = world as BulletWorldUnman; |
265 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | 275 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; |
266 | return new BulletShapeUnman( | 276 | return new BulletShapeUnman( |
267 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | 277 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), |
268 | BSPhysicsShapeType.SHAPE_HULL); | 278 | BSPhysicsShapeType.SHAPE_HULL); |
269 | } | 279 | } |
270 | 280 | ||
281 | public 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 | |||
290 | public 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 | |||
271 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | 300 | public 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 | ||
362 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | 391 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) |
@@ -1407,11 +1436,24 @@ public static extern IntPtr CreateMeshShape2(IntPtr world, | |||
1407 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | 1436 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); |
1408 | 1437 | ||
1409 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1438 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1439 | public static extern IntPtr CreateGImpactShape2(IntPtr world, | ||
1440 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1441 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1442 | |||
1443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1410 | public static extern IntPtr CreateHullShape2(IntPtr world, | 1444 | public static extern IntPtr CreateHullShape2(IntPtr world, |
1411 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | 1445 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); |
1412 | 1446 | ||
1413 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1447 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1414 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | 1448 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); |
1449 | |||
1450 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1451 | public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1452 | |||
1453 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1454 | public static extern IntPtr CreateConvexHullShape2(IntPtr world, | ||
1455 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1456 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1415 | 1457 | ||
1416 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1458 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1417 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | 1459 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); |
@@ -1476,7 +1518,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | |||
1476 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | 1518 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); |
1477 | 1519 | ||
1478 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1520 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1479 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | 1521 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, |
1480 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | 1522 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, |
1481 | float scaleFactor, float collisionMargin); | 1523 | float scaleFactor, float collisionMargin); |
1482 | 1524 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 6fc10e9..2a820be 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | |||
@@ -81,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody | |||
81 | private sealed class BulletShapeXNA : BulletShape | 81 | private 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> |
@@ -174,7 +174,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; | 175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; |
176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); | 176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); |
177 | 177 | ||
178 | return true; | 178 | return true; |
179 | 179 | ||
180 | } | 180 | } |
@@ -300,7 +300,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { | 300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { |
301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
302 | return world.GetForceUpdateAllAabbs(); | 302 | return world.GetForceUpdateAllAabbs(); |
303 | 303 | ||
304 | } | 304 | } |
305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) | 305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) |
306 | { | 306 | { |
@@ -404,7 +404,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | 404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); |
405 | mat._origin = vposition; | 405 | mat._origin = vposition; |
406 | collisionObject.SetWorldTransform(mat); | 406 | collisionObject.SetWorldTransform(mat); |
407 | 407 | ||
408 | } | 408 | } |
409 | 409 | ||
410 | public override Vector3 GetPosition(BulletBody pCollisionObject) | 410 | public override Vector3 GetPosition(BulletBody pCollisionObject) |
@@ -457,7 +457,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
457 | { | 457 | { |
458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
459 | collisionObject.Activate(pforceactivation); | 459 | collisionObject.Activate(pforceactivation); |
460 | 460 | ||
461 | } | 461 | } |
462 | 462 | ||
463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) | 463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) |
@@ -486,7 +486,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
486 | { | 486 | { |
487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
488 | return collisionObject.GetCcdSweptSphereRadius(); | 488 | return collisionObject.GetCcdSweptSphereRadius(); |
489 | 489 | ||
490 | } | 490 | } |
491 | 491 | ||
492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) | 492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) |
@@ -559,8 +559,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
559 | } | 559 | } |
560 | 560 | ||
561 | 561 | ||
562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | 562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | 563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
565 | 565 | ||
566 | { | 566 | { |
@@ -604,7 +604,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
604 | } | 604 | } |
605 | 605 | ||
606 | /// <summary> | 606 | /// <summary> |
607 | /// | 607 | /// |
608 | /// </summary> | 608 | /// </summary> |
609 | /// <param name="pWorld"></param> | 609 | /// <param name="pWorld"></param> |
610 | /// <param name="pBody1"></param> | 610 | /// <param name="pBody1"></param> |
@@ -824,7 +824,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
824 | { | 824 | { |
825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | 825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
826 | float angularDamping = body.GetAngularDamping(); | 826 | float angularDamping = body.GetAngularDamping(); |
827 | body.SetDamping(lin_damping, angularDamping); | 827 | body.SetDamping(lin_damping, angularDamping); |
828 | } | 828 | } |
829 | 829 | ||
830 | public override float GetLinearDamping(BulletBody pBody) | 830 | public override float GetLinearDamping(BulletBody pBody) |
@@ -907,7 +907,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
907 | RigidBody bo = co as RigidBody; | 907 | RigidBody bo = co as RigidBody; |
908 | if (bo == null) | 908 | if (bo == null) |
909 | { | 909 | { |
910 | 910 | ||
911 | if (world.IsInWorld(co)) | 911 | if (world.IsInWorld(co)) |
912 | { | 912 | { |
913 | world.RemoveCollisionObject(co); | 913 | world.RemoveCollisionObject(co); |
@@ -915,7 +915,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
915 | } | 915 | } |
916 | else | 916 | else |
917 | { | 917 | { |
918 | 918 | ||
919 | if (world.IsInWorld(bo)) | 919 | if (world.IsInWorld(bo)) |
920 | { | 920 | { |
921 | world.RemoveRigidBody(bo); | 921 | world.RemoveRigidBody(bo); |
@@ -947,7 +947,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
947 | 947 | ||
948 | // TODO: Turn this from a reference copy to a Value Copy. | 948 | // TODO: Turn this from a reference copy to a Value Copy. |
949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); | 949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); |
950 | 950 | ||
951 | return shape2; | 951 | return shape2; |
952 | } | 952 | } |
953 | 953 | ||
@@ -957,7 +957,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
957 | return false; | 957 | return false; |
958 | } | 958 | } |
959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
960 | 960 | ||
961 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | 961 | public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) |
962 | { | 962 | { |
963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; | 963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; |
@@ -993,11 +993,11 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
993 | m_startWorldTransform = IndexedMatrix.Identity; | 993 | m_startWorldTransform = IndexedMatrix.Identity; |
994 | */ | 994 | */ |
995 | body.SetUserPointer(pLocalID); | 995 | body.SetUserPointer(pLocalID); |
996 | 996 | ||
997 | return new BulletBodyXNA(pLocalID, body); | 997 | return new BulletBodyXNA(pLocalID, body); |
998 | } | 998 | } |
999 | 999 | ||
1000 | 1000 | ||
1001 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | 1001 | public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) |
1002 | { | 1002 | { |
1003 | 1003 | ||
@@ -1025,7 +1025,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) | 1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) |
1026 | { | 1026 | { |
1027 | 1027 | ||
1028 | /* TODO */ | 1028 | /* TODO */ |
1029 | return Vector3.Zero; | 1029 | return Vector3.Zero; |
1030 | } | 1030 | } |
1031 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } | 1031 | public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } |
@@ -1035,7 +1035,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1035 | { | 1035 | { |
1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | 1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
1037 | return collisionObject.IsStaticObject(); | 1037 | return collisionObject.IsStaticObject(); |
1038 | 1038 | ||
1039 | } | 1039 | } |
1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) | 1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) |
1041 | { | 1041 | { |
@@ -1098,10 +1098,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); | 1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); |
1099 | } | 1099 | } |
1100 | 1100 | ||
1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, | 1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, |
1102 | ConfigurationParameters[] o, | 1102 | ConfigurationParameters[] o, |
1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, | 1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, |
1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, | 1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, |
1105 | object mDebugLogCallbackHandle) | 1105 | object mDebugLogCallbackHandle) |
1106 | { | 1106 | { |
1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | 1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); |
@@ -1138,9 +1138,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; | 1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; |
1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; | 1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; |
1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; | 1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; |
1141 | 1141 | ||
1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; | 1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; |
1143 | 1143 | ||
1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | 1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; |
1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | 1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; |
1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | 1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; |
@@ -1160,7 +1160,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; | 1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; |
1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; | 1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; |
1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | 1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); |
1163 | 1163 | ||
1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | 1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); |
1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | 1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); |
1166 | 1166 | ||
@@ -1221,6 +1221,50 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1221 | //BSParam.TerrainImplementation = 0; | 1221 | //BSParam.TerrainImplementation = 0; |
1222 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | 1222 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); |
1223 | 1223 | ||
1224 | // Turn off Pooling since globals and pooling are bad for threading. | ||
1225 | BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); | ||
1226 | BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); | ||
1227 | BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); | ||
1228 | BulletGlobals.CastResultPool.SetPoolingEnabled(false); | ||
1229 | BulletGlobals.SphereShapePool.SetPoolingEnabled(false); | ||
1230 | BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); | ||
1231 | BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); | ||
1232 | BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); | ||
1233 | BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); | ||
1234 | BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); | ||
1235 | BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); | ||
1236 | BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); | ||
1237 | BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); | ||
1238 | BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); | ||
1239 | BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); | ||
1240 | BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); | ||
1241 | |||
1242 | BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1243 | BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1244 | BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1245 | BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); | ||
1246 | BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); | ||
1247 | BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1248 | BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1249 | BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1250 | BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); | ||
1251 | BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); | ||
1252 | BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); | ||
1253 | BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); | ||
1254 | BulletGlobals.GJKPool.SetPoolingEnabled(false); | ||
1255 | BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); | ||
1256 | BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); | ||
1257 | BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); | ||
1258 | BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); | ||
1259 | BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); | ||
1260 | BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); | ||
1261 | BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); | ||
1262 | BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); | ||
1263 | BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); | ||
1264 | BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); | ||
1265 | BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); | ||
1266 | BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); | ||
1267 | |||
1224 | return world; | 1268 | return world; |
1225 | } | 1269 | } |
1226 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | 1270 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL |
@@ -1263,7 +1307,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1263 | } | 1307 | } |
1264 | } | 1308 | } |
1265 | return ret; | 1309 | return ret; |
1266 | 1310 | ||
1267 | } | 1311 | } |
1268 | 1312 | ||
1269 | public override float GetAngularMotionDisc(BulletShape pShape) | 1313 | public override float GetAngularMotionDisc(BulletShape pShape) |
@@ -1353,10 +1397,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | 1397 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1354 | gObj.SetCollisionShape(shape); | 1398 | gObj.SetCollisionShape(shape); |
1355 | gObj.SetUserPointer(pLocalID); | 1399 | gObj.SetUserPointer(pLocalID); |
1356 | 1400 | ||
1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) | 1401 | if (specialCollisionObjects.ContainsKey(pLocalID)) |
1358 | specialCollisionObjects[pLocalID] = gObj; | 1402 | specialCollisionObjects[pLocalID] = gObj; |
1359 | else | 1403 | else |
1360 | specialCollisionObjects.Add(pLocalID, gObj); | 1404 | specialCollisionObjects.Add(pLocalID, gObj); |
1361 | 1405 | ||
1362 | // TODO: Add to Special CollisionObjects! | 1406 | // TODO: Add to Special CollisionObjects! |
@@ -1447,8 +1491,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); | 1491 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); |
1448 | } | 1492 | } |
1449 | 1493 | ||
1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | 1494 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { |
1451 | 1495 | ||
1452 | if (cShape == null) | 1496 | if (cShape == null) |
1453 | return null; | 1497 | return null; |
1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | 1498 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; |
@@ -1456,7 +1500,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | 1500 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); |
1457 | 1501 | ||
1458 | 1502 | ||
1459 | return retShape; | 1503 | return retShape; |
1460 | } | 1504 | } |
1461 | 1505 | ||
1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | 1506 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) |
@@ -1475,7 +1519,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1519 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
1476 | break; | 1520 | break; |
1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | 1521 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: |
1478 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1522 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1479 | break; | 1523 | break; |
1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | 1524 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: |
1481 | ret = BSPhysicsShapeType.SHAPE_HULL; | 1525 | ret = BSPhysicsShapeType.SHAPE_HULL; |
@@ -1503,7 +1547,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1503 | ret = BSPhysicsShapeType.SHAPE_CONE; | 1547 | ret = BSPhysicsShapeType.SHAPE_CONE; |
1504 | break; | 1548 | break; |
1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | 1549 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: |
1506 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1550 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1507 | break; | 1551 | break; |
1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | 1552 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: |
1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | 1553 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; |
@@ -1547,7 +1591,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1547 | break; | 1591 | break; |
1548 | ///Used for GIMPACT Trimesh integration | 1592 | ///Used for GIMPACT Trimesh integration |
1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | 1593 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: |
1550 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1594 | ret = BSPhysicsShapeType.SHAPE_GIMPACT; |
1551 | break; | 1595 | break; |
1552 | ///Multimaterial mesh | 1596 | ///Multimaterial mesh |
1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | 1597 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: |
@@ -1598,8 +1642,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 1642 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
1599 | } | 1643 | } |
1600 | 1644 | ||
1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | 1645 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | 1646 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 1647 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
1604 | 1648 | ||
1605 | { | 1649 | { |
@@ -1745,7 +1789,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1745 | { | 1789 | { |
1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 1790 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1747 | CompoundShape compoundshape = new CompoundShape(false); | 1791 | CompoundShape compoundshape = new CompoundShape(false); |
1748 | 1792 | ||
1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | 1793 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); |
1750 | int ii = 1; | 1794 | int ii = 1; |
1751 | 1795 | ||
@@ -1761,7 +1805,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1761 | int ender = ((ii + 4) + (vertexCount*3)); | 1805 | int ender = ((ii + 4) + (vertexCount*3)); |
1762 | for (int iii = ii + 4; iii < ender; iii+=3) | 1806 | for (int iii = ii + 4; iii < ender; iii+=3) |
1763 | { | 1807 | { |
1764 | 1808 | ||
1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | 1809 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); |
1766 | } | 1810 | } |
1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | 1811 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); |
@@ -1769,26 +1813,35 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1769 | compoundshape.AddChildShape(ref childTrans, convexShape); | 1813 | compoundshape.AddChildShape(ref childTrans, convexShape); |
1770 | ii += (vertexCount*3 + 4); | 1814 | ii += (vertexCount*3 + 4); |
1771 | } | 1815 | } |
1772 | 1816 | ||
1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | 1817 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); |
1774 | } | 1818 | } |
1775 | 1819 | ||
1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 1820 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
1777 | { | 1821 | { |
1778 | /* TODO */ return null; | 1822 | /* TODO */ return null; |
1823 | } | ||
1779 | 1824 | ||
1825 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
1826 | { | ||
1827 | /* TODO */ return null; | ||
1828 | } | ||
1829 | |||
1830 | public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1831 | { | ||
1832 | /* TODO */ return null; | ||
1780 | } | 1833 | } |
1781 | 1834 | ||
1782 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | 1835 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) |
1783 | { | 1836 | { |
1784 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | 1837 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); |
1785 | 1838 | ||
1786 | for (int iter = 0; iter < pVerticesCount; iter++) | 1839 | for (int iter = 0; iter < pVerticesCount; iter++) |
1787 | { | 1840 | { |
1788 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | 1841 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; |
1789 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | 1842 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; |
1790 | } | 1843 | } |
1791 | 1844 | ||
1792 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | 1845 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); |
1793 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | 1846 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); |
1794 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | 1847 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); |
@@ -1802,7 +1855,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1802 | mesh.m_vertexStride = 3; | 1855 | mesh.m_vertexStride = 3; |
1803 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1856 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1804 | mesh.m_triangleIndexStride = 3; | 1857 | mesh.m_triangleIndexStride = 3; |
1805 | 1858 | ||
1806 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1859 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1807 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1860 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1808 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | 1861 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); |
@@ -1811,9 +1864,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1811 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | 1864 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); |
1812 | 1865 | ||
1813 | } | 1866 | } |
1867 | public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1868 | { | ||
1869 | // TODO: | ||
1870 | return null; | ||
1871 | } | ||
1814 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | 1872 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) |
1815 | { | 1873 | { |
1816 | 1874 | ||
1817 | String fileName = "objTest3.raw"; | 1875 | String fileName = "objTest3.raw"; |
1818 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | 1876 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); |
1819 | StreamWriter sw = new StreamWriter(completePath); | 1877 | StreamWriter sw = new StreamWriter(completePath); |
@@ -1839,7 +1897,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1839 | string s = vertices[indices[i * 3]].ToString("0.0000"); | 1897 | string s = vertices[indices[i * 3]].ToString("0.0000"); |
1840 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | 1898 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); |
1841 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | 1899 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); |
1842 | 1900 | ||
1843 | sw.Write(s + "\n"); | 1901 | sw.Write(s + "\n"); |
1844 | } | 1902 | } |
1845 | 1903 | ||
@@ -1861,7 +1919,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1861 | mesh.m_vertexStride = 3; | 1919 | mesh.m_vertexStride = 3; |
1862 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1920 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1863 | mesh.m_triangleIndexStride = 3; | 1921 | mesh.m_triangleIndexStride = 3; |
1864 | 1922 | ||
1865 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1923 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1866 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1924 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1867 | 1925 | ||
@@ -1892,7 +1950,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1892 | sw.Close(); | 1950 | sw.Close(); |
1893 | } | 1951 | } |
1894 | 1952 | ||
1895 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 1953 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
1896 | float scaleFactor, float collisionMargin) | 1954 | float scaleFactor, float collisionMargin) |
1897 | { | 1955 | { |
1898 | const int upAxis = 2; | 1956 | const int upAxis = 2; |
@@ -1900,7 +1958,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1900 | heightMap, scaleFactor, | 1958 | heightMap, scaleFactor, |
1901 | minHeight, maxHeight, upAxis, | 1959 | minHeight, maxHeight, upAxis, |
1902 | false); | 1960 | false); |
1903 | terrainShape.SetMargin(collisionMargin + 0.5f); | 1961 | terrainShape.SetMargin(collisionMargin); |
1904 | terrainShape.SetUseDiamondSubdivision(true); | 1962 | terrainShape.SetUseDiamondSubdivision(true); |
1905 | terrainShape.SetUserPointer(id); | 1963 | terrainShape.SetUserPointer(id); |
1906 | return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); | 1964 | return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); |
@@ -1934,14 +1992,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1934 | /* TODO */ | 1992 | /* TODO */ |
1935 | updatedEntityCount = 0; | 1993 | updatedEntityCount = 0; |
1936 | collidersCount = 0; | 1994 | collidersCount = 0; |
1937 | 1995 | ||
1938 | 1996 | ||
1939 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | 1997 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); |
1940 | 1998 | ||
1941 | return ret; | 1999 | return ret; |
1942 | } | 2000 | } |
1943 | 2001 | ||
1944 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | 2002 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, |
1945 | out int updatedEntityCount, out EntityProperties[] updatedEntities, | 2003 | out int updatedEntityCount, out EntityProperties[] updatedEntities, |
1946 | out int collidersCount, out CollisionDesc[] colliders) | 2004 | out int collidersCount, out CollisionDesc[] colliders) |
1947 | { | 2005 | { |
@@ -1950,24 +2008,24 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1950 | return epic; | 2008 | return epic; |
1951 | } | 2009 | } |
1952 | 2010 | ||
1953 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, | 2011 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, |
1954 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) | 2012 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) |
1955 | { | 2013 | { |
1956 | int numSimSteps = 0; | 2014 | int numSimSteps = 0; |
1957 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | 2015 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); |
1958 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | 2016 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); |
1959 | LastEntityProperty=0; | 2017 | LastEntityProperty=0; |
1960 | 2018 | ||
1961 | 2019 | ||
1962 | 2020 | ||
1963 | 2021 | ||
1964 | 2022 | ||
1965 | 2023 | ||
1966 | LastCollisionDesc=0; | 2024 | LastCollisionDesc=0; |
1967 | 2025 | ||
1968 | updatedEntityCount = 0; | 2026 | updatedEntityCount = 0; |
1969 | collidersCount = 0; | 2027 | collidersCount = 0; |
1970 | 2028 | ||
1971 | 2029 | ||
1972 | if (pWorld is BulletWorldXNA) | 2030 | if (pWorld is BulletWorldXNA) |
1973 | { | 2031 | { |
@@ -2024,7 +2082,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2024 | 2082 | ||
2025 | collidersCount = LastCollisionDesc; | 2083 | collidersCount = LastCollisionDesc; |
2026 | colliders = UpdatedCollisions; | 2084 | colliders = UpdatedCollisions; |
2027 | 2085 | ||
2028 | 2086 | ||
2029 | } | 2087 | } |
2030 | else | 2088 | else |
@@ -2032,15 +2090,15 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2032 | //if (updatedEntities is null) | 2090 | //if (updatedEntities is null) |
2033 | //updatedEntities = new List<BulletXNA.EntityProperties>(); | 2091 | //updatedEntities = new List<BulletXNA.EntityProperties>(); |
2034 | //updatedEntityCount = 0; | 2092 | //updatedEntityCount = 0; |
2035 | 2093 | ||
2036 | 2094 | ||
2037 | //collidersCount = 0; | 2095 | //collidersCount = 0; |
2038 | 2096 | ||
2039 | updatedEntities = new EntityProperties[0]; | 2097 | updatedEntities = new EntityProperties[0]; |
2040 | 2098 | ||
2041 | 2099 | ||
2042 | colliders = new CollisionDesc[0]; | 2100 | colliders = new CollisionDesc[0]; |
2043 | 2101 | ||
2044 | } | 2102 | } |
2045 | return numSimSteps; | 2103 | return numSimSteps; |
2046 | } | 2104 | } |
@@ -2048,7 +2106,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2048 | { | 2106 | { |
2049 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | 2107 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); |
2050 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | 2108 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); |
2051 | 2109 | ||
2052 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | 2110 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; |
2053 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | 2111 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); |
2054 | BroadphasePair collisionPair; | 2112 | BroadphasePair collisionPair; |
@@ -2060,7 +2118,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2060 | ManifoldPoint pt; | 2118 | ManifoldPoint pt; |
2061 | 2119 | ||
2062 | int numPairs = pairs.Count; | 2120 | int numPairs = pairs.Count; |
2063 | 2121 | ||
2064 | for (int i = 0; i < numPairs; i++) | 2122 | for (int i = 0; i < numPairs; i++) |
2065 | { | 2123 | { |
2066 | manifoldArray.Clear(); | 2124 | manifoldArray.Clear(); |
@@ -2069,7 +2127,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2069 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | 2127 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); |
2070 | if (collisionPair == null) | 2128 | if (collisionPair == null) |
2071 | continue; | 2129 | continue; |
2072 | 2130 | ||
2073 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | 2131 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); |
2074 | for (int j = 0; j < manifoldArray.Count; j++) | 2132 | for (int j = 0; j < manifoldArray.Count; j++) |
2075 | { | 2133 | { |
@@ -2092,7 +2150,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2092 | } | 2150 | } |
2093 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | 2151 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) |
2094 | { | 2152 | { |
2095 | 2153 | ||
2096 | IndexedVector3 contactNormal = norm; | 2154 | IndexedVector3 contactNormal = norm; |
2097 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | 2155 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && |
2098 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | 2156 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) |
@@ -2162,11 +2220,11 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2162 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | 2220 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) |
2163 | { | 2221 | { |
2164 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; | 2222 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; |
2165 | 2223 | ||
2166 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | 2224 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); |
2167 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | 2225 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); |
2168 | using ( | 2226 | using ( |
2169 | ClosestNotMeRayResultCallback rayCallback = | 2227 | ClosestNotMeRayResultCallback rayCallback = |
2170 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | 2228 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) |
2171 | ) | 2229 | ) |
2172 | { | 2230 | { |
@@ -2182,9 +2240,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2182 | return false; | 2240 | return false; |
2183 | } | 2241 | } |
2184 | } | 2242 | } |
2185 | |||
2186 | 2243 | ||
2187 | 2244 | ||
2245 | |||
2188 | 2246 | ||
2189 | public class SimMotionState : DefaultMotionState | 2247 | public class SimMotionState : DefaultMotionState |
2190 | { | 2248 | { |
@@ -2277,12 +2335,12 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2277 | m_lastProperties = m_properties; | 2335 | m_lastProperties = m_properties; |
2278 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | 2336 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) |
2279 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | 2337 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); |
2280 | 2338 | ||
2281 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | 2339 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; |
2282 | } | 2340 | } |
2283 | 2341 | ||
2284 | 2342 | ||
2285 | 2343 | ||
2286 | 2344 | ||
2287 | } | 2345 | } |
2288 | public override void SetRigidBody(RigidBody body) | 2346 | public override void SetRigidBody(RigidBody body) |
@@ -2305,7 +2363,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2305 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | 2363 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && |
2306 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | 2364 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); |
2307 | } | 2365 | } |
2308 | 2366 | ||
2309 | } | 2367 | } |
2310 | } | 2368 | } |
2311 | 2369 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs new file mode 100755 index 0000000..68bc1b9 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | |||
@@ -0,0 +1,409 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public 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, "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 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
132 | SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); | ||
133 | |||
134 | m_physicsScene.BeforeStep += Mover; | ||
135 | m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; | ||
136 | |||
137 | m_walkingUpStairs = 0; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | private void DeactivateAvatarMove() | ||
142 | { | ||
143 | if (m_velocityMotor != null) | ||
144 | { | ||
145 | m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; | ||
146 | m_physicsScene.BeforeStep -= Mover; | ||
147 | m_velocityMotor = null; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
152 | private void Mover(float timeStep) | ||
153 | { | ||
154 | // Don't do movement while the object is selected. | ||
155 | if (!isActive) | ||
156 | return; | ||
157 | |||
158 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
159 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
160 | |||
161 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
162 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
163 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
164 | // component is not fooled with (thus allowing gravity to do its thing). | ||
165 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
166 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
167 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
168 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
169 | // errors can creap in and the avatar will slowly float off in some direction. | ||
170 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
171 | // from real pushing. | ||
172 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
173 | |||
174 | m_velocityMotor.Step(timeStep); | ||
175 | m_controllingPrim.IsStationary = false; | ||
176 | |||
177 | // If we're not supposed to be moving, make sure things are zero. | ||
178 | if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
179 | { | ||
180 | // The avatar shouldn't be moving | ||
181 | m_velocityMotor.Zero(); | ||
182 | |||
183 | if (m_controllingPrim.IsColliding) | ||
184 | { | ||
185 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
186 | if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) | ||
187 | { | ||
188 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); | ||
189 | m_controllingPrim.IsStationary = true; | ||
190 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
191 | } | ||
192 | |||
193 | // Standing has more friction on the ground | ||
194 | if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) | ||
195 | { | ||
196 | m_controllingPrim.Friction = BSParam.AvatarStandingFriction; | ||
197 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
198 | } | ||
199 | } | ||
200 | else | ||
201 | { | ||
202 | if (m_controllingPrim.Flying) | ||
203 | { | ||
204 | // Flying and not colliding and velocity nearly zero. | ||
205 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", | ||
210 | m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | // Supposed to be moving. | ||
215 | OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; | ||
216 | |||
217 | if (m_controllingPrim.Friction != BSParam.AvatarFriction) | ||
218 | { | ||
219 | // Probably starting to walk. Set friction to moving friction. | ||
220 | m_controllingPrim.Friction = BSParam.AvatarFriction; | ||
221 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
222 | } | ||
223 | |||
224 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
225 | { | ||
226 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
227 | } | ||
228 | |||
229 | |||
230 | // Colliding and not flying with an upward force. The avatar must be trying to jump. | ||
231 | if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0) | ||
232 | { | ||
233 | // We allow the upward force to happen for this many frames. | ||
234 | m_jumpFrames = BSParam.AvatarJumpFrames; | ||
235 | m_jumpVelocity = stepVelocity.Z; | ||
236 | } | ||
237 | |||
238 | // The case where the avatar is not colliding and is not flying is special. | ||
239 | // The avatar is either falling or jumping and the user can be applying force to the avatar | ||
240 | // (force in some direction or force up or down). | ||
241 | // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity. | ||
242 | // If the user is trying to apply upward force but we're not colliding, assume the avatar | ||
243 | // is trying to jump and don't apply the upward force if not touching the ground any more. | ||
244 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
245 | { | ||
246 | // If upward velocity is being applied, this must be a jump and only allow that to go on so long | ||
247 | if (m_jumpFrames > 0) | ||
248 | { | ||
249 | // Since not touching the ground, only apply upward force for so long. | ||
250 | m_jumpFrames--; | ||
251 | stepVelocity.Z = m_jumpVelocity; | ||
252 | } | ||
253 | else | ||
254 | { | ||
255 | // Since we're not affected by anything, whatever vertical motion the avatar has, continue that. | ||
256 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
257 | } | ||
258 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
259 | } | ||
260 | |||
261 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
262 | OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; | ||
263 | |||
264 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
265 | moveForce += WalkUpStairs(); | ||
266 | |||
267 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", | ||
268 | m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); | ||
269 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | // Called just as the property update is received from the physics engine. | ||
274 | // Do any mode necessary for avatar movement. | ||
275 | private void Process_OnPreUpdateProperty(ref EntityProperties entprop) | ||
276 | { | ||
277 | // Don't change position if standing on a stationary object. | ||
278 | if (m_controllingPrim.IsStationary) | ||
279 | { | ||
280 | entprop.Position = m_controllingPrim.RawPosition; | ||
281 | m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); | ||
282 | } | ||
283 | |||
284 | } | ||
285 | |||
286 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
287 | // avatar up so it can walk up and over the low objects. | ||
288 | private OMV.Vector3 WalkUpStairs() | ||
289 | { | ||
290 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
291 | |||
292 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", | ||
293 | m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, | ||
294 | m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); | ||
295 | |||
296 | // Check for stairs climbing if colliding, not flying and moving forward | ||
297 | if ( m_controllingPrim.IsColliding | ||
298 | && !m_controllingPrim.Flying | ||
299 | && m_controllingPrim.TargetVelocitySpeed > 0.1f ) | ||
300 | { | ||
301 | // The range near the character's feet where we will consider stairs | ||
302 | // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; | ||
303 | // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off | ||
304 | // from the height. Revisit size and this computation when height is scaled properly. | ||
305 | float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f; | ||
306 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
307 | |||
308 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. | ||
309 | // Find the highest 'good' collision. | ||
310 | OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; | ||
311 | foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) | ||
312 | { | ||
313 | // Don't care about collisions with the terrain | ||
314 | if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) | ||
315 | { | ||
316 | BSPhysObject collisionObject; | ||
317 | if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) | ||
318 | { | ||
319 | if (!collisionObject.IsVolumeDetect) | ||
320 | { | ||
321 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
322 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
323 | m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
324 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
325 | { | ||
326 | // This contact is within the 'near the feet' range. | ||
327 | // The normal should be our contact point to the object so it is pointing away | ||
328 | // thus the difference between our facing orientation and the normal should be small. | ||
329 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; | ||
330 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
331 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
332 | if (diff < BSParam.AvatarStepApproachFactor) | ||
333 | { | ||
334 | if (highestTouchPosition.Z < touchPosition.Z) | ||
335 | highestTouchPosition = touchPosition; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | m_walkingUpStairs = 0; | ||
343 | // If there is a good step sensing, move the avatar over the step. | ||
344 | if (highestTouchPosition != OMV.Vector3.Zero) | ||
345 | { | ||
346 | // Remember that we are going up stairs. This is needed because collisions | ||
347 | // will stop when we move up so this smoothes out that effect. | ||
348 | m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; | ||
349 | |||
350 | m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; | ||
351 | ret = ComputeStairCorrection(m_lastStepUp); | ||
352 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", | ||
353 | m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); | ||
354 | } | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | // If we used to be going up stairs but are not now, smooth the case where collision goes away while | ||
359 | // we are bouncing up the stairs. | ||
360 | if (m_walkingUpStairs > 0) | ||
361 | { | ||
362 | m_walkingUpStairs--; | ||
363 | ret = ComputeStairCorrection(m_lastStepUp); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | return ret; | ||
368 | } | ||
369 | |||
370 | private OMV.Vector3 ComputeStairCorrection(float stepUp) | ||
371 | { | ||
372 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
373 | OMV.Vector3 displacement = OMV.Vector3.Zero; | ||
374 | |||
375 | if (stepUp > 0f) | ||
376 | { | ||
377 | // Found the stairs contact point. Push up a little to raise the character. | ||
378 | if (BSParam.AvatarStepForceFactor > 0f) | ||
379 | { | ||
380 | float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; | ||
381 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
382 | } | ||
383 | |||
384 | // Also move the avatar up for the new height | ||
385 | if (BSParam.AvatarStepUpCorrectionFactor > 0f) | ||
386 | { | ||
387 | // Move the avatar up related to the height of the collision | ||
388 | displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); | ||
389 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | if (BSParam.AvatarStepUpCorrectionFactor < 0f) | ||
394 | { | ||
395 | // Move the avatar up about the specified step height | ||
396 | displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); | ||
397 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
398 | } | ||
399 | } | ||
400 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}", | ||
401 | m_controllingPrim.LocalID, displacement, ret); | ||
402 | |||
403 | } | ||
404 | return ret; | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | |||
409 | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public 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 new file mode 100755 index 0000000..8b0fdeb --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs | |||
@@ -0,0 +1,187 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public class BSActorLockAxis : BSActor | ||
38 | { | ||
39 | BSConstraint LockAxisConstraint = null; | ||
40 | |||
41 | public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
42 | : base(physicsScene, pObj, actorName) | ||
43 | { | ||
44 | m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); | ||
45 | LockAxisConstraint = null; | ||
46 | } | ||
47 | |||
48 | // BSActor.isActive | ||
49 | public override bool isActive | ||
50 | { | ||
51 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
52 | } | ||
53 | |||
54 | // Release any connections and resources used by the actor. | ||
55 | // BSActor.Dispose() | ||
56 | public override void Dispose() | ||
57 | { | ||
58 | RemoveAxisLockConstraint(); | ||
59 | } | ||
60 | |||
61 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
62 | // Called at taint-time. | ||
63 | // BSActor.Refresh() | ||
64 | public override void Refresh() | ||
65 | { | ||
66 | m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,lockedAxis={1},enabled={2},pActive={3}", | ||
67 | m_controllingPrim.LocalID, m_controllingPrim.LockedAngularAxis, Enabled, m_controllingPrim.IsPhysicallyActive); | ||
68 | // If all the axis are free, we don't need to exist | ||
69 | if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree) | ||
70 | { | ||
71 | Enabled = false; | ||
72 | } | ||
73 | |||
74 | // If the object is physically active, add the axis locking constraint | ||
75 | if (isActive) | ||
76 | { | ||
77 | AddAxisLockConstraint(); | ||
78 | } | ||
79 | else | ||
80 | { | ||
81 | RemoveAxisLockConstraint(); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
86 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
87 | // Called at taint-time. | ||
88 | // BSActor.RemoveDependencies() | ||
89 | public override void RemoveDependencies() | ||
90 | { | ||
91 | if (LockAxisConstraint != null) | ||
92 | { | ||
93 | // If a constraint is set up, remove it from the physical scene | ||
94 | RemoveAxisLockConstraint(); | ||
95 | // Schedule a call before the next simulation step to restore the constraint. | ||
96 | m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate() | ||
97 | { | ||
98 | Refresh(); | ||
99 | }); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | private void AddAxisLockConstraint() | ||
104 | { | ||
105 | if (LockAxisConstraint == null) | ||
106 | { | ||
107 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | ||
108 | // the other in the object. | ||
109 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
110 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
111 | |||
112 | // Remove any existing axis constraint (just to be sure) | ||
113 | RemoveAxisLockConstraint(); | ||
114 | |||
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); | ||
120 | |||
121 | // The constraint is tied to the world and oriented to the prim. | ||
122 | |||
123 | // Free to move linearly in the region | ||
124 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | ||
125 | OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize; | ||
126 | if (m_controllingPrim.LockedLinearAxis.X != BSPhysObject.FreeAxis) | ||
127 | { | ||
128 | linearLow.X = m_controllingPrim.RawPosition.X; | ||
129 | linearHigh.X = m_controllingPrim.RawPosition.X; | ||
130 | } | ||
131 | if (m_controllingPrim.LockedLinearAxis.Y != BSPhysObject.FreeAxis) | ||
132 | { | ||
133 | linearLow.Y = m_controllingPrim.RawPosition.Y; | ||
134 | linearHigh.Y = m_controllingPrim.RawPosition.Y; | ||
135 | } | ||
136 | if (m_controllingPrim.LockedLinearAxis.Z != BSPhysObject.FreeAxis) | ||
137 | { | ||
138 | linearLow.Z = m_controllingPrim.RawPosition.Z; | ||
139 | linearHigh.Z = m_controllingPrim.RawPosition.Z; | ||
140 | } | ||
141 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | ||
142 | |||
143 | // Angular with some axis locked | ||
144 | float fPI = (float)Math.PI; | ||
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 | } | ||
166 | |||
167 | m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
168 | m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); | ||
169 | |||
170 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
171 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
172 | |||
173 | axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); | ||
174 | } | ||
175 | } | ||
176 | |||
177 | private void RemoveAxisLockConstraint() | ||
178 | { | ||
179 | if (LockAxisConstraint != null) | ||
180 | { | ||
181 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
182 | LockAxisConstraint = null; | ||
183 | m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | } | ||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | using OMV = OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
38 | { | ||
39 | public 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 new file mode 100755 index 0000000..e0ccc50 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | |||
@@ -0,0 +1,156 @@ | |||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
32 | { | ||
33 | public class BSActorCollection | ||
34 | { | ||
35 | private BSScene m_physicsScene { get; set; } | ||
36 | private Dictionary<string, BSActor> m_actors; | ||
37 | |||
38 | public BSActorCollection(BSScene physicsScene) | ||
39 | { | ||
40 | m_physicsScene = physicsScene; | ||
41 | m_actors = new Dictionary<string, BSActor>(); | ||
42 | } | ||
43 | public void Add(string name, BSActor actor) | ||
44 | { | ||
45 | lock (m_actors) | ||
46 | { | ||
47 | if (!m_actors.ContainsKey(name)) | ||
48 | { | ||
49 | m_actors[name] = actor; | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | public bool RemoveAndRelease(string name) | ||
54 | { | ||
55 | bool ret = false; | ||
56 | lock (m_actors) | ||
57 | { | ||
58 | if (m_actors.ContainsKey(name)) | ||
59 | { | ||
60 | BSActor beingRemoved = m_actors[name]; | ||
61 | m_actors.Remove(name); | ||
62 | beingRemoved.Dispose(); | ||
63 | ret = true; | ||
64 | } | ||
65 | } | ||
66 | return ret; | ||
67 | } | ||
68 | public void Clear() | ||
69 | { | ||
70 | lock (m_actors) | ||
71 | { | ||
72 | ForEachActor(a => a.Dispose()); | ||
73 | m_actors.Clear(); | ||
74 | } | ||
75 | } | ||
76 | public void Dispose() | ||
77 | { | ||
78 | Clear(); | ||
79 | } | ||
80 | public bool HasActor(string name) | ||
81 | { | ||
82 | return m_actors.ContainsKey(name); | ||
83 | } | ||
84 | public bool TryGetActor(string actorName, out BSActor theActor) | ||
85 | { | ||
86 | return m_actors.TryGetValue(actorName, out theActor); | ||
87 | } | ||
88 | public void ForEachActor(Action<BSActor> act) | ||
89 | { | ||
90 | lock (m_actors) | ||
91 | { | ||
92 | foreach (KeyValuePair<string, BSActor> kvp in m_actors) | ||
93 | act(kvp.Value); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | public void Enable(bool enabl) | ||
98 | { | ||
99 | ForEachActor(a => a.SetEnabled(enabl)); | ||
100 | } | ||
101 | public void Refresh() | ||
102 | { | ||
103 | ForEachActor(a => a.Refresh()); | ||
104 | } | ||
105 | public void RemoveDependencies() | ||
106 | { | ||
107 | ForEachActor(a => a.RemoveDependencies()); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // ============================================================================= | ||
112 | /// <summary> | ||
113 | /// Each physical object can have 'actors' who are pushing the object around. | ||
114 | /// This can be used for hover, locking axis, making vehicles, etc. | ||
115 | /// Each physical object can have multiple actors acting on it. | ||
116 | /// | ||
117 | /// An actor usually registers itself with physics scene events (pre-step action) | ||
118 | /// and modifies the parameters on the host physical object. | ||
119 | /// </summary> | ||
120 | public abstract class BSActor | ||
121 | { | ||
122 | protected BSScene m_physicsScene { get; private set; } | ||
123 | protected BSPhysObject m_controllingPrim { get; private set; } | ||
124 | public virtual bool Enabled { get; set; } | ||
125 | public string ActorName { get; private set; } | ||
126 | |||
127 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
128 | { | ||
129 | m_physicsScene = physicsScene; | ||
130 | m_controllingPrim = pObj; | ||
131 | ActorName = actorName; | ||
132 | Enabled = true; | ||
133 | } | ||
134 | |||
135 | // Return 'true' if activily updating the prim | ||
136 | public virtual bool isActive | ||
137 | { | ||
138 | get { return Enabled; } | ||
139 | } | ||
140 | |||
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) | ||
144 | { | ||
145 | Enabled = setEnabled; | ||
146 | } | ||
147 | // Release any connections and resources used by the actor. | ||
148 | public abstract void Dispose(); | ||
149 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
150 | public abstract void Refresh(); | ||
151 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
152 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
153 | public abstract void RemoveDependencies(); | ||
154 | |||
155 | } | ||
156 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs index 5765b0d..6cdc112 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | |||
@@ -70,6 +70,8 @@ public enum BSPhysicsShapeType | |||
70 | SHAPE_COMPOUND = 22, | 70 | SHAPE_COMPOUND = 22, |
71 | SHAPE_HEIGHTMAP = 23, | 71 | SHAPE_HEIGHTMAP = 23, |
72 | SHAPE_AVATAR = 24, | 72 | SHAPE_AVATAR = 24, |
73 | SHAPE_CONVEXHULL= 25, | ||
74 | SHAPE_GIMPACT = 26, | ||
73 | }; | 75 | }; |
74 | 76 | ||
75 | // The native shapes have predefined shape hash keys | 77 | // The native shapes have predefined shape hash keys |
@@ -191,6 +193,21 @@ public struct ConfigurationParameters | |||
191 | public const float numericFalse = 0f; | 193 | public const float numericFalse = 0f; |
192 | } | 194 | } |
193 | 195 | ||
196 | // Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. | ||
197 | [StructLayout(LayoutKind.Sequential)] | ||
198 | public struct HACDParams | ||
199 | { | ||
200 | // usual default values | ||
201 | public float maxVerticesPerHull; // 100 | ||
202 | public float minClusters; // 2 | ||
203 | public float compacityWeight; // 0.1 | ||
204 | public float volumeWeight; // 0.0 | ||
205 | public float concavity; // 100 | ||
206 | public float addExtraDistPoints; // false | ||
207 | public float addNeighboursDistPoints; // false | ||
208 | public float addFacesPoints; // false | ||
209 | public float shouldAdjustCollisionMargin; // false | ||
210 | } | ||
194 | 211 | ||
195 | // The states a bullet collision object can have | 212 | // The states a bullet collision object can have |
196 | public enum ActivationState : uint | 213 | public enum ActivationState : uint |
@@ -282,7 +299,7 @@ public abstract class BSAPITemplate | |||
282 | { | 299 | { |
283 | // Returns the name of the underlying Bullet engine | 300 | // Returns the name of the underlying Bullet engine |
284 | public abstract string BulletEngineName { get; } | 301 | public abstract string BulletEngineName { get; } |
285 | public abstract string BulletEngineVersion { get; protected set;} | 302 | public abstract string BulletEngineVersion { get; protected set;} |
286 | 303 | ||
287 | // Initialization and simulation | 304 | // Initialization and simulation |
288 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | 305 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, |
@@ -305,10 +322,20 @@ public abstract BulletShape CreateMeshShape(BulletWorld world, | |||
305 | int indicesCount, int[] indices, | 322 | int indicesCount, int[] indices, |
306 | int verticesCount, float[] vertices ); | 323 | int verticesCount, float[] vertices ); |
307 | 324 | ||
325 | public abstract BulletShape CreateGImpactShape(BulletWorld world, | ||
326 | int indicesCount, int[] indices, | ||
327 | int verticesCount, float[] vertices ); | ||
328 | |||
308 | public abstract BulletShape CreateHullShape(BulletWorld world, | 329 | public abstract BulletShape CreateHullShape(BulletWorld world, |
309 | int hullCount, float[] hulls); | 330 | int hullCount, float[] hulls); |
310 | 331 | ||
311 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | 332 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); |
333 | |||
334 | public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
335 | |||
336 | public abstract BulletShape CreateConvexHullShape(BulletWorld world, | ||
337 | int indicesCount, int[] indices, | ||
338 | int verticesCount, float[] vertices ); | ||
312 | 339 | ||
313 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | 340 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); |
314 | 341 | ||
@@ -351,7 +378,7 @@ public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | |||
351 | // ===================================================================================== | 378 | // ===================================================================================== |
352 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); | 379 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); |
353 | 380 | ||
354 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 381 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
355 | float scaleFactor, float collisionMargin); | 382 | float scaleFactor, float collisionMargin); |
356 | 383 | ||
357 | // ===================================================================================== | 384 | // ===================================================================================== |
@@ -366,7 +393,7 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, | |||
366 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 393 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
367 | 394 | ||
368 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | 395 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, |
369 | Vector3 frameInBloc, Quaternion frameInBrot, | 396 | Vector3 frameInBloc, Quaternion frameInBrot, |
370 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | 397 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); |
371 | 398 | ||
372 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | 399 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 90c2d9c..291dfcd 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; |
@@ -62,28 +57,25 @@ public sealed class BSCharacter : BSPhysObject | |||
62 | private bool _kinematic; | 57 | private bool _kinematic; |
63 | private float _buoyancy; | 58 | private float _buoyancy; |
64 | 59 | ||
65 | private BSVMotor _velocityMotor; | 60 | private BSActorAvatarMove m_moveActor; |
61 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; | ||
66 | 62 | ||
67 | private OMV.Vector3 _PIDTarget; | 63 | private OMV.Vector3 _PIDTarget; |
68 | private bool _usePID; | 64 | private bool _usePID; |
69 | private float _PIDTau; | 65 | private float _PIDTau; |
70 | private bool _useHoverPID; | ||
71 | private float _PIDHoverHeight; | ||
72 | private PIDHoverType _PIDHoverType; | ||
73 | private float _PIDHoverTao; | ||
74 | 66 | ||
75 | 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) |
76 | : base(parent_scene, localID, avName, "BSCharacter") | 68 | : base(parent_scene, localID, avName, "BSCharacter") |
77 | { | 69 | { |
78 | _physicsActorType = (int)ActorTypes.Agent; | 70 | _physicsActorType = (int)ActorTypes.Agent; |
79 | _position = pos; | 71 | RawPosition = pos; |
80 | 72 | ||
81 | _flying = isFlying; | 73 | _flying = isFlying; |
82 | _orientation = OMV.Quaternion.Identity; | 74 | RawOrientation = OMV.Quaternion.Identity; |
83 | _velocity = OMV.Vector3.Zero; | 75 | RawVelocity = OMV.Vector3.Zero; |
84 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 76 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
85 | Friction = BSParam.AvatarStandingFriction; | 77 | Friction = BSParam.AvatarStandingFriction; |
86 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; | 78 | Density = BSParam.AvatarDensity; |
87 | 79 | ||
88 | // 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, |
89 | // replace with the default values. | 81 | // replace with the default values. |
@@ -97,19 +89,26 @@ public sealed class BSCharacter : BSPhysObject | |||
97 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 89 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
98 | ComputeAvatarVolumeAndMass(); | 90 | ComputeAvatarVolumeAndMass(); |
99 | 91 | ||
100 | SetupMovementMotor(); | 92 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}", |
101 | 93 | LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos); | |
102 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
103 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | ||
104 | 94 | ||
105 | // do actual creation in taint time | 95 | // do actual creation in taint time |
106 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 96 | PhysScene.TaintedObject("BSCharacter.create", delegate() |
107 | { | 97 | { |
108 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 98 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
109 | // New body and shape into PhysBody and PhysShape | 99 | // New body and shape into PhysBody and PhysShape |
110 | 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); | ||
111 | 108 | ||
112 | SetPhysicalProperties(); | 109 | SetPhysicalProperties(); |
110 | |||
111 | IsInitialized = true; | ||
113 | }); | 112 | }); |
114 | return; | 113 | return; |
115 | } | 114 | } |
@@ -117,217 +116,68 @@ public sealed class BSCharacter : BSPhysObject | |||
117 | // 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 |
118 | public override void Destroy() | 117 | public override void Destroy() |
119 | { | 118 | { |
119 | IsInitialized = false; | ||
120 | |||
120 | base.Destroy(); | 121 | base.Destroy(); |
121 | 122 | ||
122 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 123 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
123 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 124 | PhysScene.TaintedObject("BSCharacter.destroy", delegate() |
124 | { | 125 | { |
125 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); | 126 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
126 | PhysBody.Clear(); | 127 | PhysBody.Clear(); |
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); | 128 | PhysShape.Dereference(PhysScene); |
128 | PhysShape.Clear(); | 129 | PhysShape = new BSShapeNull(); |
129 | }); | 130 | }); |
130 | } | 131 | } |
131 | 132 | ||
132 | private void SetPhysicalProperties() | 133 | private void SetPhysicalProperties() |
133 | { | 134 | { |
134 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 135 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
135 | 136 | ||
136 | ZeroMotion(true); | 137 | ZeroMotion(true); |
137 | ForcePosition = _position; | 138 | ForcePosition = RawPosition; |
138 | 139 | ||
139 | // Set the velocity | 140 | // Set the velocity |
140 | _velocityMotor.Reset(); | 141 | if (m_moveActor != null) |
141 | _velocityMotor.SetTarget(_velocity); | 142 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); |
142 | _velocityMotor.SetCurrent(_velocity); | 143 | |
143 | ForceVelocity = _velocity; | 144 | ForceVelocity = RawVelocity; |
144 | 145 | ||
145 | // This will enable or disable the flying buoyancy of the avatar. | 146 | // This will enable or disable the flying buoyancy of the avatar. |
146 | // 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. |
147 | Flying = _flying; | 148 | Flying = _flying; |
148 | 149 | ||
149 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | 150 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
150 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | 151 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); |
151 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 152 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
152 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 153 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
153 | if (BSParam.CcdMotionThreshold > 0f) | 154 | if (BSParam.CcdMotionThreshold > 0f) |
154 | { | 155 | { |
155 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 156 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
156 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 157 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
157 | } | 158 | } |
158 | 159 | ||
159 | UpdatePhysicalMassProperties(RawMass, false); | 160 | UpdatePhysicalMassProperties(RawMass, false); |
160 | 161 | ||
161 | // Make so capsule does not fall over | 162 | // Make so capsule does not fall over |
162 | 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(); | ||
163 | 167 | ||
164 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 168 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
165 | 169 | ||
166 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 170 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
167 | 171 | ||
168 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 172 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
169 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | 173 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
170 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 174 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
171 | 175 | ||
172 | // Do this after the object has been added to the world | 176 | // Do this after the object has been added to the world |
173 | PhysBody.collisionType = CollisionType.Avatar; | 177 | PhysBody.collisionType = CollisionType.Avatar; |
174 | PhysBody.ApplyCollisionMask(PhysicsScene); | 178 | PhysBody.ApplyCollisionMask(PhysScene); |
175 | } | ||
176 | |||
177 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
178 | // the avatar seeking to reach the motor's target speed. | ||
179 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
180 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
181 | private void SetupMovementMotor() | ||
182 | { | ||
183 | // Infinite decay and timescale values so motor only changes current to target values. | ||
184 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
185 | 0.2f, // time scale | ||
186 | BSMotor.Infinite, // decay time scale | ||
187 | BSMotor.InfiniteVector, // friction timescale | ||
188 | 1f // efficiency | ||
189 | ); | ||
190 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
191 | |||
192 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
193 | { | ||
194 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
195 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
196 | |||
197 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
198 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
199 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
200 | // component is not fooled with (thus allowing gravity to do its thing). | ||
201 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
202 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
203 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
204 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
205 | // errors can creap in and the avatar will slowly float off in some direction. | ||
206 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
207 | // from real pushing. | ||
208 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
209 | |||
210 | _velocityMotor.Step(timeStep); | ||
211 | |||
212 | // If we're not supposed to be moving, make sure things are zero. | ||
213 | if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
214 | { | ||
215 | // The avatar shouldn't be moving | ||
216 | _velocityMotor.Zero(); | ||
217 | |||
218 | if (IsColliding) | ||
219 | { | ||
220 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
221 | if (!ColliderIsMoving) | ||
222 | { | ||
223 | DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID); | ||
224 | ZeroMotion(true /* inTaintTime */); | ||
225 | } | ||
226 | |||
227 | // Standing has more friction on the ground | ||
228 | if (Friction != BSParam.AvatarStandingFriction) | ||
229 | { | ||
230 | Friction = BSParam.AvatarStandingFriction; | ||
231 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
232 | } | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | if (Flying) | ||
237 | { | ||
238 | // Flying and not collising and velocity nearly zero. | ||
239 | ZeroMotion(true /* inTaintTime */); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding); | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // Supposed to be moving. | ||
248 | OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue; | ||
249 | |||
250 | if (Friction != BSParam.AvatarFriction) | ||
251 | { | ||
252 | // Probably starting up walking. Set friction to moving friction. | ||
253 | Friction = BSParam.AvatarFriction; | ||
254 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | ||
255 | } | ||
256 | |||
257 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
258 | // The check for _velocity.Z < 0 makes jumping work (temporary upward force). | ||
259 | if (!Flying && !IsColliding) | ||
260 | { | ||
261 | if (_velocity.Z < 0) | ||
262 | stepVelocity.Z = _velocity.Z; | ||
263 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
264 | } | ||
265 | |||
266 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
267 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass; | ||
268 | |||
269 | // Should we check for move force being small and forcing velocity to zero? | ||
270 | |||
271 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
272 | moveForce += WalkUpStairs(); | ||
273 | |||
274 | DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
275 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce); | ||
276 | } | ||
277 | }); | ||
278 | } | 179 | } |
279 | 180 | ||
280 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
281 | // avatar up so it can walk up and over the low objects. | ||
282 | private OMV.Vector3 WalkUpStairs() | ||
283 | { | ||
284 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
285 | |||
286 | // This test is done if moving forward, not flying and is colliding with something. | ||
287 | // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}", | ||
288 | // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count); | ||
289 | if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */) | ||
290 | { | ||
291 | // The range near the character's feet where we will consider stairs | ||
292 | float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f; | ||
293 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
294 | |||
295 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is | ||
296 | foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList) | ||
297 | { | ||
298 | // Don't care about collisions with the terrain | ||
299 | if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID) | ||
300 | { | ||
301 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
302 | // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
303 | // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
304 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
305 | { | ||
306 | // This contact is within the 'near the feet' range. | ||
307 | // The normal should be our contact point to the object so it is pointing away | ||
308 | // thus the difference between our facing orientation and the normal should be small. | ||
309 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation; | ||
310 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
311 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
312 | if (diff < BSParam.AvatarStepApproachFactor) | ||
313 | { | ||
314 | // Found the stairs contact point. Push up a little to raise the character. | ||
315 | float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor; | ||
316 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
317 | |||
318 | // Also move the avatar up for the new height | ||
319 | OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f); | ||
320 | ForcePosition = RawPosition + displacement; | ||
321 | } | ||
322 | DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}", | ||
323 | LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret); | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | } | ||
328 | |||
329 | return ret; | ||
330 | } | ||
331 | 181 | ||
332 | public override void RequestPhysicsterseUpdate() | 182 | public override void RequestPhysicsterseUpdate() |
333 | { | 183 | { |
@@ -344,6 +194,10 @@ public sealed class BSCharacter : BSPhysObject | |||
344 | } | 194 | } |
345 | 195 | ||
346 | 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 | |||
347 | _size = value; | 201 | _size = value; |
348 | // 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, |
349 | // replace with the default values. | 203 | // replace with the default values. |
@@ -355,14 +209,18 @@ public sealed class BSCharacter : BSPhysObject | |||
355 | 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}", |
356 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 210 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
357 | 211 | ||
358 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 212 | PhysScene.TaintedObject("BSCharacter.setSize", delegate() |
359 | { | 213 | { |
360 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | 214 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) |
361 | { | 215 | { |
362 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 216 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
363 | 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 | |||
364 | // Make sure this change appears as a property update event | 222 | // Make sure this change appears as a property update event |
365 | PhysicsScene.PE.PushUpdate(PhysBody); | 223 | PhysScene.PE.PushUpdate(PhysBody); |
366 | } | 224 | } |
367 | }); | 225 | }); |
368 | 226 | ||
@@ -373,11 +231,6 @@ public sealed class BSCharacter : BSPhysObject | |||
373 | { | 231 | { |
374 | set { BaseShape = value; } | 232 | set { BaseShape = value; } |
375 | } | 233 | } |
376 | // I want the physics engine to make an avatar capsule | ||
377 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
378 | { | ||
379 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
380 | } | ||
381 | 234 | ||
382 | public override bool Grabbed { | 235 | public override bool Grabbed { |
383 | set { _grabbed = value; } | 236 | set { _grabbed = value; } |
@@ -399,29 +252,29 @@ public sealed class BSCharacter : BSPhysObject | |||
399 | // Called at taint time! | 252 | // Called at taint time! |
400 | public override void ZeroMotion(bool inTaintTime) | 253 | public override void ZeroMotion(bool inTaintTime) |
401 | { | 254 | { |
402 | _velocity = OMV.Vector3.Zero; | 255 | RawVelocity = OMV.Vector3.Zero; |
403 | _acceleration = OMV.Vector3.Zero; | 256 | _acceleration = OMV.Vector3.Zero; |
404 | _rotationalVelocity = OMV.Vector3.Zero; | 257 | _rotationalVelocity = OMV.Vector3.Zero; |
405 | 258 | ||
406 | // Zero some other properties directly into the physics engine | 259 | // Zero some other properties directly into the physics engine |
407 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 260 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
408 | { | 261 | { |
409 | if (PhysBody.HasPhysicalBody) | 262 | if (PhysBody.HasPhysicalBody) |
410 | PhysicsScene.PE.ClearAllForces(PhysBody); | 263 | PhysScene.PE.ClearAllForces(PhysBody); |
411 | }); | 264 | }); |
412 | } | 265 | } |
413 | public override void ZeroAngularMotion(bool inTaintTime) | 266 | public override void ZeroAngularMotion(bool inTaintTime) |
414 | { | 267 | { |
415 | _rotationalVelocity = OMV.Vector3.Zero; | 268 | _rotationalVelocity = OMV.Vector3.Zero; |
416 | 269 | ||
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 270 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
418 | { | 271 | { |
419 | if (PhysBody.HasPhysicalBody) | 272 | if (PhysBody.HasPhysicalBody) |
420 | { | 273 | { |
421 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | 274 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
422 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | 275 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
423 | // 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. |
424 | PhysicsScene.PE.ClearForces(PhysBody); | 277 | PhysScene.PE.ClearForces(PhysBody); |
425 | } | 278 | } |
426 | }); | 279 | }); |
427 | } | 280 | } |
@@ -429,38 +282,33 @@ public sealed class BSCharacter : BSPhysObject | |||
429 | 282 | ||
430 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 283 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } |
431 | 284 | ||
432 | public override OMV.Vector3 RawPosition | ||
433 | { | ||
434 | get { return _position; } | ||
435 | set { _position = value; } | ||
436 | } | ||
437 | public override OMV.Vector3 Position { | 285 | public override OMV.Vector3 Position { |
438 | get { | 286 | get { |
439 | // 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 |
440 | // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); | 288 | // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); |
441 | return _position; | 289 | return RawPosition; |
442 | } | 290 | } |
443 | set { | 291 | set { |
444 | _position = value; | 292 | RawPosition = value; |
445 | 293 | ||
446 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 294 | PhysScene.TaintedObject("BSCharacter.setPosition", delegate() |
447 | { | 295 | { |
448 | 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); |
449 | PositionSanityCheck(); | 297 | PositionSanityCheck(); |
450 | ForcePosition = _position; | 298 | ForcePosition = RawPosition; |
451 | }); | 299 | }); |
452 | } | 300 | } |
453 | } | 301 | } |
454 | public override OMV.Vector3 ForcePosition { | 302 | public override OMV.Vector3 ForcePosition { |
455 | get { | 303 | get { |
456 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 304 | RawPosition = PhysScene.PE.GetPosition(PhysBody); |
457 | return _position; | 305 | return RawPosition; |
458 | } | 306 | } |
459 | set { | 307 | set { |
460 | _position = value; | 308 | RawPosition = value; |
461 | if (PhysBody.HasPhysicalBody) | 309 | if (PhysBody.HasPhysicalBody) |
462 | { | 310 | { |
463 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 311 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
464 | } | 312 | } |
465 | } | 313 | } |
466 | } | 314 | } |
@@ -474,30 +322,30 @@ public sealed class BSCharacter : BSPhysObject | |||
474 | bool ret = false; | 322 | bool ret = false; |
475 | 323 | ||
476 | // TODO: check for out of bounds | 324 | // TODO: check for out of bounds |
477 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 325 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
478 | { | 326 | { |
479 | // The character is out of the known/simulated area. | 327 | // The character is out of the known/simulated area. |
480 | // 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 |
481 | // 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. |
482 | RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); | 330 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); |
483 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | 331 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); |
484 | return true; | 332 | return true; |
485 | } | 333 | } |
486 | 334 | ||
487 | // If below the ground, move the avatar up | 335 | // If below the ground, move the avatar up |
488 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 336 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
489 | if (Position.Z < terrainHeight) | 337 | if (Position.Z < terrainHeight) |
490 | { | 338 | { |
491 | 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); |
492 | _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; | 340 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); |
493 | ret = true; | 341 | ret = true; |
494 | } | 342 | } |
495 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 343 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
496 | { | 344 | { |
497 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 345 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); |
498 | if (Position.Z < waterHeight) | 346 | if (Position.Z < waterHeight) |
499 | { | 347 | { |
500 | _position.Z = waterHeight; | 348 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); |
501 | ret = true; | 349 | ret = true; |
502 | } | 350 | } |
503 | } | 351 | } |
@@ -515,10 +363,10 @@ public sealed class BSCharacter : BSPhysObject | |||
515 | { | 363 | { |
516 | // 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 |
517 | // just assign to "Position" because of potential call loops. | 365 | // just assign to "Position" because of potential call loops. |
518 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 366 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
519 | { | 367 | { |
520 | 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); |
521 | ForcePosition = _position; | 369 | ForcePosition = RawPosition; |
522 | }); | 370 | }); |
523 | ret = true; | 371 | ret = true; |
524 | } | 372 | } |
@@ -528,25 +376,25 @@ public sealed class BSCharacter : BSPhysObject | |||
528 | public override float Mass { get { return _mass; } } | 376 | public override float Mass { get { return _mass; } } |
529 | 377 | ||
530 | // 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 |
531 | public override float RawMass { | 379 | public override float RawMass { |
532 | get {return _mass; } | 380 | get {return _mass; } |
533 | } | 381 | } |
534 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 382 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
535 | { | 383 | { |
536 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 384 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
537 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | 385 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
538 | } | 386 | } |
539 | 387 | ||
540 | public override OMV.Vector3 Force { | 388 | public override OMV.Vector3 Force { |
541 | get { return _force; } | 389 | get { return RawForce; } |
542 | set { | 390 | set { |
543 | _force = value; | 391 | RawForce = value; |
544 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 392 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
545 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 393 | PhysScene.TaintedObject("BSCharacter.SetForce", delegate() |
546 | { | 394 | { |
547 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 395 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
548 | if (PhysBody.HasPhysicalBody) | 396 | if (PhysBody.HasPhysicalBody) |
549 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 397 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); |
550 | }); | 398 | }); |
551 | } | 399 | } |
552 | } | 400 | } |
@@ -560,6 +408,7 @@ public sealed class BSCharacter : BSPhysObject | |||
560 | 408 | ||
561 | // 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 |
562 | public override void SetVolumeDetect(int param) { return; } | 410 | public override void SetVolumeDetect(int param) { return; } |
411 | public override bool IsVolumeDetect { get { return false; } } | ||
563 | 412 | ||
564 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | 413 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } |
565 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 414 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } |
@@ -569,61 +418,49 @@ public sealed class BSCharacter : BSPhysObject | |||
569 | { | 418 | { |
570 | get | 419 | get |
571 | { | 420 | { |
572 | return m_targetVelocity; | 421 | return base.m_targetVelocity; |
573 | } | 422 | } |
574 | set | 423 | set |
575 | { | 424 | { |
576 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | 425 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); |
577 | m_targetVelocity = value; | 426 | m_targetVelocity = value; |
578 | OMV.Vector3 targetVel = value; | 427 | OMV.Vector3 targetVel = value; |
579 | if (_setAlwaysRun) | 428 | if (_setAlwaysRun && !_flying) |
580 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); | 429 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); |
581 | 430 | ||
582 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 431 | if (m_moveActor != null) |
583 | { | 432 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
584 | _velocityMotor.Reset(); | ||
585 | _velocityMotor.SetTarget(targetVel); | ||
586 | _velocityMotor.SetCurrent(_velocity); | ||
587 | _velocityMotor.Enabled = true; | ||
588 | }); | ||
589 | } | 433 | } |
590 | } | 434 | } |
591 | public override OMV.Vector3 RawVelocity | ||
592 | { | ||
593 | get { return _velocity; } | ||
594 | set { _velocity = value; } | ||
595 | } | ||
596 | // 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. |
597 | public override OMV.Vector3 Velocity { | 436 | public override OMV.Vector3 Velocity { |
598 | get { return _velocity; } | 437 | get { return RawVelocity; } |
599 | set { | 438 | set { |
600 | _velocity = value; | 439 | RawVelocity = value; |
601 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 440 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); |
602 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 441 | PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() |
603 | { | 442 | { |
604 | _velocityMotor.Reset(); | 443 | if (m_moveActor != null) |
605 | _velocityMotor.SetCurrent(_velocity); | 444 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); |
606 | _velocityMotor.SetTarget(_velocity); | ||
607 | _velocityMotor.Enabled = false; | ||
608 | 445 | ||
609 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 446 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); |
610 | ForceVelocity = _velocity; | 447 | ForceVelocity = RawVelocity; |
611 | }); | 448 | }); |
612 | } | 449 | } |
613 | } | 450 | } |
614 | public override OMV.Vector3 ForceVelocity { | 451 | public override OMV.Vector3 ForceVelocity { |
615 | get { return _velocity; } | 452 | get { return RawVelocity; } |
616 | set { | 453 | set { |
617 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 454 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
618 | 455 | ||
619 | _velocity = value; | 456 | RawVelocity = value; |
620 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 457 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
621 | PhysicsScene.PE.Activate(PhysBody, true); | 458 | PhysScene.PE.Activate(PhysBody, true); |
622 | } | 459 | } |
623 | } | 460 | } |
624 | public override OMV.Vector3 Torque { | 461 | public override OMV.Vector3 Torque { |
625 | get { return _torque; } | 462 | get { return RawTorque; } |
626 | set { _torque = value; | 463 | set { RawTorque = value; |
627 | } | 464 | } |
628 | } | 465 | } |
629 | public override float CollisionScore { | 466 | public override float CollisionScore { |
@@ -635,22 +472,27 @@ public sealed class BSCharacter : BSPhysObject | |||
635 | get { return _acceleration; } | 472 | get { return _acceleration; } |
636 | set { _acceleration = value; } | 473 | set { _acceleration = value; } |
637 | } | 474 | } |
638 | public override OMV.Quaternion RawOrientation | ||
639 | { | ||
640 | get { return _orientation; } | ||
641 | set { _orientation = value; } | ||
642 | } | ||
643 | public override OMV.Quaternion Orientation { | 475 | public override OMV.Quaternion Orientation { |
644 | get { return _orientation; } | 476 | get { return RawOrientation; } |
645 | set { | 477 | set { |
646 | // 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 |
647 | // the viewer doesn't trust us. | 479 | // the viewer doesn't trust us. |
648 | if (_orientation != value) | 480 | if (RawOrientation != value) |
649 | { | 481 | { |
650 | _orientation = value; | 482 | RawOrientation = value; |
651 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 483 | PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() |
652 | { | 484 | { |
653 | 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; | ||
654 | }); | 496 | }); |
655 | } | 497 | } |
656 | } | 498 | } |
@@ -660,16 +502,16 @@ public sealed class BSCharacter : BSPhysObject | |||
660 | { | 502 | { |
661 | get | 503 | get |
662 | { | 504 | { |
663 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 505 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); |
664 | return _orientation; | 506 | return RawOrientation; |
665 | } | 507 | } |
666 | set | 508 | set |
667 | { | 509 | { |
668 | _orientation = value; | 510 | RawOrientation = value; |
669 | if (PhysBody.HasPhysicalBody) | 511 | if (PhysBody.HasPhysicalBody) |
670 | { | 512 | { |
671 | // _position = PhysicsScene.PE.GetPosition(BSBody); | 513 | // RawPosition = PhysicsScene.PE.GetPosition(BSBody); |
672 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 514 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
673 | } | 515 | } |
674 | } | 516 | } |
675 | } | 517 | } |
@@ -718,14 +560,14 @@ public sealed class BSCharacter : BSPhysObject | |||
718 | public override bool FloatOnWater { | 560 | public override bool FloatOnWater { |
719 | set { | 561 | set { |
720 | _floatOnWater = value; | 562 | _floatOnWater = value; |
721 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 563 | PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
722 | { | 564 | { |
723 | if (PhysBody.HasPhysicalBody) | 565 | if (PhysBody.HasPhysicalBody) |
724 | { | 566 | { |
725 | if (_floatOnWater) | 567 | if (_floatOnWater) |
726 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 568 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
727 | else | 569 | else |
728 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 570 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
729 | } | 571 | } |
730 | }); | 572 | }); |
731 | } | 573 | } |
@@ -746,7 +588,7 @@ public sealed class BSCharacter : BSPhysObject | |||
746 | public override float Buoyancy { | 588 | public override float Buoyancy { |
747 | get { return _buoyancy; } | 589 | get { return _buoyancy; } |
748 | set { _buoyancy = value; | 590 | set { _buoyancy = value; |
749 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 591 | PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
750 | { | 592 | { |
751 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 593 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
752 | ForceBuoyancy = _buoyancy; | 594 | ForceBuoyancy = _buoyancy; |
@@ -755,8 +597,8 @@ public sealed class BSCharacter : BSPhysObject | |||
755 | } | 597 | } |
756 | public override float ForceBuoyancy { | 598 | public override float ForceBuoyancy { |
757 | get { return _buoyancy; } | 599 | get { return _buoyancy; } |
758 | set { | 600 | set { |
759 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | 601 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); |
760 | 602 | ||
761 | _buoyancy = value; | 603 | _buoyancy = value; |
762 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 604 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
@@ -764,7 +606,7 @@ public sealed class BSCharacter : BSPhysObject | |||
764 | float grav = BSParam.Gravity * (1f - _buoyancy); | 606 | float grav = BSParam.Gravity * (1f - _buoyancy); |
765 | Gravity = new OMV.Vector3(0f, 0f, grav); | 607 | Gravity = new OMV.Vector3(0f, 0f, grav); |
766 | if (PhysBody.HasPhysicalBody) | 608 | if (PhysBody.HasPhysicalBody) |
767 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 609 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
768 | } | 610 | } |
769 | } | 611 | } |
770 | 612 | ||
@@ -779,46 +621,25 @@ public sealed class BSCharacter : BSPhysObject | |||
779 | set { _PIDTau = value; } | 621 | set { _PIDTau = value; } |
780 | } | 622 | } |
781 | 623 | ||
782 | // Used for llSetHoverHeight and maybe vehicle height | ||
783 | // Hover Height will override MoveTo target's Z | ||
784 | public override bool PIDHoverActive { | ||
785 | set { _useHoverPID = value; } | ||
786 | } | ||
787 | public override float PIDHoverHeight { | ||
788 | set { _PIDHoverHeight = value; } | ||
789 | } | ||
790 | public override PIDHoverType PIDHoverType { | ||
791 | set { _PIDHoverType = value; } | ||
792 | } | ||
793 | public override float PIDHoverTau { | ||
794 | set { _PIDHoverTao = value; } | ||
795 | } | ||
796 | |||
797 | // For RotLookAt | ||
798 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
799 | public override bool APIDActive { set { return; } } | ||
800 | public override float APIDStrength { set { return; } } | ||
801 | public override float APIDDamping { set { return; } } | ||
802 | |||
803 | public override void AddForce(OMV.Vector3 force, bool pushforce) | 624 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
804 | { | 625 | { |
805 | // 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. |
806 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 627 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; |
807 | AddForce(addForce, pushforce, false); | 628 | AddForce(addForce, pushforce, false); |
808 | } | 629 | } |
809 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 630 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
810 | if (force.IsFinite()) | 631 | if (force.IsFinite()) |
811 | { | 632 | { |
812 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 633 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
813 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | 634 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
814 | 635 | ||
815 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | 636 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() |
816 | { | 637 | { |
817 | // 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 |
818 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | 639 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
819 | if (PhysBody.HasPhysicalBody) | 640 | if (PhysBody.HasPhysicalBody) |
820 | { | 641 | { |
821 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 642 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
822 | } | 643 | } |
823 | }); | 644 | }); |
824 | } | 645 | } |
@@ -829,7 +650,7 @@ public sealed class BSCharacter : BSPhysObject | |||
829 | } | 650 | } |
830 | } | 651 | } |
831 | 652 | ||
832 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 653 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
833 | } | 654 | } |
834 | public override void SetMomentum(OMV.Vector3 momentum) { | 655 | public override void SetMomentum(OMV.Vector3 momentum) { |
835 | } | 656 | } |
@@ -837,14 +658,14 @@ public sealed class BSCharacter : BSPhysObject | |||
837 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | 658 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
838 | { | 659 | { |
839 | OMV.Vector3 newScale; | 660 | OMV.Vector3 newScale; |
840 | 661 | ||
841 | // Bullet's capsule total height is the "passed height + radius * 2"; | 662 | // Bullet's capsule total height is the "passed height + radius * 2"; |
842 | // 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) |
843 | // 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 |
844 | // shape to be the size desired. | 665 | // shape to be the size desired. |
845 | // 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 |
846 | // (size.Z) and remove the caps. | 667 | // (size.Z) and remove the caps. |
847 | // 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 |
848 | // 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 |
849 | // 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. |
850 | 671 | ||
@@ -852,8 +673,27 @@ public sealed class BSCharacter : BSPhysObject | |||
852 | newScale.X = size.X / 2f; | 673 | newScale.X = size.X / 2f; |
853 | newScale.Y = size.Y / 2f; | 674 | newScale.Y = size.Y / 2f; |
854 | 675 | ||
676 | float heightAdjust = BSParam.AvatarHeightMidFudge; | ||
677 | if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) | ||
678 | { | ||
679 | // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. | ||
680 | // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 | ||
681 | float midHeightOffset = size.Z - 1.87f; | ||
682 | if (midHeightOffset < 0f) | ||
683 | { | ||
684 | // Small avatar. Add the adjustment based on the distance from midheight | ||
685 | heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | // Large avatar. Add the adjustment based on the distance from midheight | ||
690 | heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; | ||
691 | } | ||
692 | } | ||
855 | // The total scale height is the central cylindar plus the caps on the two ends. | 693 | // The total scale height is the central cylindar plus the caps on the two ends. |
856 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; | 694 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; |
695 | // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); | ||
696 | |||
857 | // If smaller than the endcaps, just fake like we're almost that small | 697 | // If smaller than the endcaps, just fake like we're almost that small |
858 | if (newScale.Z < 0) | 698 | if (newScale.Z < 0) |
859 | newScale.Z = 0.1f; | 699 | newScale.Z = 0.1f; |
@@ -882,15 +722,18 @@ public sealed class BSCharacter : BSPhysObject | |||
882 | // the world that things have changed. | 722 | // the world that things have changed. |
883 | public override void UpdateProperties(EntityProperties entprop) | 723 | public override void UpdateProperties(EntityProperties entprop) |
884 | { | 724 | { |
885 | _position = entprop.Position; | 725 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. |
886 | _orientation = entprop.Rotation; | 726 | TriggerPreUpdatePropertyAction(ref entprop); |
727 | |||
728 | RawPosition = entprop.Position; | ||
729 | RawOrientation = entprop.Rotation; | ||
887 | 730 | ||
888 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | 731 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar |
889 | // and will send agent updates to the clients if velocity changes by more than | 732 | // and will send agent updates to the clients if velocity changes by more than |
890 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | 733 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many |
891 | // extra updates. | 734 | // extra updates. |
892 | if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) | 735 | if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) |
893 | _velocity = entprop.Velocity; | 736 | RawVelocity = entprop.Velocity; |
894 | 737 | ||
895 | _acceleration = entprop.Acceleration; | 738 | _acceleration = entprop.Acceleration; |
896 | _rotationalVelocity = entprop.RotationalVelocity; | 739 | _rotationalVelocity = entprop.RotationalVelocity; |
@@ -898,8 +741,8 @@ public sealed class BSCharacter : BSPhysObject | |||
898 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 741 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
899 | if (PositionSanityCheck(true)) | 742 | if (PositionSanityCheck(true)) |
900 | { | 743 | { |
901 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); | 744 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); |
902 | entprop.Position = _position; | 745 | entprop.Position = RawPosition; |
903 | } | 746 | } |
904 | 747 | ||
905 | // remember the current and last set values | 748 | // remember the current and last set values |
@@ -910,10 +753,10 @@ public sealed class BSCharacter : BSPhysObject | |||
910 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | 753 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
911 | 754 | ||
912 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 755 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
913 | // base.RequestPhysicsterseUpdate(); | 756 | // PhysScene.PostUpdate(this); |
914 | 757 | ||
915 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 758 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
916 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 759 | LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); |
917 | } | 760 | } |
918 | } | 761 | } |
919 | } | 762 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index b813974..42b5c49 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -85,7 +85,9 @@ public abstract class BSConstraint : IDisposable | |||
85 | { | 85 | { |
86 | bool ret = false; | 86 | bool ret = false; |
87 | if (m_enabled) | 87 | if (m_enabled) |
88 | { | ||
88 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); | 89 | ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); |
90 | } | ||
89 | return ret; | 91 | return ret; |
90 | } | 92 | } |
91 | 93 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 476a0e5..d0949f5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -97,14 +97,14 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
97 | 97 | ||
98 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object | 98 | // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object |
99 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, | 99 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, |
100 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 100 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) |
101 | : base(world) | 101 | : base(world) |
102 | { | 102 | { |
103 | m_body1 = obj1; | 103 | m_body1 = obj1; |
104 | m_body2 = obj1; // Look out for confusion down the road | 104 | m_body2 = obj1; // Look out for confusion down the road |
105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, | 105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, |
106 | frameInBloc, frameInBrot, | 106 | frameInBloc, frameInBrot, |
107 | useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); | 107 | useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); |
108 | m_enabled = true; | 108 | m_enabled = true; |
109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", | 109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", |
110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); | 110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); |
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/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 65df741..f0d17d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -40,13 +40,14 @@ using OpenSim.Region.Physics.Manager; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | 41 | namespace OpenSim.Region.Physics.BulletSPlugin |
42 | { | 42 | { |
43 | public sealed class BSDynamics | 43 | public sealed class BSDynamics : BSActor |
44 | { | 44 | { |
45 | private static string LogHeader = "[BULLETSIM VEHICLE]"; | 45 | private static string LogHeader = "[BULLETSIM VEHICLE]"; |
46 | 46 | ||
47 | private BSScene PhysicsScene { get; set; } | ||
48 | // the prim this dynamic controller belongs to | 47 | // the prim this dynamic controller belongs to |
49 | private BSPrim Prim { get; set; } | 48 | private BSPrimLinkable ControllingPrim { get; set; } |
49 | |||
50 | private bool m_haveRegisteredForSceneEvents; | ||
50 | 51 | ||
51 | // mass of the vehicle fetched each time we're calles | 52 | // mass of the vehicle fetched each time we're calles |
52 | private float m_vehicleMass; | 53 | private float m_vehicleMass; |
@@ -124,38 +125,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | 125 | static readonly float PIOverFour = ((float)Math.PI) / 4f; |
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | 126 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; |
126 | 127 | ||
127 | // For debugging, flags to turn on and off individual corrections. | 128 | public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) |
128 | public bool enableAngularVerticalAttraction; | 129 | : base(myScene, myPrim, actorName) |
129 | public bool enableAngularDeflection; | ||
130 | public bool enableAngularBanking; | ||
131 | |||
132 | public BSDynamics(BSScene myScene, BSPrim myPrim) | ||
133 | { | 130 | { |
134 | PhysicsScene = myScene; | ||
135 | Prim = myPrim; | ||
136 | Type = Vehicle.TYPE_NONE; | 131 | Type = Vehicle.TYPE_NONE; |
137 | SetupVehicleDebugging(); | 132 | m_haveRegisteredForSceneEvents = false; |
138 | } | ||
139 | 133 | ||
140 | // Stopgap debugging enablement. Allows source level debugging but still checking | 134 | ControllingPrim = myPrim as BSPrimLinkable; |
141 | // in changes by making enablement of debugging flags from INI file. | 135 | if (ControllingPrim == null) |
142 | public void SetupVehicleDebugging() | ||
143 | { | ||
144 | enableAngularVerticalAttraction = true; | ||
145 | enableAngularDeflection = false; | ||
146 | enableAngularBanking = true; | ||
147 | if (BSParam.VehicleDebuggingEnabled) | ||
148 | { | 136 | { |
149 | enableAngularVerticalAttraction = true; | 137 | // THIS CANNOT HAPPEN!! |
150 | enableAngularDeflection = false; | ||
151 | enableAngularBanking = false; | ||
152 | } | 138 | } |
139 | VDetailLog("{0},Creation", ControllingPrim.LocalID); | ||
153 | } | 140 | } |
154 | 141 | ||
155 | // Return 'true' if this vehicle is doing vehicle things | 142 | // Return 'true' if this vehicle is doing vehicle things |
156 | public bool IsActive | 143 | public bool IsActive |
157 | { | 144 | { |
158 | get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); } | 145 | get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } |
159 | } | 146 | } |
160 | 147 | ||
161 | // Return 'true' if this a vehicle that should be sitting on the ground | 148 | // Return 'true' if this a vehicle that should be sitting on the ground |
@@ -167,11 +154,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | #region Vehicle parameter setting | 154 | #region Vehicle parameter setting |
168 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 155 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
169 | { | 156 | { |
170 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 157 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
171 | switch (pParam) | 158 | switch (pParam) |
172 | { | 159 | { |
173 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 160 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
174 | m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); | 161 | m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f); |
175 | break; | 162 | break; |
176 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | 163 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: |
177 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 164 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
@@ -195,7 +182,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
195 | break; | 182 | break; |
196 | case Vehicle.BUOYANCY: | 183 | case Vehicle.BUOYANCY: |
197 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | 184 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
198 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 185 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); |
199 | break; | 186 | break; |
200 | case Vehicle.HOVER_EFFICIENCY: | 187 | case Vehicle.HOVER_EFFICIENCY: |
201 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); | 188 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
@@ -207,7 +194,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
207 | m_VhoverTimescale = Math.Max(pValue, 0.01f); | 194 | m_VhoverTimescale = Math.Max(pValue, 0.01f); |
208 | break; | 195 | break; |
209 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | 196 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: |
210 | m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); | 197 | m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f); |
211 | break; | 198 | break; |
212 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | 199 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: |
213 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 200 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
@@ -233,7 +220,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
233 | // set all of the components to the same value | 220 | // set all of the components to the same value |
234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 221 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
235 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 222 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
237 | break; | 223 | break; |
238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 224 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
239 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 225 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -242,7 +228,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
242 | break; | 228 | break; |
243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 229 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
244 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 230 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
245 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
246 | break; | 231 | break; |
247 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 232 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 233 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -258,12 +243,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
258 | 243 | ||
259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 244 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) |
260 | { | 245 | { |
261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 246 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
262 | switch (pParam) | 247 | switch (pParam) |
263 | { | 248 | { |
264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 249 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 250 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
266 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
267 | break; | 251 | break; |
268 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 252 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
269 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 253 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
@@ -276,7 +260,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
276 | break; | 260 | break; |
277 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 261 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
278 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 262 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
279 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
280 | break; | 263 | break; |
281 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 264 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
282 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 265 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -294,7 +277,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
294 | 277 | ||
295 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 278 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
296 | { | 279 | { |
297 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 280 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
298 | switch (pParam) | 281 | switch (pParam) |
299 | { | 282 | { |
300 | case Vehicle.REFERENCE_FRAME: | 283 | case Vehicle.REFERENCE_FRAME: |
@@ -308,7 +291,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
308 | 291 | ||
309 | internal void ProcessVehicleFlags(int pParam, bool remove) | 292 | internal void ProcessVehicleFlags(int pParam, bool remove) |
310 | { | 293 | { |
311 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 294 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); |
312 | VehicleFlag parm = (VehicleFlag)pParam; | 295 | VehicleFlag parm = (VehicleFlag)pParam; |
313 | if (pParam == -1) | 296 | if (pParam == -1) |
314 | m_flags = (VehicleFlag)0; | 297 | m_flags = (VehicleFlag)0; |
@@ -323,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
323 | 306 | ||
324 | public void ProcessTypeChange(Vehicle pType) | 307 | public void ProcessTypeChange(Vehicle pType) |
325 | { | 308 | { |
326 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 309 | VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); |
327 | // Set Defaults For Type | 310 | // Set Defaults For Type |
328 | Type = pType; | 311 | Type = pType; |
329 | switch (pType) | 312 | switch (pType) |
@@ -557,34 +540,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
557 | break; | 540 | break; |
558 | } | 541 | } |
559 | 542 | ||
560 | // Update any physical parameters based on this type. | 543 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); |
561 | Refresh(); | 544 | // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
562 | 545 | ||
563 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | 546 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); |
564 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | 547 | // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
565 | 1f); | ||
566 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
567 | |||
568 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
569 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
570 | 1f); | ||
571 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
572 | 548 | ||
573 | /* Not implemented | 549 | /* Not implemented |
574 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | 550 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, |
575 | BSMotor.Infinite, BSMotor.InfiniteVector, | 551 | BSMotor.Infinite, BSMotor.InfiniteVector, |
576 | m_verticalAttractionEfficiency); | 552 | m_verticalAttractionEfficiency); |
577 | // Z goes away and we keep X and Y | 553 | // Z goes away and we keep X and Y |
578 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
579 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | 554 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
580 | */ | 555 | */ |
556 | |||
557 | if (this.Type == Vehicle.TYPE_NONE) | ||
558 | { | ||
559 | UnregisterForSceneEvents(); | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | RegisterForSceneEvents(); | ||
564 | } | ||
565 | |||
566 | // Update any physical parameters based on this type. | ||
567 | Refresh(); | ||
581 | } | 568 | } |
582 | #endregion // Vehicle parameter setting | 569 | #endregion // Vehicle parameter setting |
583 | 570 | ||
584 | public void Refresh() | 571 | // BSActor.Refresh() |
572 | public override void Refresh() | ||
585 | { | 573 | { |
586 | // 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. |
587 | PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate() | 575 | // Called whether active or not since the active state may be updated before the next step. |
576 | m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() | ||
588 | { | 577 | { |
589 | SetPhysicalParameters(); | 578 | SetPhysicalParameters(); |
590 | }); | 579 | }); |
@@ -597,49 +586,98 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
597 | if (IsActive) | 586 | if (IsActive) |
598 | { | 587 | { |
599 | // Remember the mass so we don't have to fetch it every step | 588 | // Remember the mass so we don't have to fetch it every step |
600 | m_vehicleMass = Prim.TotalMass; | 589 | m_vehicleMass = ControllingPrim.TotalMass; |
601 | 590 | ||
602 | // Friction affects are handled by this vehicle code | 591 | // Friction affects are handled by this vehicle code |
603 | PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction); | 592 | // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); |
604 | PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution); | 593 | // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); |
594 | ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); | ||
595 | ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); | ||
605 | 596 | ||
606 | // Moderate angular movement introduced by Bullet. | 597 | // Moderate angular movement introduced by Bullet. |
607 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | 598 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. |
608 | // Maybe compute linear and angular factor and damping from params. | 599 | // Maybe compute linear and angular factor and damping from params. |
609 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping); | 600 | m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); |
610 | PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor); | 601 | m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); |
611 | PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor); | 602 | m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); |
612 | 603 | ||
613 | // 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 |
614 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 605 | // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
606 | ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
615 | 607 | ||
616 | Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | 608 | // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); |
617 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia); | 609 | // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; |
618 | PhysicsScene.PE.UpdateInertiaTensor(Prim.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); | ||
619 | 613 | ||
620 | // Set the gravity for the vehicle depending on the buoyancy | 614 | // Set the gravity for the vehicle depending on the buoyancy |
621 | // TODO: what should be done if prim and vehicle buoyancy differ? | 615 | // TODO: what should be done if prim and vehicle buoyancy differ? |
622 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 616 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); |
623 | // 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. |
624 | PhysicsScene.PE.SetGravity(Prim.PhysBody, Vector3.Zero); | 618 | // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); |
619 | ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); | ||
625 | 620 | ||
626 | 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}", |
627 | Prim.LocalID, m_vehicleMass, Prim.Inertia, m_VehicleGravity, | 622 | ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, |
628 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | 623 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, |
629 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | 624 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor |
630 | ); | 625 | ); |
631 | } | 626 | } |
632 | else | 627 | else |
633 | { | 628 | { |
634 | if (Prim.PhysBody.HasPhysicalBody) | 629 | if (ControllingPrim.PhysBody.HasPhysicalBody) |
635 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 630 | m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
631 | // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
636 | } | 632 | } |
637 | } | 633 | } |
638 | 634 | ||
639 | public bool RemoveBodyDependencies(BSPhysObject prim) | 635 | // BSActor.RemoveBodyDependencies |
636 | public override void RemoveDependencies() | ||
640 | { | 637 | { |
641 | Refresh(); | 638 | Refresh(); |
642 | return IsActive; | 639 | } |
640 | |||
641 | // BSActor.Release() | ||
642 | public override void Dispose() | ||
643 | { | ||
644 | VDetailLog("{0},Dispose", ControllingPrim.LocalID); | ||
645 | UnregisterForSceneEvents(); | ||
646 | Type = Vehicle.TYPE_NONE; | ||
647 | Enabled = false; | ||
648 | return; | ||
649 | } | ||
650 | |||
651 | private void RegisterForSceneEvents() | ||
652 | { | ||
653 | if (!m_haveRegisteredForSceneEvents) | ||
654 | { | ||
655 | m_physicsScene.BeforeStep += this.Step; | ||
656 | m_physicsScene.AfterStep += this.PostStep; | ||
657 | ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; | ||
658 | m_haveRegisteredForSceneEvents = true; | ||
659 | } | ||
660 | } | ||
661 | |||
662 | private void UnregisterForSceneEvents() | ||
663 | { | ||
664 | if (m_haveRegisteredForSceneEvents) | ||
665 | { | ||
666 | m_physicsScene.BeforeStep -= this.Step; | ||
667 | m_physicsScene.AfterStep -= this.PostStep; | ||
668 | ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; | ||
669 | m_haveRegisteredForSceneEvents = false; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | private void PreUpdateProperty(ref EntityProperties entprop) | ||
674 | { | ||
675 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
676 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
677 | if (IsActive) | ||
678 | { | ||
679 | entprop.RotationalVelocity = Vector3.Zero; | ||
680 | } | ||
643 | } | 681 | } |
644 | 682 | ||
645 | #region Known vehicle value functions | 683 | #region Known vehicle value functions |
@@ -661,7 +699,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
661 | private Vector3 m_knownRotationalVelocity; | 699 | private Vector3 m_knownRotationalVelocity; |
662 | private Vector3 m_knownRotationalForce; | 700 | private Vector3 m_knownRotationalForce; |
663 | private Vector3 m_knownRotationalImpulse; | 701 | private Vector3 m_knownRotationalImpulse; |
664 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed | ||
665 | 702 | ||
666 | private const int m_knownChangedPosition = 1 << 0; | 703 | private const int m_knownChangedPosition = 1 << 0; |
667 | private const int m_knownChangedVelocity = 1 << 1; | 704 | private const int m_knownChangedVelocity = 1 << 1; |
@@ -673,7 +710,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
673 | private const int m_knownChangedRotationalImpulse = 1 << 7; | 710 | private const int m_knownChangedRotationalImpulse = 1 << 7; |
674 | private const int m_knownChangedTerrainHeight = 1 << 8; | 711 | private const int m_knownChangedTerrainHeight = 1 << 8; |
675 | private const int m_knownChangedWaterLevel = 1 << 9; | 712 | private const int m_knownChangedWaterLevel = 1 << 9; |
676 | private const int m_knownChangedForwardVelocity = 1 <<10; | ||
677 | 713 | ||
678 | public void ForgetKnownVehicleProperties() | 714 | public void ForgetKnownVehicleProperties() |
679 | { | 715 | { |
@@ -686,14 +722,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
686 | if (m_knownChanged != 0) | 722 | if (m_knownChanged != 0) |
687 | { | 723 | { |
688 | if ((m_knownChanged & m_knownChangedPosition) != 0) | 724 | if ((m_knownChanged & m_knownChangedPosition) != 0) |
689 | Prim.ForcePosition = m_knownPosition; | 725 | ControllingPrim.ForcePosition = m_knownPosition; |
690 | 726 | ||
691 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | 727 | if ((m_knownChanged & m_knownChangedOrientation) != 0) |
692 | Prim.ForceOrientation = m_knownOrientation; | 728 | ControllingPrim.ForceOrientation = m_knownOrientation; |
693 | 729 | ||
694 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | 730 | if ((m_knownChanged & m_knownChangedVelocity) != 0) |
695 | { | 731 | { |
696 | Prim.ForceVelocity = m_knownVelocity; | 732 | ControllingPrim.ForceVelocity = m_knownVelocity; |
697 | // Fake out Bullet by making it think the velocity is the same as last time. | 733 | // Fake out Bullet by making it think the velocity is the same as last time. |
698 | // Bullet does a bunch of smoothing for changing parameters. | 734 | // Bullet does a bunch of smoothing for changing parameters. |
699 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | 735 | // Since the vehicle is demanding this setting, we override Bullet's smoothing |
@@ -702,41 +738,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
702 | } | 738 | } |
703 | 739 | ||
704 | if ((m_knownChanged & m_knownChangedForce) != 0) | 740 | if ((m_knownChanged & m_knownChangedForce) != 0) |
705 | Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); | 741 | ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); |
706 | 742 | ||
707 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | 743 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) |
708 | Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | 744 | ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); |
709 | 745 | ||
710 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | 746 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) |
711 | { | 747 | { |
712 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | 748 | ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; |
713 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | 749 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); |
714 | } | 750 | } |
715 | 751 | ||
716 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | 752 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) |
717 | Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | 753 | ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); |
718 | 754 | ||
719 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | 755 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) |
720 | { | 756 | { |
721 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | 757 | ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); |
722 | } | 758 | } |
723 | 759 | ||
724 | // If we set one of the values (ie, the physics engine didn't do it) we must force | 760 | // If we set one of the values (ie, the physics engine didn't do it) we must force |
725 | // an UpdateProperties event to send the changes up to the simulator. | 761 | // an UpdateProperties event to send the changes up to the simulator. |
726 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | 762 | m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); |
727 | } | 763 | } |
728 | m_knownChanged = 0; | 764 | m_knownChanged = 0; |
729 | } | 765 | } |
730 | 766 | ||
731 | // 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 |
732 | // 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. |
733 | Vector3 lastRememberedHeightPos; | 769 | Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1); |
734 | private float GetTerrainHeight(Vector3 pos) | 770 | private float GetTerrainHeight(Vector3 pos) |
735 | { | 771 | { |
736 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) | 772 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) |
737 | { | 773 | { |
738 | lastRememberedHeightPos = pos; | 774 | lastRememberedHeightPos = pos; |
739 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 775 | m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); |
740 | m_knownHas |= m_knownChangedTerrainHeight; | 776 | m_knownHas |= m_knownChangedTerrainHeight; |
741 | } | 777 | } |
742 | return m_knownTerrainHeight; | 778 | return m_knownTerrainHeight; |
@@ -744,14 +780,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
744 | 780 | ||
745 | // 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 |
746 | // 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); | ||
747 | private float GetWaterLevel(Vector3 pos) | 784 | private float GetWaterLevel(Vector3 pos) |
748 | { | 785 | { |
749 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | 786 | if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos) |
750 | { | 787 | { |
751 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | 788 | lastRememberedWaterHeightPos = pos; |
789 | m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
752 | m_knownHas |= m_knownChangedWaterLevel; | 790 | m_knownHas |= m_knownChangedWaterLevel; |
753 | } | 791 | } |
754 | return (float)m_knownWaterLevel; | 792 | return m_knownWaterLevel; |
755 | } | 793 | } |
756 | 794 | ||
757 | private Vector3 VehiclePosition | 795 | private Vector3 VehiclePosition |
@@ -760,7 +798,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
760 | { | 798 | { |
761 | if ((m_knownHas & m_knownChangedPosition) == 0) | 799 | if ((m_knownHas & m_knownChangedPosition) == 0) |
762 | { | 800 | { |
763 | m_knownPosition = Prim.ForcePosition; | 801 | m_knownPosition = ControllingPrim.ForcePosition; |
764 | m_knownHas |= m_knownChangedPosition; | 802 | m_knownHas |= m_knownChangedPosition; |
765 | } | 803 | } |
766 | return m_knownPosition; | 804 | return m_knownPosition; |
@@ -779,7 +817,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
779 | { | 817 | { |
780 | if ((m_knownHas & m_knownChangedOrientation) == 0) | 818 | if ((m_knownHas & m_knownChangedOrientation) == 0) |
781 | { | 819 | { |
782 | m_knownOrientation = Prim.ForceOrientation; | 820 | m_knownOrientation = ControllingPrim.ForceOrientation; |
783 | m_knownHas |= m_knownChangedOrientation; | 821 | m_knownHas |= m_knownChangedOrientation; |
784 | } | 822 | } |
785 | return m_knownOrientation; | 823 | return m_knownOrientation; |
@@ -798,7 +836,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
798 | { | 836 | { |
799 | if ((m_knownHas & m_knownChangedVelocity) == 0) | 837 | if ((m_knownHas & m_knownChangedVelocity) == 0) |
800 | { | 838 | { |
801 | m_knownVelocity = Prim.ForceVelocity; | 839 | m_knownVelocity = ControllingPrim.ForceVelocity; |
802 | m_knownHas |= m_knownChangedVelocity; | 840 | m_knownHas |= m_knownChangedVelocity; |
803 | } | 841 | } |
804 | return m_knownVelocity; | 842 | return m_knownVelocity; |
@@ -839,7 +877,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
839 | { | 877 | { |
840 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | 878 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) |
841 | { | 879 | { |
842 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | 880 | m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; |
843 | m_knownHas |= m_knownChangedRotationalVelocity; | 881 | m_knownHas |= m_knownChangedRotationalVelocity; |
844 | } | 882 | } |
845 | return (Vector3)m_knownRotationalVelocity; | 883 | return (Vector3)m_knownRotationalVelocity; |
@@ -877,14 +915,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
877 | { | 915 | { |
878 | get | 916 | get |
879 | { | 917 | { |
880 | if ((m_knownHas & m_knownChangedForwardVelocity) == 0) | 918 | return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); |
881 | { | ||
882 | m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation)); | ||
883 | m_knownHas |= m_knownChangedForwardVelocity; | ||
884 | } | ||
885 | return m_knownForwardVelocity; | ||
886 | } | 919 | } |
887 | } | 920 | } |
921 | |||
888 | private float VehicleForwardSpeed | 922 | private float VehicleForwardSpeed |
889 | { | 923 | { |
890 | get | 924 | get |
@@ -914,11 +948,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
914 | // for the physics engine to note the changes so an UpdateProperties event will happen. | 948 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
915 | PushKnownChanged(); | 949 | PushKnownChanged(); |
916 | 950 | ||
917 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 951 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
918 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 952 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
919 | 953 | ||
920 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", | 954 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", |
921 | Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); | 955 | ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); |
922 | } | 956 | } |
923 | 957 | ||
924 | // Called after the simulation step | 958 | // Called after the simulation step |
@@ -926,8 +960,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
926 | { | 960 | { |
927 | if (!IsActive) return; | 961 | if (!IsActive) return; |
928 | 962 | ||
929 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 963 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
930 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 964 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
931 | } | 965 | } |
932 | 966 | ||
933 | // Apply the effect of the linear motor and other linear motions (like hover and float). | 967 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
@@ -935,6 +969,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
935 | { | 969 | { |
936 | ComputeLinearVelocity(pTimestep); | 970 | ComputeLinearVelocity(pTimestep); |
937 | 971 | ||
972 | ComputeLinearDeflection(pTimestep); | ||
973 | |||
938 | ComputeLinearTerrainHeightCorrection(pTimestep); | 974 | ComputeLinearTerrainHeightCorrection(pTimestep); |
939 | 975 | ||
940 | ComputeLinearHover(pTimestep); | 976 | ComputeLinearHover(pTimestep); |
@@ -950,11 +986,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
950 | { | 986 | { |
951 | Vector3 vel = VehicleVelocity; | 987 | Vector3 vel = VehicleVelocity; |
952 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | 988 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
989 | { | ||
953 | vel.X = 0; | 990 | vel.X = 0; |
991 | } | ||
954 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | 992 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) |
993 | { | ||
955 | vel.Y = 0; | 994 | vel.Y = 0; |
995 | } | ||
956 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | 996 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) |
997 | { | ||
957 | vel.Z = 0; | 998 | vel.Z = 0; |
999 | } | ||
958 | VehicleVelocity = vel; | 1000 | VehicleVelocity = vel; |
959 | } | 1001 | } |
960 | 1002 | ||
@@ -966,13 +1008,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
966 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | 1008 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG |
967 | VehicleVelocity /= VehicleVelocity.Length(); | 1009 | VehicleVelocity /= VehicleVelocity.Length(); |
968 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | 1010 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; |
969 | 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}", |
970 | Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | 1012 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); |
971 | } | 1013 | } |
972 | else if (newVelocityLengthSq < 0.001f) | 1014 | else if (newVelocityLengthSq < 0.001f) |
973 | VehicleVelocity = Vector3.Zero; | 1015 | VehicleVelocity = Vector3.Zero; |
974 | 1016 | ||
975 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity ); | 1017 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity ); |
976 | 1018 | ||
977 | } // end MoveLinear() | 1019 | } // end MoveLinear() |
978 | 1020 | ||
@@ -980,9 +1022,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
980 | { | 1022 | { |
981 | // 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. |
982 | Vector3 origVelW = VehicleVelocity; // DEBUG | 1024 | Vector3 origVelW = VehicleVelocity; // DEBUG |
983 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); | 1025 | Vector3 currentVelV = VehicleForwardVelocity; |
984 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); | 1026 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); |
985 | 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 | |||
986 | // Motor is vehicle coordinates. Rotate it to world coordinates | 1032 | // Motor is vehicle coordinates. Rotate it to world coordinates |
987 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; | 1033 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; |
988 | 1034 | ||
@@ -996,8 +1042,49 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
996 | // Add this correction to the velocity to make it faster/slower. | 1042 | // Add this correction to the velocity to make it faster/slower. |
997 | VehicleVelocity += linearMotorVelocityW; | 1043 | VehicleVelocity += linearMotorVelocityW; |
998 | 1044 | ||
999 | 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}", |
1000 | Prim.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 | } | ||
1001 | } | 1088 | } |
1002 | 1089 | ||
1003 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | 1090 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) |
@@ -1011,7 +1098,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1011 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | 1098 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
1012 | VehiclePosition = newPosition; | 1099 | VehiclePosition = newPosition; |
1013 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | 1100 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", |
1014 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | 1101 | ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
1015 | } | 1102 | } |
1016 | } | 1103 | } |
1017 | 1104 | ||
@@ -1034,14 +1121,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1034 | { | 1121 | { |
1035 | m_VhoverTargetHeight = m_VhoverHeight; | 1122 | m_VhoverTargetHeight = m_VhoverHeight; |
1036 | } | 1123 | } |
1037 | |||
1038 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 1124 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
1039 | { | 1125 | { |
1040 | // If body is already heigher, use its height as target height | 1126 | // If body is already heigher, use its height as target height |
1041 | if (VehiclePosition.Z > m_VhoverTargetHeight) | 1127 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
1042 | m_VhoverTargetHeight = VehiclePosition.Z; | 1128 | m_VhoverTargetHeight = VehiclePosition.Z; |
1043 | } | 1129 | } |
1044 | 1130 | ||
1045 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 1131 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
1046 | { | 1132 | { |
1047 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | 1133 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
@@ -1050,7 +1136,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1050 | pos.Z = m_VhoverTargetHeight; | 1136 | pos.Z = m_VhoverTargetHeight; |
1051 | VehiclePosition = pos; | 1137 | VehiclePosition = pos; |
1052 | 1138 | ||
1053 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos); | 1139 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); |
1054 | } | 1140 | } |
1055 | } | 1141 | } |
1056 | else | 1142 | else |
@@ -1079,11 +1165,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1079 | */ | 1165 | */ |
1080 | 1166 | ||
1081 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", | 1167 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", |
1082 | Prim.LocalID, VehiclePosition, m_VhoverEfficiency, | 1168 | ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, |
1083 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | 1169 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, |
1084 | verticalError, verticalCorrection); | 1170 | verticalError, verticalCorrection); |
1085 | } | 1171 | } |
1086 | |||
1087 | } | 1172 | } |
1088 | } | 1173 | } |
1089 | 1174 | ||
@@ -1124,7 +1209,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1124 | { | 1209 | { |
1125 | VehiclePosition = pos; | 1210 | VehiclePosition = pos; |
1126 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1211 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
1127 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1212 | ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); |
1128 | } | 1213 | } |
1129 | } | 1214 | } |
1130 | return changed; | 1215 | return changed; |
@@ -1135,7 +1220,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1135 | // used with conjunction with banking: the strength of the banking will decay when the | 1220 | // used with conjunction with banking: the strength of the banking will decay when the |
1136 | // vehicle no longer experiences collisions. The decay timescale is the same as | 1221 | // vehicle no longer experiences collisions. The decay timescale is the same as |
1137 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | 1222 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering |
1138 | // when they are in mid jump. | 1223 | // when they are in mid jump. |
1139 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | 1224 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? |
1140 | // This is just using the ground and a general collision check. Should really be using | 1225 | // This is just using the ground and a general collision check. Should really be using |
1141 | // a downward raycast to find what is below. | 1226 | // a downward raycast to find what is below. |
@@ -1148,7 +1233,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1148 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); | 1233 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
1149 | distanceAboveGround = VehiclePosition.Z - targetHeight; | 1234 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
1150 | // Not colliding if the vehicle is off the ground | 1235 | // Not colliding if the vehicle is off the ground |
1151 | if (!Prim.IsColliding) | 1236 | if (!Prim.HasSomeCollision) |
1152 | { | 1237 | { |
1153 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1238 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
1154 | VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); | 1239 | VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); |
@@ -1159,12 +1244,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1159 | // be computed with a motor. | 1244 | // be computed with a motor. |
1160 | // TODO: add interaction with banking. | 1245 | // TODO: add interaction with banking. |
1161 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", | 1246 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", |
1162 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); | 1247 | Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret); |
1163 | */ | 1248 | */ |
1164 | 1249 | ||
1165 | // Another approach is to measure if we're going up. If going up and not colliding, | 1250 | // Another approach is to measure if we're going up. If going up and not colliding, |
1166 | // the vehicle is in the air. Fix that by pushing down. | 1251 | // the vehicle is in the air. Fix that by pushing down. |
1167 | if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) | 1252 | if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1) |
1168 | { | 1253 | { |
1169 | // Get rid of any of the velocity vector that is pushing us up. | 1254 | // Get rid of any of the velocity vector that is pushing us up. |
1170 | float upVelocity = VehicleVelocity.Z; | 1255 | float upVelocity = VehicleVelocity.Z; |
@@ -1186,7 +1271,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1186 | } | 1271 | } |
1187 | */ | 1272 | */ |
1188 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | 1273 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", |
1189 | Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); | 1274 | ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity); |
1190 | } | 1275 | } |
1191 | } | 1276 | } |
1192 | } | 1277 | } |
@@ -1196,14 +1281,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1196 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; | 1281 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; |
1197 | 1282 | ||
1198 | // Hack to reduce downward force if the vehicle is probably sitting on the ground | 1283 | // Hack to reduce downward force if the vehicle is probably sitting on the ground |
1199 | if (Prim.IsColliding && IsGroundVehicle) | 1284 | if (ControllingPrim.HasSomeCollision && IsGroundVehicle) |
1200 | appliedGravity *= BSParam.VehicleGroundGravityFudge; | 1285 | appliedGravity *= BSParam.VehicleGroundGravityFudge; |
1201 | 1286 | ||
1202 | VehicleAddForce(appliedGravity); | 1287 | VehicleAddForce(appliedGravity); |
1203 | 1288 | ||
1204 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", | 1289 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}", |
1205 | Prim.LocalID, m_VehicleGravity, | 1290 | ControllingPrim.LocalID, m_VehicleGravity, |
1206 | Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | 1291 | ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); |
1207 | } | 1292 | } |
1208 | 1293 | ||
1209 | // ======================================================================= | 1294 | // ======================================================================= |
@@ -1227,11 +1312,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1227 | { | 1312 | { |
1228 | // The vehicle is not adding anything angular wise. | 1313 | // The vehicle is not adding anything angular wise. |
1229 | VehicleRotationalVelocity = Vector3.Zero; | 1314 | VehicleRotationalVelocity = Vector3.Zero; |
1230 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | 1315 | VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); |
1231 | } | 1316 | } |
1232 | else | 1317 | else |
1233 | { | 1318 | { |
1234 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity); | 1319 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); |
1235 | } | 1320 | } |
1236 | 1321 | ||
1237 | // ================================================================== | 1322 | // ================================================================== |
@@ -1262,7 +1347,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1262 | torqueFromOffset.Z = 0; | 1347 | torqueFromOffset.Z = 0; |
1263 | 1348 | ||
1264 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | 1349 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1265 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1350 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); |
1266 | } | 1351 | } |
1267 | 1352 | ||
1268 | } | 1353 | } |
@@ -1270,6 +1355,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1270 | private void ComputeAngularTurning(float pTimestep) | 1355 | private void ComputeAngularTurning(float pTimestep) |
1271 | { | 1356 | { |
1272 | // The user wants this many radians per second angular change? | 1357 | // The user wants this many radians per second angular change? |
1358 | Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1273 | Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); | 1359 | Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); |
1274 | Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); | 1360 | Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); |
1275 | 1361 | ||
@@ -1277,18 +1363,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1277 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | 1363 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
1278 | // This flag prevents linear deflection parallel to world z-axis. This is useful | 1364 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
1279 | // for preventing ground vehicles with large linear deflection, like bumper cars, | 1365 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
1280 | // from climbing their linear deflection into the sky. | 1366 | // from climbing their linear deflection into the sky. |
1281 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | 1367 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement |
1282 | // TODO: This is here because this is where ODE put it but documentation says it | 1368 | // TODO: This is here because this is where ODE put it but documentation says it |
1283 | // is a linear effect. Where should this check go? | 1369 | // is a linear effect. Where should this check go? |
1284 | //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1370 | //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
1285 | // { | 1371 | // { |
1286 | // angularMotorContributionV.X = 0f; | 1372 | // angularMotorContributionV.X = 0f; |
1287 | // angularMotorContributionV.Y = 0f; | 1373 | // angularMotorContributionV.Y = 0f; |
1288 | // } | 1374 | // } |
1289 | 1375 | ||
1290 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; | 1376 | // Reduce any velocity by friction. |
1291 | VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); | 1377 | Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); |
1378 | angularMotorContributionV -= (currentAngularV * frictionFactorW); | ||
1379 | |||
1380 | Vector3 angularMotorContributionW = angularMotorContributionV * VehicleOrientation; | ||
1381 | VehicleRotationalVelocity += angularMotorContributionW; | ||
1382 | |||
1383 | VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}", | ||
1384 | ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW); | ||
1292 | } | 1385 | } |
1293 | 1386 | ||
1294 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | 1387 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
@@ -1303,86 +1396,136 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1303 | { | 1396 | { |
1304 | 1397 | ||
1305 | // If vertical attaction timescale is reasonable | 1398 | // If vertical attaction timescale is reasonable |
1306 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1399 | if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1307 | { | 1400 | { |
1308 | // Possible solution derived from a discussion at: | 1401 | Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleOrientation; |
1309 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | 1402 | switch (BSParam.VehicleAngularVerticalAttractionAlgorithm) |
1310 | |||
1311 | // Create a rotation that is only the vehicle's rotation around Z | ||
1312 | Vector3 currentEuler = Vector3.Zero; | ||
1313 | VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); | ||
1314 | Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); | ||
1315 | |||
1316 | // Create the axis that is perpendicular to the up vector and the rotated up vector. | ||
1317 | Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); | ||
1318 | // Compute the angle between those to vectors. | ||
1319 | double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); | ||
1320 | // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical | ||
1321 | |||
1322 | // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. | ||
1323 | // TODO: add 'efficiency'. | ||
1324 | differenceAngle /= m_verticalAttractionTimescale; | ||
1325 | |||
1326 | // Create the quaterian representing the correction angle | ||
1327 | Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); | ||
1328 | |||
1329 | // Turn that quaternion into Euler values to make it into velocities to apply. | ||
1330 | Vector3 vertContributionV = Vector3.Zero; | ||
1331 | correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); | ||
1332 | vertContributionV *= -1f; | ||
1333 | |||
1334 | VehicleRotationalVelocity += vertContributionV; | ||
1335 | |||
1336 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", | ||
1337 | Prim.LocalID, | ||
1338 | differenceAxis, | ||
1339 | differenceAngle, | ||
1340 | correctionRotation, | ||
1341 | vertContributionV); | ||
1342 | |||
1343 | // =================================================================== | ||
1344 | /* | ||
1345 | Vector3 vertContributionV = Vector3.Zero; | ||
1346 | Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1347 | |||
1348 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
1349 | Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); | ||
1350 | |||
1351 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1352 | // is now: | ||
1353 | // leaning to one side: rotated around the X axis with the Y value going | ||
1354 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1355 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1356 | // zero and one. | ||
1357 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1358 | |||
1359 | // Y error means needed rotation around X axis and visa versa. | ||
1360 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1361 | vertContributionV.X = (float)Math.Asin(verticalError.Y); | ||
1362 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1363 | vertContributionV.Y = -(float)Math.Asin(verticalError.X); | ||
1364 | |||
1365 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1366 | if (verticalError.Z < 0f) | ||
1367 | { | 1403 | { |
1368 | vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; | 1404 | case 0: |
1369 | // vertContribution.Y -= PIOverFour; | 1405 | { |
1406 | //Another formula to try got from : | ||
1407 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1408 | |||
1409 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1410 | // since only computing half the distance between the angles. | ||
1411 | float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1412 | |||
1413 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1414 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1415 | Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1416 | |||
1417 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1418 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1419 | |||
1420 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1421 | Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed; | ||
1422 | |||
1423 | VehicleRotationalVelocity += vertContributionV; | ||
1424 | |||
1425 | VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}", | ||
1426 | ControllingPrim.LocalID, | ||
1427 | verticalAttractionSpeed, | ||
1428 | vehicleUpAxis, | ||
1429 | predictedUp, | ||
1430 | torqueVector, | ||
1431 | vertContributionV); | ||
1432 | break; | ||
1433 | } | ||
1434 | case 1: | ||
1435 | { | ||
1436 | // Possible solution derived from a discussion at: | ||
1437 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | ||
1438 | |||
1439 | // Create a rotation that is only the vehicle's rotation around Z | ||
1440 | Vector3 currentEulerW = Vector3.Zero; | ||
1441 | VehicleOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z); | ||
1442 | Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z); | ||
1443 | |||
1444 | // Create the axis that is perpendicular to the up vector and the rotated up vector. | ||
1445 | Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); | ||
1446 | // Compute the angle between those to vectors. | ||
1447 | double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); | ||
1448 | // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical | ||
1449 | |||
1450 | // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. | ||
1451 | // TODO: add 'efficiency'. | ||
1452 | // differenceAngle /= m_verticalAttractionTimescale; | ||
1453 | |||
1454 | // Create the quaterian representing the correction angle | ||
1455 | Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle); | ||
1456 | |||
1457 | // Turn that quaternion into Euler values to make it into velocities to apply. | ||
1458 | Vector3 vertContributionW = Vector3.Zero; | ||
1459 | correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z); | ||
1460 | vertContributionW *= -1f; | ||
1461 | vertContributionW /= m_verticalAttractionTimescale; | ||
1462 | |||
1463 | VehicleRotationalVelocity += vertContributionW; | ||
1464 | |||
1465 | VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", | ||
1466 | ControllingPrim.LocalID, | ||
1467 | vehicleUpAxis, | ||
1468 | differenceAxisW, | ||
1469 | differenceAngle, | ||
1470 | correctionRotationW, | ||
1471 | vertContributionW); | ||
1472 | break; | ||
1473 | } | ||
1474 | case 2: | ||
1475 | { | ||
1476 | Vector3 vertContributionV = Vector3.Zero; | ||
1477 | Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1478 | |||
1479 | // Take a vector pointing up and convert it from world to vehicle relative coords. | ||
1480 | Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); | ||
1481 | |||
1482 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1483 | // is now: | ||
1484 | // leaning to one side: rotated around the X axis with the Y value going | ||
1485 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1486 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1487 | // zero and one. | ||
1488 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1489 | |||
1490 | // Y error means needed rotation around X axis and visa versa. | ||
1491 | // Since the error goes from zero to one, the asin is the corresponding angle. | ||
1492 | vertContributionV.X = (float)Math.Asin(verticalError.Y); | ||
1493 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | ||
1494 | vertContributionV.Y = -(float)Math.Asin(verticalError.X); | ||
1495 | |||
1496 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1497 | if (verticalError.Z < 0f) | ||
1498 | { | ||
1499 | vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; | ||
1500 | // vertContribution.Y -= PIOverFour; | ||
1501 | } | ||
1502 | |||
1503 | // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. | ||
1504 | // Correction happens over a number of seconds. | ||
1505 | Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG | ||
1506 | |||
1507 | // The correction happens over the user's time period | ||
1508 | vertContributionV /= m_verticalAttractionTimescale; | ||
1509 | |||
1510 | // Rotate the vehicle rotation to the world coordinates. | ||
1511 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); | ||
1512 | |||
1513 | VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}", | ||
1514 | ControllingPrim.LocalID, | ||
1515 | vehicleUpAxis, | ||
1516 | origRotVelW, | ||
1517 | verticalError, | ||
1518 | unscaledContribVerticalErrorV, | ||
1519 | m_verticalAttractionEfficiency, | ||
1520 | m_verticalAttractionTimescale, | ||
1521 | vertContributionV); | ||
1522 | break; | ||
1523 | } | ||
1524 | default: | ||
1525 | { | ||
1526 | break; | ||
1527 | } | ||
1370 | } | 1528 | } |
1371 | |||
1372 | // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. | ||
1373 | // Correction happens over a number of seconds. | ||
1374 | Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG | ||
1375 | |||
1376 | // The correction happens over the user's time period | ||
1377 | vertContributionV /= m_verticalAttractionTimescale; | ||
1378 | |||
1379 | // Rotate the vehicle rotation to the world coordinates. | ||
1380 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); | ||
1381 | |||
1382 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", | ||
1383 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, | ||
1384 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); | ||
1385 | */ | ||
1386 | } | 1529 | } |
1387 | } | 1530 | } |
1388 | 1531 | ||
@@ -1392,13 +1535,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1392 | // in that direction. | 1535 | // in that direction. |
1393 | // TODO: implement reference frame. | 1536 | // TODO: implement reference frame. |
1394 | public void ComputeAngularDeflection() | 1537 | public void ComputeAngularDeflection() |
1395 | { | 1538 | { |
1396 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | ||
1397 | // approximately the same X or Y correction. When added together (when contributions are combined) | ||
1398 | // this creates an over-correction and then wabbling as the target is overshot. | ||
1399 | // TODO: rethink how the different correction computations inter-relate. | ||
1400 | 1539 | ||
1401 | if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) | 1540 | if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) |
1402 | { | 1541 | { |
1403 | Vector3 deflectContributionV = Vector3.Zero; | 1542 | Vector3 deflectContributionV = Vector3.Zero; |
1404 | 1543 | ||
@@ -1411,10 +1550,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1411 | 1550 | ||
1412 | // The direction the vehicle is pointing | 1551 | // The direction the vehicle is pointing |
1413 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | 1552 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; |
1414 | pointingDirection.Normalize(); | 1553 | //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep |
1554 | // from overshooting and allow this correction to merge with the Vertical Attraction peacefully. | ||
1555 | Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1556 | predictedPointingDirection.Normalize(); | ||
1415 | 1557 | ||
1416 | // The difference between what is and what should be. | 1558 | // The difference between what is and what should be. |
1417 | Vector3 deflectionError = movingDirection - pointingDirection; | 1559 | // Vector3 deflectionError = movingDirection - predictedPointingDirection; |
1560 | Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection); | ||
1418 | 1561 | ||
1419 | // Don't try to correct very large errors (not our job) | 1562 | // Don't try to correct very large errors (not our job) |
1420 | // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); | 1563 | // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); |
@@ -1427,15 +1570,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1427 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | 1570 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); |
1428 | 1571 | ||
1429 | // Scale the correction by recovery timescale and efficiency | 1572 | // Scale the correction by recovery timescale and efficiency |
1430 | deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; | 1573 | // Not modeling a spring so clamp the scale to no more then the arc |
1431 | deflectContributionV /= m_angularDeflectionTimescale; | 1574 | deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f); |
1432 | 1575 | //deflectContributionV /= m_angularDeflectionTimescale; | |
1433 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | ||
1434 | 1576 | ||
1577 | // VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | ||
1578 | VehicleRotationalVelocity += deflectContributionV; | ||
1435 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | 1579 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", |
1436 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); | 1580 | ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); |
1437 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | 1581 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}", |
1438 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | 1582 | ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection); |
1439 | } | 1583 | } |
1440 | } | 1584 | } |
1441 | 1585 | ||
@@ -1447,13 +1591,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1447 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | 1591 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude |
1448 | // of the yaw effect will be proportional to the | 1592 | // of the yaw effect will be proportional to the |
1449 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | 1593 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's |
1450 | // velocity along its preferred axis of motion. | 1594 | // velocity along its preferred axis of motion. |
1451 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | 1595 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any |
1452 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | 1596 | // positive rotation (by the right-hand rule) about the roll-axis will effect a |
1453 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | 1597 | // (negative) torque around the yaw-axis, making it turn to the right--that is the |
1454 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | 1598 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. |
1455 | // Negating the banking coefficient will make it so that the vehicle leans to the | 1599 | // Negating the banking coefficient will make it so that the vehicle leans to the |
1456 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | 1600 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). |
1457 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | 1601 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making |
1458 | // banking vehicles do what you want rather than what the laws of physics allow. | 1602 | // banking vehicles do what you want rather than what the laws of physics allow. |
1459 | // For example, consider a real motorcycle...it must be moving forward in order for | 1603 | // For example, consider a real motorcycle...it must be moving forward in order for |
@@ -1465,14 +1609,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1465 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | 1609 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the |
1466 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | 1610 | // banking effect depends only on the vehicle's rotation about its roll-axis compared |
1467 | // to "dynamic" where the banking is also proportional to its velocity along its | 1611 | // to "dynamic" where the banking is also proportional to its velocity along its |
1468 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | 1612 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. |
1469 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | 1613 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the |
1470 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | 1614 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to |
1471 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | 1615 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can |
1472 | // make a sluggish vehicle by giving it a timescale of several seconds. | 1616 | // make a sluggish vehicle by giving it a timescale of several seconds. |
1473 | public void ComputeAngularBanking() | 1617 | public void ComputeAngularBanking() |
1474 | { | 1618 | { |
1475 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1619 | if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1476 | { | 1620 | { |
1477 | Vector3 bankingContributionV = Vector3.Zero; | 1621 | Vector3 bankingContributionV = Vector3.Zero; |
1478 | 1622 | ||
@@ -1498,10 +1642,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1498 | 1642 | ||
1499 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; | 1643 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; |
1500 | VehicleRotationalVelocity += bankingContributionV; | 1644 | VehicleRotationalVelocity += bankingContributionV; |
1501 | 1645 | ||
1502 | 1646 | ||
1503 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", | 1647 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", |
1504 | Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); | 1648 | ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); |
1505 | } | 1649 | } |
1506 | } | 1650 | } |
1507 | 1651 | ||
@@ -1540,8 +1684,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1540 | if (rotq != m_rot) | 1684 | if (rotq != m_rot) |
1541 | { | 1685 | { |
1542 | VehicleOrientation = m_rot; | 1686 | VehicleOrientation = m_rot; |
1543 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1687 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); |
1688 | } | ||
1689 | |||
1690 | } | ||
1691 | |||
1692 | // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce | ||
1693 | // some value by to apply this friction. | ||
1694 | private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) | ||
1695 | { | ||
1696 | Vector3 frictionFactor = Vector3.Zero; | ||
1697 | if (friction != BSMotor.InfiniteVector) | ||
1698 | { | ||
1699 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
1700 | // Individual friction components can be 'infinite' so compute each separately. | ||
1701 | frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); | ||
1702 | frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); | ||
1703 | frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); | ||
1704 | frictionFactor *= pTimestep; | ||
1705 | } | ||
1706 | return frictionFactor; | ||
1707 | } | ||
1708 | |||
1709 | private float SortedClampInRange(float clampa, float val, float clampb) | ||
1710 | { | ||
1711 | if (clampa > clampb) | ||
1712 | { | ||
1713 | float temp = clampa; | ||
1714 | clampa = clampb; | ||
1715 | clampb = temp; | ||
1544 | } | 1716 | } |
1717 | return ClampInRange(clampa, val, clampb); | ||
1545 | 1718 | ||
1546 | } | 1719 | } |
1547 | 1720 | ||
@@ -1554,8 +1727,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1554 | // Invoke the detailed logger and output something if it's enabled. | 1727 | // Invoke the detailed logger and output something if it's enabled. |
1555 | private void VDetailLog(string msg, params Object[] args) | 1728 | private void VDetailLog(string msg, params Object[] args) |
1556 | { | 1729 | { |
1557 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 1730 | if (ControllingPrim.PhysScene.VehicleLoggingEnabled) |
1558 | Prim.PhysicsScene.DetailLog(msg, args); | 1731 | ControllingPrim.PhysScene.DetailLog(msg, args); |
1559 | } | 1732 | } |
1560 | } | 1733 | } |
1561 | } | 1734 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4ece1eb..3afd52e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -33,14 +33,6 @@ using OMV = OpenMetaverse; | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace 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. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
44 | public abstract class BSLinkset | 36 | public 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,33 @@ 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 | } | ||
81 | |||
82 | public LinksetImplementation LinksetImpl { get; protected set; } | ||
83 | |||
81 | public BSPrimLinkable LinksetRoot { get; protected set; } | 84 | public BSPrimLinkable LinksetRoot { get; protected set; } |
82 | 85 | ||
83 | public BSScene PhysicsScene { get; private set; } | 86 | protected BSScene m_physicsScene { get; private set; } |
84 | 87 | ||
85 | static int m_nextLinksetID = 1; | 88 | static int m_nextLinksetID = 1; |
86 | public int LinksetID { get; private set; } | 89 | public int LinksetID { get; private set; } |
87 | 90 | ||
88 | // The children under the root in this linkset. | 91 | // The children under the root in this linkset. |
89 | protected HashSet<BSPrimLinkable> m_children; | 92 | // protected HashSet<BSPrimLinkable> m_children; |
93 | protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children; | ||
90 | 94 | ||
91 | // We lock the diddling of linkset classes to prevent any badness. | 95 | // We lock the diddling of linkset classes to prevent any badness. |
92 | // This locks the modification of the instances of this class. Changes | 96 | // This locks the modification of the instances of this class. Changes |
93 | // to the physical representation is done via the tainting mechenism. | 97 | // to the physical representation is done via the tainting mechenism. |
94 | protected object m_linksetActivityLock = new Object(); | 98 | protected object m_linksetActivityLock = new Object(); |
95 | 99 | ||
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 | 100 | // 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; } | 101 | public float LinksetMass { get; protected set; } |
105 | 102 | ||
@@ -122,9 +119,9 @@ public abstract class BSLinkset | |||
122 | // We create LOTS of linksets. | 119 | // We create LOTS of linksets. |
123 | if (m_nextLinksetID <= 0) | 120 | if (m_nextLinksetID <= 0) |
124 | m_nextLinksetID = 1; | 121 | m_nextLinksetID = 1; |
125 | PhysicsScene = scene; | 122 | m_physicsScene = scene; |
126 | LinksetRoot = parent; | 123 | LinksetRoot = parent; |
127 | m_children = new HashSet<BSPrimLinkable>(); | 124 | m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>(); |
128 | LinksetMass = parent.RawMass; | 125 | LinksetMass = parent.RawMass; |
129 | Rebuilding = false; | 126 | Rebuilding = false; |
130 | 127 | ||
@@ -165,7 +162,7 @@ public abstract class BSLinkset | |||
165 | } | 162 | } |
166 | 163 | ||
167 | // The child is down to a linkset of just itself | 164 | // The child is down to a linkset of just itself |
168 | return BSLinkset.Factory(PhysicsScene, child); | 165 | return BSLinkset.Factory(m_physicsScene, child); |
169 | } | 166 | } |
170 | 167 | ||
171 | // Return 'true' if the passed object is the root object of this linkset | 168 | // Return 'true' if the passed object is the root object of this linkset |
@@ -185,17 +182,7 @@ public abstract class BSLinkset | |||
185 | bool ret = false; | 182 | bool ret = false; |
186 | lock (m_linksetActivityLock) | 183 | lock (m_linksetActivityLock) |
187 | { | 184 | { |
188 | ret = m_children.Contains(child); | 185 | 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 | } | 186 | } |
200 | return ret; | 187 | return ret; |
201 | } | 188 | } |
@@ -209,7 +196,24 @@ public abstract class BSLinkset | |||
209 | lock (m_linksetActivityLock) | 196 | lock (m_linksetActivityLock) |
210 | { | 197 | { |
211 | action(LinksetRoot); | 198 | action(LinksetRoot); |
212 | foreach (BSPrimLinkable po in m_children) | 199 | foreach (BSPrimLinkable po in m_children.Keys) |
200 | { | ||
201 | if (action(po)) | ||
202 | break; | ||
203 | } | ||
204 | } | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | // Perform an action on each member of the linkset including root prim. | ||
209 | // Depends on the action on whether this should be done at taint time. | ||
210 | public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); | ||
211 | public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) | ||
212 | { | ||
213 | bool ret = false; | ||
214 | lock (m_linksetActivityLock) | ||
215 | { | ||
216 | foreach (BSLinkInfo po in m_children.Values) | ||
213 | { | 217 | { |
214 | if (action(po)) | 218 | if (action(po)) |
215 | break; | 219 | break; |
@@ -218,10 +222,37 @@ public abstract class BSLinkset | |||
218 | return ret; | 222 | return ret; |
219 | } | 223 | } |
220 | 224 | ||
225 | // Called after a simulation step to post a collision with this object. | ||
226 | // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have | ||
227 | // anything to add for the collision and it should be passed through normal processing. | ||
228 | // Default processing for a linkset. | ||
229 | public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, | ||
230 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
231 | { | ||
232 | bool ret = false; | ||
233 | |||
234 | // prims in the same linkset cannot collide with each other | ||
235 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; | ||
236 | if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) | ||
237 | { | ||
238 | // By returning 'true', we tell the caller the collision has been 'handled' so it won't | ||
239 | // do anything about this collision and thus, effectivily, ignoring the collision. | ||
240 | ret = true; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | // Not a collision between members of the linkset. Must be a real collision. | ||
245 | // So the linkset root can know if there is a collision anywhere in the linkset. | ||
246 | LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; | ||
247 | } | ||
248 | |||
249 | return ret; | ||
250 | } | ||
251 | |||
221 | // I am the root of a linkset and a new child is being added | 252 | // I am the root of a linkset and a new child is being added |
222 | // Called while LinkActivity is locked. | 253 | // Called while LinkActivity is locked. |
223 | protected abstract void AddChildToLinkset(BSPrimLinkable child); | 254 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
224 | 255 | ||
225 | // I am the root of a linkset and one of my children is being removed. | 256 | // 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. | 257 | // Safe to call even if the child is not really in my linkset. |
227 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); | 258 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); |
@@ -263,8 +294,87 @@ public abstract class BSLinkset | |||
263 | // This is called when the root body is changing. | 294 | // This is called when the root body is changing. |
264 | // Returns 'true' of something was actually removed and would need restoring | 295 | // Returns 'true' of something was actually removed and would need restoring |
265 | // Called at taint-time!! | 296 | // Called at taint-time!! |
266 | public abstract bool RemoveBodyDependencies(BSPrimLinkable child); | 297 | public abstract bool RemoveDependencies(BSPrimLinkable child); |
298 | |||
299 | // ================================================================ | ||
300 | // Some physical setting happen to all members of the linkset | ||
301 | public virtual void SetPhysicalFriction(float friction) | ||
302 | { | ||
303 | ForEachMember((member) => | ||
304 | { | ||
305 | if (member.PhysBody.HasPhysicalBody) | ||
306 | m_physicsScene.PE.SetFriction(member.PhysBody, friction); | ||
307 | return false; // 'false' says to continue looping | ||
308 | } | ||
309 | ); | ||
310 | } | ||
311 | public virtual void SetPhysicalRestitution(float restitution) | ||
312 | { | ||
313 | ForEachMember((member) => | ||
314 | { | ||
315 | if (member.PhysBody.HasPhysicalBody) | ||
316 | m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); | ||
317 | return false; // 'false' says to continue looping | ||
318 | } | ||
319 | ); | ||
320 | } | ||
321 | public virtual void SetPhysicalGravity(OMV.Vector3 gravity) | ||
322 | { | ||
323 | ForEachMember((member) => | ||
324 | { | ||
325 | if (member.PhysBody.HasPhysicalBody) | ||
326 | m_physicsScene.PE.SetGravity(member.PhysBody, gravity); | ||
327 | return false; // 'false' says to continue looping | ||
328 | } | ||
329 | ); | ||
330 | } | ||
331 | public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) | ||
332 | { | ||
333 | ForEachMember((member) => | ||
334 | { | ||
335 | if (member.PhysBody.HasPhysicalBody) | ||
336 | { | ||
337 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); | ||
338 | member.Inertia = inertia * inertiaFactor; | ||
339 | m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); | ||
340 | m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); | ||
341 | DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); | ||
267 | 342 | ||
343 | } | ||
344 | return false; // 'false' says to continue looping | ||
345 | } | ||
346 | ); | ||
347 | } | ||
348 | public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) | ||
349 | { | ||
350 | ForEachMember((member) => | ||
351 | { | ||
352 | if (member.PhysBody.HasPhysicalBody) | ||
353 | m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); | ||
354 | return false; // 'false' says to continue looping | ||
355 | } | ||
356 | ); | ||
357 | } | ||
358 | public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) | ||
359 | { | ||
360 | ForEachMember((member) => | ||
361 | { | ||
362 | if (member.PhysBody.HasPhysicalBody) | ||
363 | m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); | ||
364 | return false; // 'false' says to continue looping | ||
365 | } | ||
366 | ); | ||
367 | } | ||
368 | public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
369 | { | ||
370 | ForEachMember((member) => | ||
371 | { | ||
372 | if (member.PhysBody.HasPhysicalBody) | ||
373 | m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); | ||
374 | return false; // 'false' says to continue looping | ||
375 | } | ||
376 | ); | ||
377 | } | ||
268 | // ================================================================ | 378 | // ================================================================ |
269 | protected virtual float ComputeLinksetMass() | 379 | protected virtual float ComputeLinksetMass() |
270 | { | 380 | { |
@@ -273,7 +383,7 @@ public abstract class BSLinkset | |||
273 | { | 383 | { |
274 | lock (m_linksetActivityLock) | 384 | lock (m_linksetActivityLock) |
275 | { | 385 | { |
276 | foreach (BSPrimLinkable bp in m_children) | 386 | foreach (BSPrimLinkable bp in m_children.Keys) |
277 | { | 387 | { |
278 | mass += bp.RawMass; | 388 | mass += bp.RawMass; |
279 | } | 389 | } |
@@ -291,7 +401,7 @@ public abstract class BSLinkset | |||
291 | com = LinksetRoot.Position * LinksetRoot.RawMass; | 401 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
292 | float totalMass = LinksetRoot.RawMass; | 402 | float totalMass = LinksetRoot.RawMass; |
293 | 403 | ||
294 | foreach (BSPrimLinkable bp in m_children) | 404 | foreach (BSPrimLinkable bp in m_children.Keys) |
295 | { | 405 | { |
296 | com += bp.Position * bp.RawMass; | 406 | com += bp.Position * bp.RawMass; |
297 | totalMass += bp.RawMass; | 407 | totalMass += bp.RawMass; |
@@ -310,7 +420,7 @@ public abstract class BSLinkset | |||
310 | { | 420 | { |
311 | com = LinksetRoot.Position; | 421 | com = LinksetRoot.Position; |
312 | 422 | ||
313 | foreach (BSPrimLinkable bp in m_children) | 423 | foreach (BSPrimLinkable bp in m_children.Keys) |
314 | { | 424 | { |
315 | com += bp.Position; | 425 | com += bp.Position; |
316 | } | 426 | } |
@@ -323,9 +433,8 @@ public abstract class BSLinkset | |||
323 | // Invoke the detailed logger and output something if it's enabled. | 433 | // Invoke the detailed logger and output something if it's enabled. |
324 | protected void DetailLog(string msg, params Object[] args) | 434 | protected void DetailLog(string msg, params Object[] args) |
325 | { | 435 | { |
326 | if (PhysicsScene.PhysicsLogging.Enabled) | 436 | if (m_physicsScene.PhysicsLogging.Enabled) |
327 | PhysicsScene.DetailLog(msg, args); | 437 | m_physicsScene.DetailLog(msg, args); |
328 | } | 438 | } |
329 | |||
330 | } | 439 | } |
331 | } | 440 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e05562a..085d195 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,81 +35,56 @@ using OMV = OpenMetaverse; | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | 37 | ||
38 | // When a child is linked, the relationship position of the child to the parent | 38 | public sealed class BSLinksetCompound : BSLinkset |
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed 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 | |||
92 | public 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 | } | 81 | } |
110 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | 82 | public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) |
111 | return ret; | 83 | { |
84 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
85 | m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
112 | } | 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. |
@@ -124,14 +99,15 @@ public sealed class BSLinksetCompound : BSLinkset | |||
124 | // Schedule a refresh to happen after all the other taint processing. | 99 | // Schedule a refresh to happen after all the other taint processing. |
125 | private void ScheduleRebuild(BSPrimLinkable requestor) | 100 | private void ScheduleRebuild(BSPrimLinkable requestor) |
126 | { | 101 | { |
127 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | 102 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
128 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | 103 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
104 | |||
129 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | 105 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
130 | // If already rebuilding, don't request another rebuild. | 106 | // 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. | 107 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. |
132 | if (!Rebuilding && HasAnyChildren) | 108 | if (!Rebuilding && HasAnyChildren) |
133 | { | 109 | { |
134 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 110 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
135 | { | 111 | { |
136 | if (HasAnyChildren) | 112 | if (HasAnyChildren) |
137 | RecomputeLinksetCompound(); | 113 | RecomputeLinksetCompound(); |
@@ -153,46 +129,23 @@ public sealed class BSLinksetCompound : BSLinkset | |||
153 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 129 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
154 | ScheduleRebuild(LinksetRoot); | 130 | ScheduleRebuild(LinksetRoot); |
155 | } | 131 | } |
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 | } | ||
169 | return ret; | 132 | return ret; |
170 | } | 133 | } |
171 | 134 | ||
172 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 135 | // 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. | 136 | // 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! | 137 | // Called at taint-time! |
177 | public override bool MakeStatic(BSPrimLinkable child) | 138 | public override bool MakeStatic(BSPrimLinkable child) |
178 | { | 139 | { |
179 | bool ret = false; | 140 | bool ret = false; |
141 | |||
180 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 142 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
143 | child.ClearDisplacement(); | ||
181 | if (IsRoot(child)) | 144 | if (IsRoot(child)) |
182 | { | 145 | { |
146 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
183 | ScheduleRebuild(LinksetRoot); | 147 | ScheduleRebuild(LinksetRoot); |
184 | } | 148 | } |
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 | } | ||
196 | return ret; | 149 | return ret; |
197 | } | 150 | } |
198 | 151 | ||
@@ -200,13 +153,20 @@ public sealed class BSLinksetCompound : BSLinkset | |||
200 | // Called at taint-time. | 153 | // Called at taint-time. |
201 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | 154 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) |
202 | { | 155 | { |
156 | if (!LinksetRoot.IsPhysicallyActive) | ||
157 | { | ||
158 | // No reason to do this physical stuff for static linksets. | ||
159 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
160 | return; | ||
161 | } | ||
162 | |||
203 | // The user moving a child around requires the rebuilding of the linkset compound shape | 163 | // 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 | 164 | // 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 | 165 | // stores the position into the group which causes the move of the object |
206 | // but it also means all the child positions get updated. | 166 | // 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 | 167 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
208 | // region before bothering to do a rebuild. | 168 | // region before bothering to do a rebuild. |
209 | if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | 169 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
210 | { | 170 | { |
211 | // If a child of the linkset is updating only the position or rotation, that can be done | 171 | // If a child of the linkset is updating only the position or rotation, that can be done |
212 | // without rebuilding the linkset. | 172 | // without rebuilding the linkset. |
@@ -218,22 +178,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
218 | // and that is caused by us updating the object. | 178 | // and that is caused by us updating the object. |
219 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | 179 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) |
220 | { | 180 | { |
221 | // Find the physical instance of the child | 181 | // Find the physical instance of the child |
222 | if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) | 182 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) |
223 | { | 183 | { |
224 | // It is possible that the linkset is still under construction and the child is not yet | 184 | // 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 | 185 | // 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. | 186 | // 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 | 187 | // The index must be checked because Bullet references the child array but does no validity |
228 | // checking of the child index passed. | 188 | // checking of the child index passed. |
229 | int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); | 189 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); |
230 | if (updated.LinksetChildIndex < numLinksetChildren) | 190 | if (updated.LinksetChildIndex < numLinksetChildren) |
231 | { | 191 | { |
232 | BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); | 192 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); |
233 | if (linksetChildShape.HasPhysicalShape) | 193 | if (linksetChildShape.HasPhysicalShape) |
234 | { | 194 | { |
235 | // Found the child shape within the compound shape | 195 | // Found the child shape within the compound shape |
236 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, | 196 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, |
237 | updated.RawPosition - LinksetRoot.RawPosition, | 197 | updated.RawPosition - LinksetRoot.RawPosition, |
238 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | 198 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), |
239 | true /* shouldRecalculateLocalAabb */); | 199 | true /* shouldRecalculateLocalAabb */); |
@@ -267,7 +227,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
267 | // there will already be a rebuild scheduled. | 227 | // there will already be a rebuild scheduled. |
268 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | 228 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", |
269 | updated.LocalID, whichUpdated); | 229 | updated.LocalID, whichUpdated); |
270 | updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. | ||
271 | ScheduleRebuild(updated); | 230 | ScheduleRebuild(updated); |
272 | } | 231 | } |
273 | } | 232 | } |
@@ -275,75 +234,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
275 | } | 234 | } |
276 | 235 | ||
277 | // Routine called when rebuilding the body of some member of the linkset. | 236 | // 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. | 237 | // If one of the bodies is being changed, the linkset needs rebuilding. |
238 | // 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 | 239 | // Returns 'true' of something was actually removed and would need restoring |
280 | // Called at taint-time!! | 240 | // Called at taint-time!! |
281 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 241 | public override bool RemoveDependencies(BSPrimLinkable child) |
282 | { | 242 | { |
283 | bool ret = false; | 243 | bool ret = false; |
284 | 244 | ||
285 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 245 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
286 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | 246 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
287 | 247 | ||
288 | if (!IsRoot(child)) | 248 | ScheduleRebuild(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 | 249 | ||
300 | return ret; | 250 | return ret; |
301 | } | 251 | } |
302 | 252 | ||
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 | // ================================================================ | 253 | // ================================================================ |
348 | 254 | ||
349 | // Add a new child to the linkset. | 255 | // Add a new child to the linkset. |
@@ -352,7 +258,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
352 | { | 258 | { |
353 | if (!HasChild(child)) | 259 | if (!HasChild(child)) |
354 | { | 260 | { |
355 | m_children.Add(child); | 261 | m_children.Add(child, new BSLinkInfo(child)); |
356 | 262 | ||
357 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 263 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
358 | 264 | ||
@@ -376,8 +282,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
376 | child.LocalID, child.PhysBody.AddrString); | 282 | child.LocalID, child.PhysBody.AddrString); |
377 | 283 | ||
378 | // Cause the child's body to be rebuilt and thus restored to normal operation | 284 | // Cause the child's body to be rebuilt and thus restored to normal operation |
379 | RecomputeChildWorldPosition(child, false); | ||
380 | child.LinksetInfo = null; | ||
381 | child.ForceBodyShapeRebuild(false); | 285 | child.ForceBodyShapeRebuild(false); |
382 | 286 | ||
383 | if (!HasAnyChildren) | 287 | if (!HasAnyChildren) |
@@ -399,108 +303,118 @@ public sealed class BSLinksetCompound : BSLinkset | |||
399 | // Constraint linksets are rebuilt every time. | 303 | // Constraint linksets are rebuilt every time. |
400 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 304 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
401 | // Called at taint time!! | 305 | // Called at taint time!! |
402 | private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged | 306 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape |
403 | private void RecomputeLinksetCompound() | 307 | private void RecomputeLinksetCompound() |
404 | { | 308 | { |
405 | try | 309 | try |
406 | { | 310 | { |
407 | // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) | ||
408 | Rebuilding = true; | 311 | Rebuilding = true; |
409 | 312 | ||
410 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 313 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set |
411 | LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); | 314 | // to what they should be as if the root was not in a linkset. |
315 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
316 | // something has been updated/changed. | ||
317 | // Have to do the rebuild before checking for physical because this might be a linkset | ||
318 | // being destructed and going non-physical. | ||
319 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
412 | 320 | ||
413 | // The center of mass for the linkset is the geometric center of the group. | 321 | // There is no reason to build all this physical stuff for a non-physical linkset. |
414 | // Compute a displacement for each component so it is relative to the center-of-mass. | 322 | if (!LinksetRoot.IsPhysicallyActive) |
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 | { | 323 | { |
419 | // Compute a center-of-mass in world coordinates. | 324 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); |
420 | centerOfMassW = ComputeLinksetCenterOfMass(); | 325 | return; // Note the 'finally' clause at the botton which will get executed. |
421 | } | 326 | } |
422 | 327 | ||
423 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 328 | // Get a new compound shape to build the linkset shape in. |
329 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | ||
424 | 330 | ||
425 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | 331 | // Compute a displacement for each component so it is relative to the center-of-mass. |
426 | OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | 332 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass |
427 | LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); | 333 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); |
428 | |||
429 | // This causes the physical position of the root prim to be offset to accomodate for the displacements | ||
430 | LinksetRoot.ForcePosition = LinksetRoot.RawPosition; | ||
431 | 334 | ||
432 | // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM | 335 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); |
433 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, | 336 | OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; |
434 | -centerDisplacement, | ||
435 | OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, | ||
436 | false /* shouldRecalculateLocalAabb (is done later after linkset built) */); | ||
437 | 337 | ||
438 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", | 338 | // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass |
439 | LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); | 339 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; |
340 | if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) | ||
341 | { | ||
342 | // Zero everything if center-of-mass displacement is not being done. | ||
343 | centerDisplacementV = OMV.Vector3.Zero; | ||
344 | LinksetRoot.ClearDisplacement(); | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | // The actual center-of-mass could have been set by the user. | ||
349 | centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
350 | } | ||
440 | 351 | ||
441 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 352 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", |
442 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 353 | LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); |
443 | 354 | ||
444 | // Add a shape for each of the other children in the linkset | 355 | // Add the shapes of all the components of the linkset |
445 | int memberIndex = 1; | 356 | int memberIndex = 1; |
446 | ForEachMember(delegate(BSPrimLinkable cPrim) | 357 | ForEachMember((cPrim) => |
447 | { | 358 | { |
448 | if (IsRoot(cPrim)) | 359 | if (IsRoot(cPrim)) |
449 | { | 360 | { |
361 | // Root shape is always index zero. | ||
450 | cPrim.LinksetChildIndex = 0; | 362 | cPrim.LinksetChildIndex = 0; |
451 | } | 363 | } |
452 | else | 364 | else |
453 | { | 365 | { |
454 | cPrim.LinksetChildIndex = memberIndex; | 366 | cPrim.LinksetChildIndex = memberIndex; |
367 | memberIndex++; | ||
368 | } | ||
455 | 369 | ||
456 | if (cPrim.PhysShape.isNativeShape) | 370 | // Get a reference to the shape of the child for adding of that shape to the linkset compound shape |
457 | { | 371 | 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 | 372 | ||
492 | } | 373 | // Offset the child shape from the center-of-mass and rotate it to vehicle relative. |
493 | memberIndex++; | 374 | OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; |
375 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
376 | |||
377 | // Add the child shape to the compound shape being built | ||
378 | m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); | ||
379 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", | ||
380 | LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); | ||
381 | |||
382 | // Since we are borrowing the shape of the child, disable the origional child body | ||
383 | if (!IsRoot(cPrim)) | ||
384 | { | ||
385 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
386 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
387 | // We don't want collisions from the old linkset children. | ||
388 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
389 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; | ||
494 | } | 390 | } |
391 | |||
495 | return false; // 'false' says to move onto the next child in the list | 392 | return false; // 'false' says to move onto the next child in the list |
496 | }); | 393 | }); |
497 | 394 | ||
395 | // Replace the root shape with the built compound shape. | ||
396 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
397 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
398 | LinksetRoot.PhysShape = linksetShape; | ||
399 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
400 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
401 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
402 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
403 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
404 | |||
498 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 405 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
499 | LinksetMass = ComputeLinksetMass(); | 406 | LinksetMass = ComputeLinksetMass(); |
500 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 407 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
501 | 408 | ||
502 | // Enable the physical position updator to return the position and rotation of the root shape | 409 | if (UseBulletSimRootOffsetHack) |
503 | PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | 410 | { |
411 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
412 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
413 | // compound shape. This aleviates the need to offset the returned physical position by the | ||
414 | // center-of-mass offset. | ||
415 | // TODO: either debug this feature or remove it. | ||
416 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | ||
417 | } | ||
504 | } | 418 | } |
505 | finally | 419 | finally |
506 | { | 420 | { |
@@ -508,7 +422,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
508 | } | 422 | } |
509 | 423 | ||
510 | // See that the Aabb surrounds the new shape | 424 | // See that the Aabb surrounds the new shape |
511 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | 425 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); |
512 | } | 426 | } |
513 | } | 427 | } |
514 | } \ No newline at end of file | 428 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 6d252ca..4bac222 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,8 +36,78 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public class BSLinkInfoConstraint : BSLinkInfo | ||
40 | { | ||
41 | public ConstraintType constraintType; | ||
42 | public BSConstraint constraint; | ||
43 | public OMV.Vector3 linearLimitLow; | ||
44 | public OMV.Vector3 linearLimitHigh; | ||
45 | public OMV.Vector3 angularLimitLow; | ||
46 | public OMV.Vector3 angularLimitHigh; | ||
47 | public bool useFrameOffset; | ||
48 | public bool enableTransMotor; | ||
49 | public float transMotorMaxVel; | ||
50 | public float transMotorMaxForce; | ||
51 | public float cfm; | ||
52 | public float erp; | ||
53 | public float solverIterations; | ||
54 | |||
55 | public BSLinkInfoConstraint(BSPrimLinkable pMember) | ||
56 | : base(pMember) | ||
57 | { | ||
58 | constraint = null; | ||
59 | ResetToFixedConstraint(); | ||
60 | } | ||
61 | |||
62 | // Set all the parameters for this constraint to a fixed, non-movable constraint. | ||
63 | public void ResetToFixedConstraint() | ||
64 | { | ||
65 | constraintType = ConstraintType.D6_CONSTRAINT_TYPE; | ||
66 | linearLimitLow = OMV.Vector3.Zero; | ||
67 | linearLimitHigh = OMV.Vector3.Zero; | ||
68 | angularLimitLow = OMV.Vector3.Zero; | ||
69 | angularLimitHigh = OMV.Vector3.Zero; | ||
70 | useFrameOffset = BSParam.LinkConstraintUseFrameOffset; | ||
71 | enableTransMotor = BSParam.LinkConstraintEnableTransMotor; | ||
72 | transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; | ||
73 | transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; | ||
74 | cfm = BSParam.LinkConstraintCFM; | ||
75 | erp = BSParam.LinkConstraintERP; | ||
76 | solverIterations = BSParam.LinkConstraintSolverIterations; | ||
77 | } | ||
78 | |||
79 | // Given a constraint, apply the current constraint parameters to same. | ||
80 | public void SetConstraintParameters(BSConstraint constrain) | ||
81 | { | ||
82 | switch (constraintType) | ||
83 | { | ||
84 | case ConstraintType.D6_CONSTRAINT_TYPE: | ||
85 | BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; | ||
86 | if (constrain6dof != null) | ||
87 | { | ||
88 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
89 | constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
90 | constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
91 | |||
92 | // tweek the constraint to increase stability | ||
93 | constrain6dof.UseFrameOffset(useFrameOffset); | ||
94 | constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
95 | constrain6dof.SetCFMAndERP(cfm, erp); | ||
96 | if (solverIterations != 0f) | ||
97 | { | ||
98 | constrain6dof.SetSolverIterations(solverIterations); | ||
99 | } | ||
100 | } | ||
101 | break; | ||
102 | default: | ||
103 | break; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
39 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) | 108 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) |
40 | { | 109 | { |
110 | LinksetImpl = LinksetImplementation.Constraint; | ||
41 | } | 111 | } |
42 | 112 | ||
43 | // When physical properties are changed the linkset needs to recalculate | 113 | // When physical properties are changed the linkset needs to recalculate |
@@ -48,12 +118,22 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
48 | { | 118 | { |
49 | base.Refresh(requestor); | 119 | base.Refresh(requestor); |
50 | 120 | ||
51 | if (HasAnyChildren && IsRoot(requestor)) | 121 | } |
122 | |||
123 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
124 | { | ||
125 | DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | ||
126 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | ||
127 | |||
128 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | ||
129 | // If already rebuilding, don't request another rebuild. | ||
130 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | ||
131 | if (!Rebuilding && HasAnyChildren) | ||
52 | { | 132 | { |
53 | // Queue to happen after all the other taint processing | 133 | // Queue to happen after all the other taint processing |
54 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 134 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
55 | { | 135 | { |
56 | if (HasAnyChildren && IsRoot(requestor)) | 136 | if (HasAnyChildren) |
57 | RecomputeLinksetConstraints(); | 137 | RecomputeLinksetConstraints(); |
58 | }); | 138 | }); |
59 | } | 139 | } |
@@ -67,8 +147,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
67 | // Called at taint-time! | 147 | // Called at taint-time! |
68 | public override bool MakeDynamic(BSPrimLinkable child) | 148 | public override bool MakeDynamic(BSPrimLinkable child) |
69 | { | 149 | { |
70 | // What is done for each object in BSPrim is what we want. | 150 | bool ret = false; |
71 | return false; | 151 | DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
152 | if (IsRoot(child)) | ||
153 | { | ||
154 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
155 | ScheduleRebuild(LinksetRoot); | ||
156 | } | ||
157 | return ret; | ||
72 | } | 158 | } |
73 | 159 | ||
74 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 160 | // The object is going static (non-physical). Do any setup necessary for a static linkset. |
@@ -78,8 +164,16 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
78 | // Called at taint-time! | 164 | // Called at taint-time! |
79 | public override bool MakeStatic(BSPrimLinkable child) | 165 | public override bool MakeStatic(BSPrimLinkable child) |
80 | { | 166 | { |
81 | // What is done for each object in BSPrim is what we want. | 167 | bool ret = false; |
82 | return false; | 168 | |
169 | DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
170 | child.ClearDisplacement(); | ||
171 | if (IsRoot(child)) | ||
172 | { | ||
173 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
174 | ScheduleRebuild(LinksetRoot); | ||
175 | } | ||
176 | return ret; | ||
83 | } | 177 | } |
84 | 178 | ||
85 | // Called at taint-time!! | 179 | // Called at taint-time!! |
@@ -93,11 +187,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
93 | // up to rebuild the constraints before the next simulation step. | 187 | // up to rebuild the constraints before the next simulation step. |
94 | // Returns 'true' of something was actually removed and would need restoring | 188 | // Returns 'true' of something was actually removed and would need restoring |
95 | // Called at taint-time!! | 189 | // Called at taint-time!! |
96 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 190 | public override bool RemoveDependencies(BSPrimLinkable child) |
97 | { | 191 | { |
98 | bool ret = false; | 192 | bool ret = false; |
99 | 193 | ||
100 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 194 | DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); | 195 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); |
102 | 196 | ||
103 | lock (m_linksetActivityLock) | 197 | lock (m_linksetActivityLock) |
@@ -105,7 +199,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
105 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | 199 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. |
106 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | 200 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
107 | // Cause the constraints, et al to be rebuilt before the next simulation step. | 201 | // Cause the constraints, et al to be rebuilt before the next simulation step. |
108 | Refresh(LinksetRoot); | 202 | ScheduleRebuild(LinksetRoot); |
109 | } | 203 | } |
110 | return ret; | 204 | return ret; |
111 | } | 205 | } |
@@ -118,12 +212,12 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
118 | { | 212 | { |
119 | if (!HasChild(child)) | 213 | if (!HasChild(child)) |
120 | { | 214 | { |
121 | m_children.Add(child); | 215 | m_children.Add(child, new BSLinkInfoConstraint(child)); |
122 | 216 | ||
123 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 217 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
124 | 218 | ||
125 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 219 | // Cause constraints and assorted properties to be recomputed before the next simulation step. |
126 | Refresh(LinksetRoot); | 220 | ScheduleRebuild(LinksetRoot); |
127 | } | 221 | } |
128 | return; | 222 | return; |
129 | } | 223 | } |
@@ -142,12 +236,12 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
142 | rootx.LocalID, rootx.PhysBody.AddrString, | 236 | rootx.LocalID, rootx.PhysBody.AddrString, |
143 | childx.LocalID, childx.PhysBody.AddrString); | 237 | childx.LocalID, childx.PhysBody.AddrString); |
144 | 238 | ||
145 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 239 | m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
146 | { | 240 | { |
147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 241 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
148 | }); | 242 | }); |
149 | // See that the linkset parameters are recomputed at the end of the taint time. | 243 | // See that the linkset parameters are recomputed at the end of the taint time. |
150 | Refresh(LinksetRoot); | 244 | ScheduleRebuild(LinksetRoot); |
151 | } | 245 | } |
152 | else | 246 | else |
153 | { | 247 | { |
@@ -165,73 +259,75 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
165 | Refresh(rootPrim); | 259 | Refresh(rootPrim); |
166 | } | 260 | } |
167 | 261 | ||
168 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) | 262 | // Create a static constraint between the two passed objects |
263 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) | ||
169 | { | 264 | { |
265 | BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint; | ||
266 | if (liConstraint == null) | ||
267 | return null; | ||
268 | |||
170 | // Zero motion for children so they don't interpolate | 269 | // Zero motion for children so they don't interpolate |
171 | childPrim.ZeroMotion(true); | 270 | li.member.ZeroMotion(true); |
172 | 271 | ||
173 | // Relative position normalized to the root prim | 272 | BSConstraint constrain = null; |
174 | // Essentually a vector pointing from center of rootPrim to center of childPrim | 273 | |
175 | OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; | 274 | switch (liConstraint.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 | { | 275 | { |
233 | constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations); | 276 | case ConstraintType.D6_CONSTRAINT_TYPE: |
277 | // Relative position normalized to the root prim | ||
278 | // Essentually a vector pointing from center of rootPrim to center of li.member | ||
279 | OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position; | ||
280 | |||
281 | // real world coordinate of midpoint between the two objects | ||
282 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
283 | |||
284 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | ||
285 | rootPrim.LocalID, | ||
286 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
287 | liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString, | ||
288 | rootPrim.Position, liConstraint.member.Position, midPoint); | ||
289 | |||
290 | // create a constraint that allows no freedom of movement between the two objects | ||
291 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
292 | |||
293 | constrain = new BSConstraint6Dof( | ||
294 | m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true ); | ||
295 | |||
296 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | ||
297 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | ||
298 | * of the objects. | ||
299 | * Code left for future programmers. | ||
300 | // ================================================================================== | ||
301 | // relative position normalized to the root prim | ||
302 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
303 | OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; | ||
304 | |||
305 | // relative rotation of the child to the parent | ||
306 | OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; | ||
307 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
308 | |||
309 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); | ||
310 | constrain = new BS6DofConstraint( | ||
311 | PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, | ||
312 | OMV.Vector3.Zero, | ||
313 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
314 | OMV.Vector3.Zero, | ||
315 | OMV.Quaternion.Inverse(liConstraint.member.Orientation), | ||
316 | true, | ||
317 | true | ||
318 | ); | ||
319 | // ================================================================================== | ||
320 | */ | ||
321 | |||
322 | break; | ||
323 | default: | ||
324 | break; | ||
234 | } | 325 | } |
326 | |||
327 | liConstraint.SetConstraintParameters(constrain); | ||
328 | |||
329 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
330 | |||
235 | return constrain; | 331 | return constrain; |
236 | } | 332 | } |
237 | 333 | ||
@@ -248,10 +344,10 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
248 | childPrim.LocalID, childPrim.PhysBody.AddrString); | 344 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
249 | 345 | ||
250 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 346 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
251 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 347 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
252 | { | 348 | { |
253 | // Make the child refresh its location | 349 | // Make the child refresh its location |
254 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); | 350 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); |
255 | ret = true; | 351 | ret = true; |
256 | } | 352 | } |
257 | 353 | ||
@@ -265,7 +361,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
265 | { | 361 | { |
266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 362 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
267 | 363 | ||
268 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | 364 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); |
269 | } | 365 | } |
270 | 366 | ||
271 | // Call each of the constraints that make up this linkset and recompute the | 367 | // Call each of the constraints that make up this linkset and recompute the |
@@ -281,24 +377,40 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
281 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | 377 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", |
282 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); | 378 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); |
283 | 379 | ||
284 | foreach (BSPrimLinkable child in m_children) | 380 | try |
285 | { | 381 | { |
286 | // A child in the linkset physically shows the mass of the whole linkset. | 382 | 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 | 383 | ||
291 | BSConstraint constrain; | 384 | // 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)) | 385 | if (!LinksetRoot.IsPhysicallyActive) |
293 | { | 386 | { |
294 | // If constraint doesn't exist yet, create it. | 387 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); |
295 | constrain = BuildConstraint(LinksetRoot, child); | 388 | return; // Note the 'finally' clause at the botton which will get executed. |
296 | } | 389 | } |
297 | constrain.RecomputeConstraintVariables(linksetMass); | ||
298 | 390 | ||
299 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG | 391 | ForEachLinkInfo((li) => |
300 | } | 392 | { |
393 | // A child in the linkset physically shows the mass of the whole linkset. | ||
394 | // This allows Bullet to apply enough force on the child to move the whole linkset. | ||
395 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | ||
396 | li.member.UpdatePhysicalMassProperties(linksetMass, true); | ||
397 | |||
398 | BSConstraint constrain; | ||
399 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) | ||
400 | { | ||
401 | // If constraint doesn't exist yet, create it. | ||
402 | constrain = BuildConstraint(LinksetRoot, li); | ||
403 | } | ||
404 | constrain.RecomputeConstraintVariables(linksetMass); | ||
301 | 405 | ||
406 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG | ||
407 | return false; // 'false' says to keep processing other members | ||
408 | }); | ||
409 | } | ||
410 | finally | ||
411 | { | ||
412 | Rebuilding = false; | ||
413 | } | ||
302 | } | 414 | } |
303 | } | 415 | } |
304 | } | 416 | } |
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. |
403 | public class BSPIDVMotor : BSVMotor | 370 | public 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..fcb892a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Reflection; | ||
29 | using System.Text; | 30 | using System.Text; |
30 | 31 | ||
31 | using OpenSim.Region.Physics.Manager; | 32 | using OpenSim.Region.Physics.Manager; |
@@ -37,7 +38,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
37 | { | 38 | { |
38 | public static class BSParam | 39 | public 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; } |
@@ -122,11 +130,17 @@ public static class BSParam | |||
122 | public static float AvatarCapsuleWidth { get; private set; } | 130 | public static float AvatarCapsuleWidth { get; private set; } |
123 | public static float AvatarCapsuleDepth { get; private set; } | 131 | public static float AvatarCapsuleDepth { get; private set; } |
124 | public static float AvatarCapsuleHeight { get; private set; } | 132 | public static float AvatarCapsuleHeight { get; private set; } |
133 | public static float AvatarHeightLowFudge { get; private set; } | ||
134 | public static float AvatarHeightMidFudge { get; private set; } | ||
135 | public static float AvatarHeightHighFudge { get; private set; } | ||
125 | public static float AvatarContactProcessingThreshold { get; private set; } | 136 | public static float AvatarContactProcessingThreshold { get; private set; } |
137 | public static int AvatarJumpFrames { get; private set; } | ||
126 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | 138 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } |
127 | public static float AvatarStepHeight { get; private set; } | 139 | public static float AvatarStepHeight { get; private set; } |
128 | public static float AvatarStepApproachFactor { get; private set; } | 140 | public static float AvatarStepApproachFactor { get; private set; } |
129 | public static float AvatarStepForceFactor { get; private set; } | 141 | public static float AvatarStepForceFactor { get; private set; } |
142 | public static float AvatarStepUpCorrectionFactor { get; private set; } | ||
143 | public static int AvatarStepSmoothingSteps { get; private set; } | ||
130 | 144 | ||
131 | // Vehicle parameters | 145 | // Vehicle parameters |
132 | public static float VehicleMaxLinearVelocity { get; private set; } | 146 | public static float VehicleMaxLinearVelocity { get; private set; } |
@@ -138,9 +152,15 @@ public static class BSParam | |||
138 | public static float VehicleRestitution { get; private set; } | 152 | public static float VehicleRestitution { get; private set; } |
139 | public static Vector3 VehicleLinearFactor { get; private set; } | 153 | public static Vector3 VehicleLinearFactor { get; private set; } |
140 | public static Vector3 VehicleAngularFactor { get; private set; } | 154 | public static Vector3 VehicleAngularFactor { get; private set; } |
155 | public static Vector3 VehicleInertiaFactor { get; private set; } | ||
141 | public static float VehicleGroundGravityFudge { get; private set; } | 156 | public static float VehicleGroundGravityFudge { get; private set; } |
142 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | 157 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } |
143 | public static bool VehicleDebuggingEnabled { get; private set; } | 158 | public static bool VehicleEnableLinearDeflection { get; private set; } |
159 | public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } | ||
160 | public static bool VehicleEnableAngularVerticalAttraction { get; private set; } | ||
161 | public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } | ||
162 | public static bool VehicleEnableAngularDeflection { get; private set; } | ||
163 | public static bool VehicleEnableAngularBanking { get; private set; } | ||
144 | 164 | ||
145 | // Convex Hulls | 165 | // Convex Hulls |
146 | public static int CSHullMaxDepthSplit { get; private set; } | 166 | public static int CSHullMaxDepthSplit { get; private set; } |
@@ -149,9 +169,19 @@ public static class BSParam | |||
149 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | 169 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } |
150 | public static int CSHullMaxVertices { get; private set; } | 170 | public static int CSHullMaxVertices { get; private set; } |
151 | public static float CSHullMaxSkinWidth { get; private set; } | 171 | public static float CSHullMaxSkinWidth { get; private set; } |
172 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
173 | public static float BHullMinClusters { get; private set; } // 2 | ||
174 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
175 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
176 | public static float BHullConcavity { get; private set; } // 100 | ||
177 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
178 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
179 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
180 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
152 | 181 | ||
153 | // Linkset implementation parameters | 182 | // Linkset implementation parameters |
154 | public static float LinksetImplementation { get; private set; } | 183 | public static float LinksetImplementation { get; private set; } |
184 | public static bool LinksetOffsetCenterOfMass { get; private set; } | ||
155 | public static bool LinkConstraintUseFrameOffset { get; private set; } | 185 | public static bool LinkConstraintUseFrameOffset { get; private set; } |
156 | public static bool LinkConstraintEnableTransMotor { get; private set; } | 186 | public static bool LinkConstraintEnableTransMotor { get; private set; } |
157 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | 187 | public static float LinkConstraintTransMotorMaxVel { get; private set; } |
@@ -223,16 +253,41 @@ public static class BSParam | |||
223 | getter = pGetter; | 253 | getter = pGetter; |
224 | objectSet = pObjSetter; | 254 | objectSet = pObjSetter; |
225 | } | 255 | } |
226 | /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work | 256 | // 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) | 257 | // and the value is only a simple get and set. |
258 | public ParameterDefn(string pName, string pDesc, T pDefault) | ||
228 | : base(pName, pDesc) | 259 | : base(pName, pDesc) |
229 | { | 260 | { |
230 | defaultValue = pDefault; | 261 | defaultValue = pDefault; |
231 | setter = (s, v) => { loc = v; }; | 262 | setter = (s, v) => { SetValueByName(s, name, v); }; |
232 | getter = (s) => { return loc; }; | 263 | getter = (s) => { return GetValueByName(s, name); }; |
233 | objectSet = null; | 264 | objectSet = null; |
234 | } | 265 | } |
235 | */ | 266 | // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. |
267 | private void SetValueByName(BSScene s, string pName, T val) | ||
268 | { | ||
269 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
270 | if (prop == null) | ||
271 | { | ||
272 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
273 | s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | prop.SetValue(null, val, null); | ||
278 | } | ||
279 | } | ||
280 | // Use reflection to find the property named 'pName' in BSParam and return the value in same. | ||
281 | private T GetValueByName(BSScene s, string pName) | ||
282 | { | ||
283 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
284 | if (prop == null) | ||
285 | { | ||
286 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
287 | s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); | ||
288 | } | ||
289 | return (T)prop.GetValue(null, null); | ||
290 | } | ||
236 | public override void AssignDefault(BSScene s) | 291 | public override void AssignDefault(BSScene s) |
237 | { | 292 | { |
238 | setter(s, defaultValue); | 293 | setter(s, defaultValue); |
@@ -309,6 +364,11 @@ public static class BSParam | |||
309 | // v = value (appropriate type) | 364 | // v = value (appropriate type) |
310 | private static ParameterDefnBase[] ParameterDefinitions = | 365 | private static ParameterDefnBase[] ParameterDefinitions = |
311 | { | 366 | { |
367 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
368 | false ), | ||
369 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
370 | 0.089f ), | ||
371 | |||
312 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | 372 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
313 | true, | 373 | true, |
314 | (s) => { return ShouldMeshSculptedPrim; }, | 374 | (s) => { return ShouldMeshSculptedPrim; }, |
@@ -322,18 +382,20 @@ public static class BSParam | |||
322 | (s) => { return ShouldUseHullsForPhysicalObjects; }, | 382 | (s) => { return ShouldUseHullsForPhysicalObjects; }, |
323 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), | 383 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), |
324 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", | 384 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", |
325 | true, | 385 | true ), |
326 | (s) => { return ShouldRemoveZeroWidthTriangles; }, | 386 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", |
327 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), | 387 | false ), |
388 | new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", | ||
389 | true ), | ||
390 | new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", | ||
391 | false ), | ||
392 | new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", | ||
393 | true ), | ||
328 | 394 | ||
329 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | 395 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", |
330 | 5, | 396 | 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", | 397 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", |
334 | 0.1f, | 398 | 0.1f ), |
335 | (s) => { return UpdateVelocityChangeThreshold; }, | ||
336 | (s,v) => { UpdateVelocityChangeThreshold = v; } ), | ||
337 | 399 | ||
338 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 400 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
339 | 32f, | 401 | 32f, |
@@ -399,26 +461,22 @@ public static class BSParam | |||
399 | (s) => { return MaxAddForceMagnitude; }, | 461 | (s) => { return MaxAddForceMagnitude; }, |
400 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | 462 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), |
401 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. | 463 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. |
464 | // 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)", | 465 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", |
403 | 0.01f, | 466 | 0.01f ), |
404 | (s) => { return DensityScaleFactor; }, | ||
405 | (s,v) => { DensityScaleFactor = v; } ), | ||
406 | 467 | ||
407 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | 468 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", |
408 | 2200f, | 469 | 2200f ), |
409 | (s) => { return (float)PID_D; }, | ||
410 | (s,v) => { PID_D = v; } ), | ||
411 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | 470 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", |
412 | 900f, | 471 | 900f ), |
413 | (s) => { return (float)PID_P; }, | ||
414 | (s,v) => { PID_P = v; } ), | ||
415 | 472 | ||
416 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | 473 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", |
417 | 0.2f, | 474 | 0.2f, |
418 | (s) => { return DefaultFriction; }, | 475 | (s) => { return DefaultFriction; }, |
419 | (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), | 476 | (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), |
477 | // For historical reasons, the viewer and simulator multiply the density by 100 | ||
420 | new ParameterDefn<float>("DefaultDensity", "Density for new objects" , | 478 | new ParameterDefn<float>("DefaultDensity", "Density for new objects" , |
421 | 10.000006836f, // Aluminum g/cm3 | 479 | 1000.0006836f, // Aluminum g/cm3 * 100 |
422 | (s) => { return DefaultDensity; }, | 480 | (s) => { return DefaultDensity; }, |
423 | (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), | 481 | (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), |
424 | new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , | 482 | new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , |
@@ -478,86 +536,59 @@ public static class BSParam | |||
478 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), | 536 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), |
479 | 537 | ||
480 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | 538 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", |
481 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | 539 | (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" , | 540 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , |
485 | 2, | 541 | 2 ), |
486 | (s) => { return TerrainMeshMagnification; }, | ||
487 | (s,v) => { TerrainMeshMagnification = v; } ), | ||
488 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , | 542 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , |
489 | 0.3f, | 543 | 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" , | 544 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , |
493 | 0.8f, | 545 | 0.8f ), |
494 | (s) => { return TerrainHitFraction; }, | ||
495 | (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
496 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , | 546 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , |
497 | 0f, | 547 | 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" , | 548 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , |
501 | 0.0f, | 549 | 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" , | 550 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , |
505 | 0.08f, | 551 | 0.08f ), |
506 | (s) => { return TerrainCollisionMargin; }, | ||
507 | (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
508 | 552 | ||
509 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 553 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
510 | 0.2f, | 554 | 0.2f ), |
511 | (s) => { return AvatarFriction; }, | ||
512 | (s,v) => { AvatarFriction = v; } ), | ||
513 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 555 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
514 | 0.95f, | 556 | 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", | 557 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", |
518 | 1.3f, | 558 | 1.3f ), |
519 | (s) => { return AvatarAlwaysRunFactor; }, | 559 | // For historical reasons, density is reported * 100 |
520 | (s,v) => { AvatarAlwaysRunFactor = v; } ), | 560 | 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.", | 561 | 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.", | 562 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |
526 | 0f, | 563 | 0f ), |
527 | (s) => { return AvatarRestitution; }, | ||
528 | (s,v) => { AvatarRestitution = v; } ), | ||
529 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | 564 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", |
530 | 0.6f, | 565 | 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", | 566 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", |
534 | 0.45f, | 567 | 0.45f ), |
535 | (s) => { return AvatarCapsuleDepth; }, | ||
536 | (s,v) => { AvatarCapsuleDepth = v; } ), | ||
537 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | 568 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", |
538 | 1.5f, | 569 | 1.5f ), |
539 | (s) => { return AvatarCapsuleHeight; }, | 570 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", |
540 | (s,v) => { AvatarCapsuleHeight = v; } ), | 571 | -0.2f ), |
572 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", | ||
573 | 0.2f ), | ||
574 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", | ||
575 | 0.2f ), | ||
541 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 576 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
542 | 0.1f, | 577 | 0.1f ), |
543 | (s) => { return AvatarContactProcessingThreshold; }, | ||
544 | (s,v) => { AvatarContactProcessingThreshold = v; } ), | ||
545 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | 578 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", |
546 | 1.0f, | 579 | 1.0f ), |
547 | (s) => { return AvatarBelowGroundUpCorrectionMeters; }, | 580 | new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", |
548 | (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), | 581 | 4 ), |
549 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | 582 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", |
550 | 0.3f, | 583 | 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)", | 584 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", |
554 | 0.6f, | 585 | 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", | 586 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", |
558 | 2.0f, | 587 | 1.0f ), |
559 | (s) => { return AvatarStepForceFactor; }, | 588 | new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", |
560 | (s,v) => { AvatarStepForceFactor = v; } ), | 589 | 1.0f ), |
590 | new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", | ||
591 | 2 ), | ||
561 | 592 | ||
562 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | 593 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", |
563 | 1000.0f, | 594 | 1000.0f, |
@@ -568,37 +599,33 @@ public static class BSParam | |||
568 | (s) => { return (float)VehicleMaxAngularVelocity; }, | 599 | (s) => { return (float)VehicleMaxAngularVelocity; }, |
569 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | 600 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), |
570 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | 601 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", |
571 | 0.0f, | 602 | 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>)", | 603 | 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), | 604 | 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>)", | 605 | 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), | 606 | new Vector3(1f, 1f, 1f) ), |
580 | (s) => { return VehicleAngularFactor; }, | 607 | new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", |
581 | (s,v) => { VehicleAngularFactor = v; } ), | 608 | new Vector3(1f, 1f, 1f) ), |
582 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | 609 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", |
583 | 0.0f, | 610 | 0.0f ), |
584 | (s) => { return VehicleFriction; }, | ||
585 | (s,v) => { VehicleFriction = v; } ), | ||
586 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | 611 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", |
587 | 0.0f, | 612 | 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)", | 613 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", |
591 | 0.2f, | 614 | 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.", | 615 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", |
595 | 60.0f, | 616 | 60.0f ), |
596 | (s) => { return VehicleAngularBankingTimescaleFudge; }, | 617 | new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", |
597 | (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), | 618 | true ), |
598 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | 619 | new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", |
599 | false, | 620 | true ), |
600 | (s) => { return VehicleDebuggingEnabled; }, | 621 | new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", |
601 | (s,v) => { VehicleDebuggingEnabled = v; } ), | 622 | true ), |
623 | new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", | ||
624 | 0 ), | ||
625 | new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", | ||
626 | true ), | ||
627 | new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", | ||
628 | true ), | ||
602 | 629 | ||
603 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 630 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
604 | 0f, | 631 | 0f, |
@@ -611,7 +638,7 @@ public static class BSParam | |||
611 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | 638 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", |
612 | false, | 639 | false, |
613 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, | 640 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, |
614 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; | 641 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; |
615 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), | 642 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), |
616 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | 643 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", |
617 | false, | 644 | false, |
@@ -643,62 +670,55 @@ public static class BSParam | |||
643 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), | 670 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), |
644 | 671 | ||
645 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", | 672 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", |
646 | 7, | 673 | 7 ), |
647 | (s) => { return CSHullMaxDepthSplit; }, | ||
648 | (s,v) => { CSHullMaxDepthSplit = v; } ), | ||
649 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | 674 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", |
650 | 2, | 675 | 2 ), |
651 | (s) => { return CSHullMaxDepthSplitForSimpleShapes; }, | ||
652 | (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ), | ||
653 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | 676 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", |
654 | 5f, | 677 | 5f ), |
655 | (s) => { return CSHullConcavityThresholdPercent; }, | ||
656 | (s,v) => { CSHullConcavityThresholdPercent = v; } ), | ||
657 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | 678 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", |
658 | 5f, | 679 | 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.", | 680 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", |
662 | 32, | 681 | 32 ), |
663 | (s) => { return CSHullMaxVertices; }, | ||
664 | (s,v) => { CSHullMaxVertices = v; } ), | ||
665 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | 682 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", |
666 | 0, | 683 | 0f ), |
667 | (s) => { return CSHullMaxSkinWidth; }, | 684 | |
668 | (s,v) => { CSHullMaxSkinWidth = v; } ), | 685 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", |
686 | 100f ), | ||
687 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
688 | 2f ), | ||
689 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
690 | 0.1f ), | ||
691 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
692 | 0f ), | ||
693 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
694 | 100f ), | ||
695 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
696 | false ), | ||
697 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
698 | false ), | ||
699 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
700 | false ), | ||
701 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
702 | false ), | ||
669 | 703 | ||
670 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | 704 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", |
671 | (float)BSLinkset.LinksetImplementation.Compound, | 705 | (float)BSLinkset.LinksetImplementation.Compound ), |
672 | (s) => { return LinksetImplementation; }, | 706 | new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", |
673 | (s,v) => { LinksetImplementation = v; } ), | 707 | true ), |
674 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | 708 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
675 | false, | 709 | false ), |
676 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
677 | (s,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
678 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | 710 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", |
679 | true, | 711 | 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", | 712 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", |
683 | 5.0f, | 713 | 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", | 714 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", |
687 | 0.1f, | 715 | 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", | 716 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
691 | 0.1f, | 717 | 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", | 718 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
695 | 0.1f, | 719 | 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)", | 720 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", |
699 | 40, | 721 | 40 ), |
700 | (s) => { return LinkConstraintSolverIterations; }, | ||
701 | (s,v) => { LinkConstraintSolverIterations = v; } ), | ||
702 | 722 | ||
703 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | 723 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", |
704 | 0, | 724 | 0, |
@@ -707,7 +727,7 @@ public static class BSParam | |||
707 | new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", | 727 | new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", |
708 | 0f, | 728 | 0f, |
709 | (s) => { return 0f; }, | 729 | (s) => { return 0f; }, |
710 | (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), | 730 | (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ), |
711 | new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", | 731 | new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", |
712 | 0f, | 732 | 0f, |
713 | (s) => { return 0f; }, | 733 | (s) => { return 0f; }, |
@@ -793,10 +813,10 @@ public static class BSParam | |||
793 | // ===================================================================== | 813 | // ===================================================================== |
794 | // There are parameters that, when set, cause things to happen in the physics engine. | 814 | // There are parameters that, when set, cause things to happen in the physics engine. |
795 | // This causes the broadphase collision cache to be cleared. | 815 | // This causes the broadphase collision cache to be cleared. |
796 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) | 816 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime) |
797 | { | 817 | { |
798 | BSScene physScene = pPhysScene; | 818 | BSScene physScene = pPhysScene; |
799 | physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() | 819 | physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate() |
800 | { | 820 | { |
801 | physScene.PE.ResetBroadphasePool(physScene.World); | 821 | physScene.PE.ResetBroadphasePool(physScene.World); |
802 | }); | 822 | }); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 6bb88c7..9dc52d5 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,19 +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 | ||
83 | // The collection of things that push me around | ||
84 | PhysicalActors = new BSActorCollection(PhysScene); | ||
85 | |||
81 | // Initialize variables kept in base. | 86 | // Initialize variables kept in base. |
82 | GravModifier = 1.0f; | 87 | GravModifier = 1.0f; |
83 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | 88 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); |
89 | HoverActive = false; | ||
84 | 90 | ||
85 | // We don't have any physical representation yet. | 91 | // We don't have any physical representation yet. |
86 | PhysBody = new BulletBody(localID); | 92 | PhysBody = new BulletBody(localID); |
87 | PhysShape = new BulletShape(); | 93 | PhysShape = new BSShapeNull(); |
94 | |||
95 | UserSetCenterOfMassDisplacement = null; | ||
88 | 96 | ||
89 | PrimAssetState = PrimAssetCondition.Unknown; | 97 | PrimAssetState = PrimAssetCondition.Unknown; |
90 | 98 | ||
@@ -92,30 +100,41 @@ public abstract class BSPhysObject : PhysicsActor | |||
92 | SetMaterial((int)MaterialAttributes.Material.Wood); | 100 | SetMaterial((int)MaterialAttributes.Material.Wood); |
93 | 101 | ||
94 | CollisionCollection = new CollisionEventUpdate(); | 102 | CollisionCollection = new CollisionEventUpdate(); |
95 | CollisionsLastTick = CollisionCollection; | 103 | CollisionsLastReported = CollisionCollection; |
104 | CollisionsLastTick = new CollisionEventUpdate(); | ||
105 | CollisionsLastTickStep = -1; | ||
106 | |||
96 | SubscribedEventsMs = 0; | 107 | SubscribedEventsMs = 0; |
97 | CollidingStep = 0; | 108 | // Crazy values that will never be true |
98 | CollidingGroundStep = 0; | 109 | CollidingStep = BSScene.NotASimulationStep; |
99 | CollisionAccumulation = 0; | 110 | CollidingGroundStep = BSScene.NotASimulationStep; |
111 | CollisionAccumulation = BSScene.NotASimulationStep; | ||
100 | ColliderIsMoving = false; | 112 | ColliderIsMoving = false; |
101 | CollisionScore = 0; | 113 | CollisionScore = 0; |
102 | 114 | ||
103 | // All axis free. | 115 | // All axis free. |
104 | LockedAxis = LockedAxisFree; | 116 | LockedLinearAxis = LockedAxisFree; |
117 | LockedAngularAxis = LockedAxisFree; | ||
105 | } | 118 | } |
106 | 119 | ||
107 | // Tell the object to clean up. | 120 | // Tell the object to clean up. |
108 | public virtual void Destroy() | 121 | public virtual void Destroy() |
109 | { | 122 | { |
110 | UnRegisterAllPreStepActions(); | 123 | PhysicalActors.Enable(false); |
111 | UnRegisterAllPostStepActions(); | 124 | PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() |
125 | { | ||
126 | PhysicalActors.Dispose(); | ||
127 | }); | ||
112 | } | 128 | } |
113 | 129 | ||
114 | public BSScene PhysicsScene { get; protected set; } | 130 | public BSScene PhysScene { get; protected set; } |
115 | // 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 |
116 | public string PhysObjectName { get; protected set; } | 132 | public string PhysObjectName { get; protected set; } |
117 | public string TypeName { get; protected set; } | 133 | public string TypeName { get; protected set; } |
118 | 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; } | ||
119 | 138 | ||
120 | // Return the object mass without calculating it or having side effects | 139 | // Return the object mass without calculating it or having side effects |
121 | public abstract float RawMass { get; } | 140 | public abstract float RawMass { get; } |
@@ -131,26 +150,19 @@ public abstract class BSPhysObject : PhysicsActor | |||
131 | // Reference to the physical body (btCollisionObject) of this object | 150 | // Reference to the physical body (btCollisionObject) of this object |
132 | public BulletBody PhysBody; | 151 | public BulletBody PhysBody; |
133 | // Reference to the physical shape (btCollisionShape) of this object | 152 | // Reference to the physical shape (btCollisionShape) of this object |
134 | public BulletShape PhysShape; | 153 | public BSShape PhysShape; |
135 | 154 | ||
136 | // The physical representation of the prim might require an asset fetch. | 155 | // The physical representation of the prim might require an asset fetch. |
137 | // 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'. |
138 | public enum PrimAssetCondition | 157 | public enum PrimAssetCondition |
139 | { | 158 | { |
140 | Unknown, Waiting, Failed, Fetched | 159 | Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched |
141 | } | 160 | } |
142 | public PrimAssetCondition PrimAssetState { get; set; } | 161 | public PrimAssetCondition PrimAssetState { get; set; } |
143 | 162 | ||
144 | // 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. |
145 | public PrimitiveBaseShape BaseShape { get; protected set; } | 164 | public PrimitiveBaseShape BaseShape { get; protected set; } |
146 | 165 | ||
147 | // Some types of objects have preferred physical representations. | ||
148 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
149 | public virtual BSPhysicsShapeType PreferredPhysicalShape | ||
150 | { | ||
151 | get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } | ||
152 | } | ||
153 | |||
154 | // 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. |
155 | // Keep the current and last EntityProperties to enable computation of differences | 167 | // Keep the current and last EntityProperties to enable computation of differences |
156 | // between the current update and the previous values. | 168 | // between the current update and the previous values. |
@@ -168,6 +180,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
168 | public abstract bool IsSolid { get; } | 180 | public abstract bool IsSolid { get; } |
169 | public abstract bool IsStatic { get; } | 181 | public abstract bool IsStatic { get; } |
170 | public abstract bool IsSelected { get; } | 182 | public abstract bool IsSelected { get; } |
183 | public abstract bool IsVolumeDetect { get; } | ||
171 | 184 | ||
172 | // Materialness | 185 | // Materialness |
173 | public MaterialAttributes.Material Material { get; private set; } | 186 | public MaterialAttributes.Material Material { get; private set; } |
@@ -176,11 +189,25 @@ public abstract class BSPhysObject : PhysicsActor | |||
176 | Material = (MaterialAttributes.Material)material; | 189 | Material = (MaterialAttributes.Material)material; |
177 | 190 | ||
178 | // 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. | ||
179 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | 193 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); |
180 | Friction = matAttrib.friction; | 194 | Friction = matAttrib.friction; |
181 | Restitution = matAttrib.restitution; | 195 | Restitution = matAttrib.restitution; |
182 | Density = matAttrib.density / BSParam.DensityScaleFactor; | 196 | Density = matAttrib.density; |
183 | 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); |
198 | } | ||
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 | } | ||
184 | } | 211 | } |
185 | 212 | ||
186 | // Stop all physical motion. | 213 | // Stop all physical motion. |
@@ -190,21 +217,55 @@ public abstract class BSPhysObject : PhysicsActor | |||
190 | // 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. |
191 | public abstract void UpdateProperties(EntityProperties entprop); | 218 | public abstract void UpdateProperties(EntityProperties entprop); |
192 | 219 | ||
193 | public abstract OMV.Vector3 RawPosition { get; set; } | 220 | public virtual OMV.Vector3 RawPosition { get; set; } |
194 | public abstract OMV.Vector3 ForcePosition { get; set; } | 221 | public abstract OMV.Vector3 ForcePosition { get; set; } |
195 | 222 | ||
196 | public abstract OMV.Quaternion RawOrientation { get; set; } | 223 | public virtual OMV.Quaternion RawOrientation { get; set; } |
197 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 224 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
198 | 225 | ||
199 | public abstract OMV.Vector3 RawVelocity { get; set; } | 226 | public OMV.Vector3 RawVelocity { get; set; } |
200 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 227 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
201 | 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 | |||
202 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 238 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
203 | 239 | ||
204 | public abstract float ForceBuoyancy { get; set; } | 240 | public abstract float ForceBuoyancy { get; set; } |
205 | 241 | ||
206 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 242 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
207 | 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 | |||
208 | // The current velocity forward | 269 | // The current velocity forward |
209 | public virtual float ForwardSpeed | 270 | public virtual float ForwardSpeed |
210 | { | 271 | { |
@@ -226,10 +287,58 @@ public abstract class BSPhysObject : PhysicsActor | |||
226 | 287 | ||
227 | // 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 |
228 | // computed center-of-mass (like in linksets). | 289 | // computed center-of-mass (like in linksets). |
229 | 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 (IsPhysical && PhysBody.HasPhysicalBody) | ||
304 | PhysScene.PE.Activate(PhysBody, forceIt); | ||
305 | } | ||
230 | 306 | ||
231 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. | 307 | // 'actors' act on the physical object to change or constrain its motion. These can range from |
232 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free | 308 | // hovering to complex vehicle motion. |
309 | // May be called at non-taint time as this just adds the actor to the action list and the real | ||
310 | // work is done during the simulation step. | ||
311 | // Note that, if the actor is already in the list and we are disabling same, the actor is just left | ||
312 | // in the list disabled. | ||
313 | public delegate BSActor CreateActor(); | ||
314 | public void EnableActor(bool enableActor, string actorName, CreateActor creator) | ||
315 | { | ||
316 | lock (PhysicalActors) | ||
317 | { | ||
318 | BSActor theActor; | ||
319 | if (PhysicalActors.TryGetActor(actorName, out theActor)) | ||
320 | { | ||
321 | // The actor already exists so just turn it on or off | ||
322 | DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); | ||
323 | theActor.Enabled = enableActor; | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | // The actor does not exist. If it should, create it. | ||
328 | if (enableActor) | ||
329 | { | ||
330 | DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); | ||
331 | theActor = creator(); | ||
332 | PhysicalActors.Add(actorName, theActor); | ||
333 | theActor.Enabled = true; | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); | ||
338 | } | ||
339 | } | ||
340 | } | ||
341 | } | ||
233 | 342 | ||
234 | #region Collisions | 343 | #region Collisions |
235 | 344 | ||
@@ -247,70 +356,98 @@ public abstract class BSPhysObject : PhysicsActor | |||
247 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 356 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
248 | // On a collision, check the collider and remember if the last collider was moving | 357 | // On a collision, check the collider and remember if the last collider was moving |
249 | // Used to modify the standing of avatars (avatars on stationary things stand still) | 358 | // Used to modify the standing of avatars (avatars on stationary things stand still) |
250 | protected bool ColliderIsMoving; | 359 | public bool ColliderIsMoving; |
360 | // 'true' if the last collider was a volume detect object | ||
361 | public bool ColliderIsVolumeDetect; | ||
362 | // Used by BSCharacter to manage standing (and not slipping) | ||
363 | public bool IsStationary; | ||
251 | 364 | ||
252 | // Count of collisions for this object | 365 | // Count of collisions for this object |
253 | protected long CollisionAccumulation { get; set; } | 366 | protected long CollisionAccumulation { get; set; } |
254 | 367 | ||
255 | public override bool IsColliding { | 368 | public override bool IsColliding { |
256 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 369 | get { return (CollidingStep == PhysScene.SimulationStep); } |
257 | set { | 370 | set { |
258 | if (value) | 371 | if (value) |
259 | CollidingStep = PhysicsScene.SimulationStep; | 372 | CollidingStep = PhysScene.SimulationStep; |
260 | else | 373 | else |
261 | CollidingStep = 0; | 374 | CollidingStep = BSScene.NotASimulationStep; |
262 | } | 375 | } |
263 | } | 376 | } |
377 | // Complex objects (like linksets) need to know if there is a collision on any part of | ||
378 | // their shape. 'IsColliding' has an existing definition of reporting a collision on | ||
379 | // only this specific prim or component of linksets. | ||
380 | // 'HasSomeCollision' is defined as reporting if there is a collision on any part of | ||
381 | // the complex body that this prim is the root of. | ||
382 | public virtual bool HasSomeCollision | ||
383 | { | ||
384 | get { return IsColliding; } | ||
385 | set { IsColliding = value; } | ||
386 | } | ||
264 | public override bool CollidingGround { | 387 | public override bool CollidingGround { |
265 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 388 | get { return (CollidingGroundStep == PhysScene.SimulationStep); } |
266 | set | 389 | set |
267 | { | 390 | { |
268 | if (value) | 391 | if (value) |
269 | CollidingGroundStep = PhysicsScene.SimulationStep; | 392 | CollidingGroundStep = PhysScene.SimulationStep; |
270 | else | 393 | else |
271 | CollidingGroundStep = 0; | 394 | CollidingGroundStep = BSScene.NotASimulationStep; |
272 | } | 395 | } |
273 | } | 396 | } |
274 | public override bool CollidingObj { | 397 | public override bool CollidingObj { |
275 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | 398 | get { return (CollidingObjectStep == PhysScene.SimulationStep); } |
276 | set { | 399 | set { |
277 | if (value) | 400 | if (value) |
278 | CollidingObjectStep = PhysicsScene.SimulationStep; | 401 | CollidingObjectStep = PhysScene.SimulationStep; |
279 | else | 402 | else |
280 | CollidingObjectStep = 0; | 403 | CollidingObjectStep = BSScene.NotASimulationStep; |
281 | } | 404 | } |
282 | } | 405 | } |
283 | 406 | ||
284 | // The collisions that have been collected this tick | 407 | // The collisions that have been collected for the next collision reporting (throttled by subscription) |
285 | protected CollisionEventUpdate CollisionCollection; | 408 | protected CollisionEventUpdate CollisionCollection; |
286 | // Remember collisions from last tick for fancy collision based actions | 409 | // This is the collision collection last reported to the Simulator. |
410 | public CollisionEventUpdate CollisionsLastReported; | ||
411 | // Remember the collisions recorded in the last tick for fancy collision checking | ||
287 | // (like a BSCharacter walking up stairs). | 412 | // (like a BSCharacter walking up stairs). |
288 | protected CollisionEventUpdate CollisionsLastTick; | 413 | public CollisionEventUpdate CollisionsLastTick; |
414 | private long CollisionsLastTickStep = -1; | ||
289 | 415 | ||
290 | // The simulation step is telling this object about a collision. | 416 | // The simulation step is telling this object about a collision. |
291 | // Return 'true' if a collision was processed and should be sent up. | 417 | // Return 'true' if a collision was processed and should be sent up. |
292 | // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. | 418 | // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. |
293 | // Called at taint time from within the Step() function | 419 | // Called at taint time from within the Step() function |
420 | public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth); | ||
294 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | 421 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, |
295 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | 422 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) |
296 | { | 423 | { |
297 | bool ret = false; | 424 | bool ret = false; |
298 | 425 | ||
299 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work | 426 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
300 | CollidingStep = PhysicsScene.SimulationStep; | 427 | CollidingStep = PhysScene.SimulationStep; |
301 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 428 | if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) |
302 | { | 429 | { |
303 | CollidingGroundStep = PhysicsScene.SimulationStep; | 430 | CollidingGroundStep = PhysScene.SimulationStep; |
304 | } | 431 | } |
305 | else | 432 | else |
306 | { | 433 | { |
307 | CollidingObjectStep = PhysicsScene.SimulationStep; | 434 | CollidingObjectStep = PhysScene.SimulationStep; |
308 | } | 435 | } |
309 | 436 | ||
310 | CollisionAccumulation++; | 437 | CollisionAccumulation++; |
311 | 438 | ||
312 | // For movement tests, remember if we are colliding with an object that is moving. | 439 | // For movement tests, remember if we are colliding with an object that is moving. |
313 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | 440 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; |
441 | ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; | ||
442 | |||
443 | // Make a collection of the collisions that happened the last simulation tick. | ||
444 | // This is different than the collection created for sending up to the simulator as it is cleared every tick. | ||
445 | if (CollisionsLastTickStep != PhysScene.SimulationStep) | ||
446 | { | ||
447 | CollisionsLastTick = new CollisionEventUpdate(); | ||
448 | CollisionsLastTickStep = PhysScene.SimulationStep; | ||
449 | } | ||
450 | CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
314 | 451 | ||
315 | // If someone has subscribed for collision events log the collision so it will be reported up | 452 | // If someone has subscribed for collision events log the collision so it will be reported up |
316 | if (SubscribedEvents()) { | 453 | if (SubscribedEvents()) { |
@@ -332,12 +469,12 @@ public abstract class BSPhysObject : PhysicsActor | |||
332 | bool ret = true; | 469 | bool ret = true; |
333 | 470 | ||
334 | // If the 'no collision' call, force it to happen right now so quick collision_end | 471 | // If the 'no collision' call, force it to happen right now so quick collision_end |
335 | bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); | 472 | bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); |
336 | 473 | ||
337 | // throttle the collisions to the number of milliseconds specified in the subscription | 474 | // throttle the collisions to the number of milliseconds specified in the subscription |
338 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 475 | if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) |
339 | { | 476 | { |
340 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | 477 | NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; |
341 | 478 | ||
342 | // We are called if we previously had collisions. If there are no collisions | 479 | // We are called if we previously had collisions. If there are no collisions |
343 | // this time, send up one last empty event so OpenSim can sense collision end. | 480 | // this time, send up one last empty event so OpenSim can sense collision end. |
@@ -351,11 +488,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
351 | base.SendCollisionUpdate(CollisionCollection); | 488 | base.SendCollisionUpdate(CollisionCollection); |
352 | 489 | ||
353 | // Remember the collisions from this tick for some collision specific processing. | 490 | // Remember the collisions from this tick for some collision specific processing. |
354 | CollisionsLastTick = CollisionCollection; | 491 | CollisionsLastReported = CollisionCollection; |
355 | 492 | ||
356 | // The CollisionCollection instance is passed around in the simulator. | 493 | // The CollisionCollection instance is passed around in the simulator. |
357 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 494 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
358 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | 495 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, |
359 | // a race condition is created for the other users of this instance. | 496 | // a race condition is created for the other users of this instance. |
360 | CollisionCollection = new CollisionEventUpdate(); | 497 | CollisionCollection = new CollisionEventUpdate(); |
361 | } | 498 | } |
@@ -372,10 +509,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
372 | // make sure first collision happens | 509 | // make sure first collision happens |
373 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | 510 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); |
374 | 511 | ||
375 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 512 | PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
376 | { | 513 | { |
377 | if (PhysBody.HasPhysicalBody) | 514 | if (PhysBody.HasPhysicalBody) |
378 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 515 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
379 | }); | 516 | }); |
380 | } | 517 | } |
381 | else | 518 | else |
@@ -387,11 +524,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
387 | public override void UnSubscribeEvents() { | 524 | public override void UnSubscribeEvents() { |
388 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | 525 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); |
389 | SubscribedEventsMs = 0; | 526 | SubscribedEventsMs = 0; |
390 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 527 | PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
391 | { | 528 | { |
392 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. | 529 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
393 | if (PhysBody.HasPhysicalBody) | 530 | if (PhysBody.HasPhysicalBody) |
394 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 531 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
395 | }); | 532 | }); |
396 | } | 533 | } |
397 | // Return 'true' if the simulator wants collision events | 534 | // Return 'true' if the simulator wants collision events |
@@ -405,7 +542,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
405 | { | 542 | { |
406 | // Scale the collision count by the time since the last collision. | 543 | // Scale the collision count by the time since the last collision. |
407 | // The "+1" prevents dividing by zero. | 544 | // The "+1" prevents dividing by zero. |
408 | long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; | 545 | long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; |
409 | CollisionScore = CollisionAccumulation / timeAgo; | 546 | CollisionScore = CollisionAccumulation / timeAgo; |
410 | } | 547 | } |
411 | public override float CollisionScore { get; set; } | 548 | public override float CollisionScore { get; set; } |
@@ -413,103 +550,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
413 | #endregion // Collisions | 550 | #endregion // Collisions |
414 | 551 | ||
415 | #region Per Simulation Step actions | 552 | #region Per Simulation Step actions |
416 | // There are some actions that must be performed for a physical object before each simulation step. | ||
417 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
418 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
419 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
420 | private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
421 | private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>(); | ||
422 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
423 | { | ||
424 | string identifier = op + "-" + id.ToString(); | ||
425 | |||
426 | lock (RegisteredPrestepActions) | ||
427 | { | ||
428 | // Clean out any existing action | ||
429 | UnRegisterPreStepAction(op, id); | ||
430 | RegisteredPrestepActions[identifier] = actn; | ||
431 | PhysicsScene.BeforeStep += actn; | ||
432 | } | ||
433 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
434 | } | ||
435 | 553 | ||
436 | // Unregister a pre step action. Safe to call if the action has not been registered. | 554 | public BSActorCollection PhysicalActors; |
437 | // Returns 'true' if an action was actually removed | ||
438 | protected bool UnRegisterPreStepAction(string op, uint id) | ||
439 | { | ||
440 | string identifier = op + "-" + id.ToString(); | ||
441 | bool removed = false; | ||
442 | lock (RegisteredPrestepActions) | ||
443 | { | ||
444 | if (RegisteredPrestepActions.ContainsKey(identifier)) | ||
445 | { | ||
446 | PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier]; | ||
447 | RegisteredPrestepActions.Remove(identifier); | ||
448 | removed = true; | ||
449 | } | ||
450 | } | ||
451 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
452 | return removed; | ||
453 | } | ||
454 | |||
455 | protected void UnRegisterAllPreStepActions() | ||
456 | { | ||
457 | lock (RegisteredPrestepActions) | ||
458 | { | ||
459 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions) | ||
460 | { | ||
461 | PhysicsScene.BeforeStep -= kvp.Value; | ||
462 | } | ||
463 | RegisteredPrestepActions.Clear(); | ||
464 | } | ||
465 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
466 | } | ||
467 | |||
468 | protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn) | ||
469 | { | ||
470 | string identifier = op + "-" + id.ToString(); | ||
471 | |||
472 | lock (RegisteredPoststepActions) | ||
473 | { | ||
474 | // Clean out any existing action | ||
475 | UnRegisterPostStepAction(op, id); | ||
476 | RegisteredPoststepActions[identifier] = actn; | ||
477 | PhysicsScene.AfterStep += actn; | ||
478 | } | ||
479 | DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier); | ||
480 | } | ||
481 | |||
482 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
483 | // Returns 'true' if an action was actually removed. | ||
484 | protected bool UnRegisterPostStepAction(string op, uint id) | ||
485 | { | ||
486 | string identifier = op + "-" + id.ToString(); | ||
487 | bool removed = false; | ||
488 | lock (RegisteredPoststepActions) | ||
489 | { | ||
490 | if (RegisteredPoststepActions.ContainsKey(identifier)) | ||
491 | { | ||
492 | PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier]; | ||
493 | RegisteredPoststepActions.Remove(identifier); | ||
494 | removed = true; | ||
495 | } | ||
496 | } | ||
497 | DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
498 | return removed; | ||
499 | } | ||
500 | |||
501 | protected void UnRegisterAllPostStepActions() | ||
502 | { | ||
503 | lock (RegisteredPoststepActions) | ||
504 | { | ||
505 | foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions) | ||
506 | { | ||
507 | PhysicsScene.AfterStep -= kvp.Value; | ||
508 | } | ||
509 | RegisteredPoststepActions.Clear(); | ||
510 | } | ||
511 | DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID); | ||
512 | } | ||
513 | 555 | ||
514 | // When an update to the physical properties happens, this event is fired to let | 556 | // When an update to the physical properties happens, this event is fired to let |
515 | // different actors to modify the update before it is passed around | 557 | // different actors to modify the update before it is passed around |
@@ -522,53 +564,13 @@ public abstract class BSPhysObject : PhysicsActor | |||
522 | actions(ref entprop); | 564 | actions(ref entprop); |
523 | } | 565 | } |
524 | 566 | ||
525 | private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>(); | ||
526 | public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn) | ||
527 | { | ||
528 | lock (RegisteredPreUpdatePropertyActions) | ||
529 | { | ||
530 | // Clean out any existing action | ||
531 | UnRegisterPreUpdatePropertyAction(identifier); | ||
532 | RegisteredPreUpdatePropertyActions[identifier] = actn; | ||
533 | OnPreUpdateProperty += actn; | ||
534 | } | ||
535 | DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier); | ||
536 | } | ||
537 | public bool UnRegisterPreUpdatePropertyAction(string identifier) | ||
538 | { | ||
539 | bool removed = false; | ||
540 | lock (RegisteredPreUpdatePropertyActions) | ||
541 | { | ||
542 | if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier)) | ||
543 | { | ||
544 | OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier]; | ||
545 | RegisteredPreUpdatePropertyActions.Remove(identifier); | ||
546 | removed = true; | ||
547 | } | ||
548 | } | ||
549 | DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed); | ||
550 | return removed; | ||
551 | } | ||
552 | public void UnRegisterAllPreUpdatePropertyActions() | ||
553 | { | ||
554 | lock (RegisteredPreUpdatePropertyActions) | ||
555 | { | ||
556 | foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions) | ||
557 | { | ||
558 | OnPreUpdateProperty -= kvp.Value; | ||
559 | } | ||
560 | RegisteredPreUpdatePropertyActions.Clear(); | ||
561 | } | ||
562 | DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID); | ||
563 | } | ||
564 | |||
565 | #endregion // Per Simulation Step actions | 567 | #endregion // Per Simulation Step actions |
566 | 568 | ||
567 | // High performance detailed logging routine used by the physical objects. | 569 | // High performance detailed logging routine used by the physical objects. |
568 | protected void DetailLog(string msg, params Object[] args) | 570 | protected void DetailLog(string msg, params Object[] args) |
569 | { | 571 | { |
570 | if (PhysicsScene.PhysicsLogging.Enabled) | 572 | if (PhysScene.PhysicsLogging.Enabled) |
571 | PhysicsScene.DetailLog(msg, args); | 573 | PhysScene.DetailLog(msg, args); |
572 | } | 574 | } |
573 | 575 | ||
574 | } | 576 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 6a5461a..d5b999d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -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,16 +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 VehicleController { get; private set; } | 68 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. |
76 | 69 | public const string VehicleActorName = "BasicVehicle"; | |
77 | private BSVMotor _targetMotor; | ||
78 | private OMV.Vector3 _PIDTarget; | ||
79 | private float _PIDTau; | ||
80 | 70 | ||
81 | private BSFMotor _hoverMotor; | 71 | // Parameters for the hover actor |
82 | private float _PIDHoverHeight; | 72 | public const string HoverActorName = "BSPrim.HoverActor"; |
83 | private PIDHoverType _PIDHoverType; | 73 | // Parameters for the axis lock actor |
84 | 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"; | ||
85 | 80 | ||
86 | 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, |
87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 82 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -89,31 +84,34 @@ public class BSPrim : BSPhysObject | |||
89 | { | 84 | { |
90 | // 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); |
91 | _physicsActorType = (int)ActorTypes.Prim; | 86 | _physicsActorType = (int)ActorTypes.Prim; |
92 | _position = pos; | 87 | RawPosition = pos; |
93 | _size = size; | 88 | _size = size; |
94 | 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). |
95 | _orientation = rotation; | 90 | RawOrientation = rotation; |
96 | _buoyancy = 0f; | 91 | _buoyancy = 0f; |
97 | _velocity = OMV.Vector3.Zero; | 92 | RawVelocity = OMV.Vector3.Zero; |
98 | _rotationalVelocity = OMV.Vector3.Zero; | 93 | _rotationalVelocity = OMV.Vector3.Zero; |
99 | BaseShape = pbs; | 94 | BaseShape = pbs; |
100 | _isPhysical = pisPhysical; | 95 | _isPhysical = pisPhysical; |
101 | _isVolumeDetect = false; | 96 | _isVolumeDetect = false; |
102 | 97 | ||
103 | VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness | 98 | // Add a dynamic vehicle to our set of actors that can move this prim. |
99 | // PhysicalActors.Add(VehicleActorName, new BSDynamics(PhysScene, this, VehicleActorName)); | ||
104 | 100 | ||
105 | _mass = CalculateMass(); | 101 | _mass = CalculateMass(); |
106 | 102 | ||
107 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 103 | // DetailLog("{0},BSPrim.constructor,call", LocalID); |
108 | // do the actual object creation at taint time | 104 | // do the actual object creation at taint time |
109 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 105 | PhysScene.TaintedObject("BSPrim.create", delegate() |
110 | { | 106 | { |
111 | // Make sure the object is being created with some sanity. | 107 | // Make sure the object is being created with some sanity. |
112 | ExtremeSanityCheck(true /* inTaintTime */); | 108 | ExtremeSanityCheck(true /* inTaintTime */); |
113 | 109 | ||
114 | CreateGeomAndObject(true); | 110 | CreateGeomAndObject(true); |
115 | 111 | ||
116 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); | 112 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); |
113 | |||
114 | IsInitialized = true; | ||
117 | }); | 115 | }); |
118 | } | 116 | } |
119 | 117 | ||
@@ -121,19 +119,21 @@ public class BSPrim : BSPhysObject | |||
121 | public override void Destroy() | 119 | public override void Destroy() |
122 | { | 120 | { |
123 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 121 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
122 | IsInitialized = false; | ||
123 | |||
124 | base.Destroy(); | 124 | base.Destroy(); |
125 | 125 | ||
126 | // Undo any vehicle properties | 126 | // Undo any vehicle properties |
127 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 127 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
128 | 128 | ||
129 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | 129 | PhysScene.TaintedObject("BSPrim.Destroy", delegate() |
130 | { | 130 | { |
131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
132 | // 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. |
133 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null); | 133 | PhysScene.Shapes.DereferenceBody(PhysBody, null); |
134 | PhysBody.Clear(); | 134 | PhysBody.Clear(); |
135 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null); | 135 | PhysShape.Dereference(PhysScene); |
136 | PhysShape.Clear(); | 136 | PhysShape = new BSShapeNull(); |
137 | }); | 137 | }); |
138 | } | 138 | } |
139 | 139 | ||
@@ -159,25 +159,13 @@ public class BSPrim : BSPhysObject | |||
159 | ForceBodyShapeRebuild(false); | 159 | ForceBodyShapeRebuild(false); |
160 | } | 160 | } |
161 | } | 161 | } |
162 | // 'unknown' says to choose the best type | ||
163 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
164 | { get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } } | ||
165 | |||
166 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 162 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
167 | { | 163 | { |
168 | if (inTaintTime) | 164 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() |
169 | { | 165 | { |
170 | _mass = CalculateMass(); // changing the shape changes the mass | 166 | _mass = CalculateMass(); // changing the shape changes the mass |
171 | CreateGeomAndObject(true); | 167 | CreateGeomAndObject(true); |
172 | } | 168 | }); |
173 | else | ||
174 | { | ||
175 | PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", delegate() | ||
176 | { | ||
177 | _mass = CalculateMass(); // changing the shape changes the mass | ||
178 | CreateGeomAndObject(true); | ||
179 | }); | ||
180 | } | ||
181 | return true; | 169 | return true; |
182 | } | 170 | } |
183 | public override bool Grabbed { | 171 | public override bool Grabbed { |
@@ -190,7 +178,7 @@ public class BSPrim : BSPhysObject | |||
190 | if (value != _isSelected) | 178 | if (value != _isSelected) |
191 | { | 179 | { |
192 | _isSelected = value; | 180 | _isSelected = value; |
193 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 181 | PhysScene.TaintedObject("BSPrim.setSelected", delegate() |
194 | { | 182 | { |
195 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 183 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
196 | SetObjectDynamic(false); | 184 | SetObjectDynamic(false); |
@@ -231,165 +219,93 @@ public class BSPrim : BSPhysObject | |||
231 | // Called at taint time! | 219 | // Called at taint time! |
232 | public override void ZeroMotion(bool inTaintTime) | 220 | public override void ZeroMotion(bool inTaintTime) |
233 | { | 221 | { |
234 | _velocity = OMV.Vector3.Zero; | 222 | RawVelocity = OMV.Vector3.Zero; |
235 | _acceleration = OMV.Vector3.Zero; | 223 | _acceleration = OMV.Vector3.Zero; |
236 | _rotationalVelocity = OMV.Vector3.Zero; | 224 | _rotationalVelocity = OMV.Vector3.Zero; |
237 | 225 | ||
238 | // Zero some other properties in the physics engine | 226 | // Zero some other properties in the physics engine |
239 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 227 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
240 | { | 228 | { |
241 | if (PhysBody.HasPhysicalBody) | 229 | if (PhysBody.HasPhysicalBody) |
242 | PhysicsScene.PE.ClearAllForces(PhysBody); | 230 | PhysScene.PE.ClearAllForces(PhysBody); |
243 | }); | 231 | }); |
244 | } | 232 | } |
245 | public override void ZeroAngularMotion(bool inTaintTime) | 233 | public override void ZeroAngularMotion(bool inTaintTime) |
246 | { | 234 | { |
247 | _rotationalVelocity = OMV.Vector3.Zero; | 235 | _rotationalVelocity = OMV.Vector3.Zero; |
248 | // Zero some other properties in the physics engine | 236 | // Zero some other properties in the physics engine |
249 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 237 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
250 | { | 238 | { |
251 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | 239 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
252 | if (PhysBody.HasPhysicalBody) | 240 | if (PhysBody.HasPhysicalBody) |
253 | { | 241 | { |
254 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 242 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
255 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 243 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
256 | } | 244 | } |
257 | }); | 245 | }); |
258 | } | 246 | } |
259 | 247 | ||
260 | bool TryExperimentalLockAxisCode = false; | ||
261 | BSConstraint LockAxisConstraint = null; | ||
262 | public override void LockAngularMotion(OMV.Vector3 axis) | 248 | public override void LockAngularMotion(OMV.Vector3 axis) |
263 | { | 249 | { |
264 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 250 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
265 | 251 | ||
266 | // "1" means free, "0" means locked | 252 | // "1" means free, "0" means locked |
267 | OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); | 253 | OMV.Vector3 locking = LockedAxisFree; |
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 (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) | 259 | EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() |
274 | { | 260 | { |
275 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | 261 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); |
276 | // the other in the object. | 262 | }); |
277 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 | ||
278 | // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 | ||
279 | |||
280 | PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() | ||
281 | { | ||
282 | CleanUpLockAxisPhysicals(true /* inTaintTime */); | ||
283 | |||
284 | BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody, | ||
285 | OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation), | ||
286 | true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); | ||
287 | LockAxisConstraint = axisConstrainer; | ||
288 | PhysicsScene.Constraints.AddConstraint(LockAxisConstraint); | ||
289 | |||
290 | // The constraint is tied to the world and oriented to the prim. | ||
291 | |||
292 | // Free to move linearly | ||
293 | OMV.Vector3 linearLow = OMV.Vector3.Zero; | ||
294 | OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize; | ||
295 | axisConstrainer.SetLinearLimits(linearLow, linearHigh); | ||
296 | |||
297 | // Angular with some axis locked | ||
298 | float f2PI = (float)Math.PI * 2f; | ||
299 | OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI); | ||
300 | OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI); | ||
301 | if (LockedAxis.X != 1f) | ||
302 | { | ||
303 | angularLow.X = 0f; | ||
304 | angularHigh.X = 0f; | ||
305 | } | ||
306 | if (LockedAxis.Y != 1f) | ||
307 | { | ||
308 | angularLow.Y = 0f; | ||
309 | angularHigh.Y = 0f; | ||
310 | } | ||
311 | if (LockedAxis.Z != 1f) | ||
312 | { | ||
313 | angularLow.Z = 0f; | ||
314 | angularHigh.Z = 0f; | ||
315 | } | ||
316 | axisConstrainer.SetAngularLimits(angularLow, angularHigh); | ||
317 | |||
318 | DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}", | ||
319 | LocalID, linearLow, linearHigh, angularLow, angularHigh); | ||
320 | |||
321 | // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. | ||
322 | axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); | ||
323 | 263 | ||
324 | axisConstrainer.RecomputeConstraintVariables(RawMass); | 264 | // Update parameters so the new actor's Refresh() action is called at the right time. |
325 | }); | 265 | PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() |
326 | } | ||
327 | else | ||
328 | { | 266 | { |
329 | // Everything seems unlocked | 267 | UpdatePhysicalParameters(); |
330 | CleanUpLockAxisPhysicals(false /* inTaintTime */); | 268 | }); |
331 | } | ||
332 | 269 | ||
333 | return; | 270 | return; |
334 | } | 271 | } |
335 | // Get rid of any constraint built for LockAxis | ||
336 | // Most often the constraint is removed when the constraint collection is cleaned for this prim. | ||
337 | private void CleanUpLockAxisPhysicals(bool inTaintTime) | ||
338 | { | ||
339 | if (LockAxisConstraint != null) | ||
340 | { | ||
341 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate() | ||
342 | { | ||
343 | if (LockAxisConstraint != null) | ||
344 | { | ||
345 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); | ||
346 | LockAxisConstraint = null; | ||
347 | DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID); | ||
348 | } | ||
349 | }); | ||
350 | } | ||
351 | } | ||
352 | 272 | ||
353 | public override OMV.Vector3 RawPosition | ||
354 | { | ||
355 | get { return _position; } | ||
356 | set { _position = value; } | ||
357 | } | ||
358 | public override OMV.Vector3 Position { | 273 | public override OMV.Vector3 Position { |
359 | get { | 274 | get { |
360 | // 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. |
361 | // _position = ForcePosition; | 276 | // RawPosition = ForcePosition; |
362 | return _position; | 277 | return RawPosition; |
363 | } | 278 | } |
364 | set { | 279 | set { |
365 | // 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. |
366 | // All positions are given in world positions. | 281 | // All positions are given in world positions. |
367 | if (_position == value) | 282 | if (RawPosition == value) |
368 | { | 283 | { |
369 | 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); |
370 | return; | 285 | return; |
371 | } | 286 | } |
372 | _position = value; | 287 | RawPosition = value; |
373 | PositionSanityCheck(false); | 288 | PositionSanityCheck(false); |
374 | 289 | ||
375 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 290 | PhysScene.TaintedObject("BSPrim.setPosition", delegate() |
376 | { | 291 | { |
377 | 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); |
378 | ForcePosition = _position; | 293 | ForcePosition = RawPosition; |
379 | }); | 294 | }); |
380 | } | 295 | } |
381 | } | 296 | } |
382 | 297 | ||
298 | // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. | ||
383 | public override OMV.Vector3 ForcePosition { | 299 | public override OMV.Vector3 ForcePosition { |
384 | get { | 300 | get { |
385 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 301 | RawPosition = PhysScene.PE.GetPosition(PhysBody); |
386 | return _position; | 302 | return RawPosition; |
387 | } | 303 | } |
388 | set { | 304 | set { |
389 | _position = value; | 305 | RawPosition = value; |
390 | if (PhysBody.HasPhysicalBody) | 306 | if (PhysBody.HasPhysicalBody) |
391 | { | 307 | { |
392 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 308 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
393 | ActivateIfPhysical(false); | 309 | ActivateIfPhysical(false); |
394 | } | 310 | } |
395 | } | 311 | } |
@@ -406,7 +322,7 @@ public class BSPrim : BSPhysObject | |||
406 | if (!IsPhysicallyActive) | 322 | if (!IsPhysicallyActive) |
407 | return ret; | 323 | return ret; |
408 | 324 | ||
409 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 325 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
410 | { | 326 | { |
411 | // The physical object is out of the known/simulated area. | 327 | // The physical object is out of the known/simulated area. |
412 | // 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 |
@@ -414,7 +330,7 @@ public class BSPrim : BSPhysObject | |||
414 | return ret; | 330 | return ret; |
415 | } | 331 | } |
416 | 332 | ||
417 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 333 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
418 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 334 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
419 | 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)); |
420 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | 336 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) |
@@ -423,10 +339,10 @@ public class BSPrim : BSPhysObject | |||
423 | float targetHeight = terrainHeight + (Size.Z / 2f); | 339 | float targetHeight = terrainHeight + (Size.Z / 2f); |
424 | // 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 |
425 | // not get it through the terrain | 341 | // not get it through the terrain |
426 | _position.Z = targetHeight; | 342 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); |
427 | if (inTaintTime) | 343 | if (inTaintTime) |
428 | { | 344 | { |
429 | ForcePosition = _position; | 345 | ForcePosition = RawPosition; |
430 | } | 346 | } |
431 | // If we are throwing the object around, zero its other forces | 347 | // If we are throwing the object around, zero its other forces |
432 | ZeroMotion(inTaintTime); | 348 | ZeroMotion(inTaintTime); |
@@ -435,7 +351,7 @@ public class BSPrim : BSPhysObject | |||
435 | 351 | ||
436 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 352 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
437 | { | 353 | { |
438 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 354 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); |
439 | // TODO: a floating motor so object will bob in the water | 355 | // TODO: a floating motor so object will bob in the water |
440 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | 356 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
441 | { | 357 | { |
@@ -443,8 +359,8 @@ public class BSPrim : BSPhysObject | |||
443 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | 359 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
444 | 360 | ||
445 | // Apply upforce and overcome gravity. | 361 | // Apply upforce and overcome gravity. |
446 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | 362 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; |
447 | 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); |
448 | AddForce(correctionForce, false, inTaintTime); | 364 | AddForce(correctionForce, false, inTaintTime); |
449 | ret = true; | 365 | ret = true; |
450 | } | 366 | } |
@@ -463,17 +379,17 @@ public class BSPrim : BSPhysObject | |||
463 | uint wayOutThere = Constants.RegionSize * Constants.RegionSize; | 379 | uint wayOutThere = Constants.RegionSize * Constants.RegionSize; |
464 | // 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 |
465 | // the border crossing code. | 381 | // the border crossing code. |
466 | if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere | 382 | if ( RawPosition.X < -Constants.RegionSize || RawPosition.X > wayOutThere |
467 | || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere | 383 | || RawPosition.Y < -Constants.RegionSize || RawPosition.Y > wayOutThere |
468 | || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) | 384 | || RawPosition.Z < -Constants.RegionSize || RawPosition.Z > wayOutThere) |
469 | { | 385 | { |
470 | _position = new OMV.Vector3(10, 10, 50); | 386 | RawPosition = new OMV.Vector3(10, 10, 50); |
471 | ZeroMotion(inTaintTime); | 387 | ZeroMotion(inTaintTime); |
472 | ret = true; | 388 | ret = true; |
473 | } | 389 | } |
474 | if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) | 390 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) |
475 | { | 391 | { |
476 | _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); | 392 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
477 | ret = true; | 393 | ret = true; |
478 | } | 394 | } |
479 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | 395 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) |
@@ -498,7 +414,7 @@ public class BSPrim : BSPhysObject | |||
498 | get { return _mass; } | 414 | get { return _mass; } |
499 | } | 415 | } |
500 | // 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 |
501 | public override float RawMass { | 417 | public override float RawMass { |
502 | get { return _mass; } | 418 | get { return _mass; } |
503 | } | 419 | } |
504 | // Set the physical mass to the passed mass. | 420 | // Set the physical mass to the passed mass. |
@@ -509,10 +425,10 @@ public class BSPrim : BSPhysObject | |||
509 | { | 425 | { |
510 | if (IsStatic) | 426 | if (IsStatic) |
511 | { | 427 | { |
512 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); | 428 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); |
513 | Inertia = OMV.Vector3.Zero; | 429 | Inertia = OMV.Vector3.Zero; |
514 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); | 430 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
515 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 431 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
516 | } | 432 | } |
517 | else | 433 | else |
518 | { | 434 | { |
@@ -521,16 +437,19 @@ public class BSPrim : BSPhysObject | |||
521 | // Changing interesting properties doesn't change proxy and collision cache | 437 | // Changing interesting properties doesn't change proxy and collision cache |
522 | // 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 |
523 | // after parameters are changed. | 439 | // after parameters are changed. |
524 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 440 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
525 | } | 441 | } |
526 | 442 | ||
527 | // 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. |
528 | Gravity = ComputeGravity(Buoyancy); | 444 | Gravity = ComputeGravity(Buoyancy); |
529 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 445 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
530 | 446 | ||
531 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 447 | // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG |
532 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | 448 | // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG |
533 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 449 | |
450 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); | ||
451 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); | ||
452 | PhysScene.PE.UpdateInertiaTensor(PhysBody); | ||
534 | 453 | ||
535 | 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}", |
536 | LocalID, physMass, Inertia, Gravity, inWorld); | 455 | LocalID, physMass, Inertia, Gravity, inWorld); |
@@ -546,7 +465,7 @@ public class BSPrim : BSPhysObject | |||
546 | // Return what gravity should be set to this very moment | 465 | // Return what gravity should be set to this very moment |
547 | public OMV.Vector3 ComputeGravity(float buoyancy) | 466 | public OMV.Vector3 ComputeGravity(float buoyancy) |
548 | { | 467 | { |
549 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | 468 | OMV.Vector3 ret = PhysScene.DefaultGravity; |
550 | 469 | ||
551 | if (!IsStatic) | 470 | if (!IsStatic) |
552 | { | 471 | { |
@@ -570,95 +489,121 @@ public class BSPrim : BSPhysObject | |||
570 | } | 489 | } |
571 | 490 | ||
572 | public override OMV.Vector3 Force { | 491 | public override OMV.Vector3 Force { |
573 | get { return _force; } | 492 | get { return RawForce; } |
574 | set { | 493 | set { |
575 | _force = value; | 494 | RawForce = value; |
576 | if (_force != OMV.Vector3.Zero) | 495 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
577 | { | 496 | { |
578 | // If the force is non-zero, it must be reapplied each tick because | 497 | return new BSActorSetForce(PhysScene, this, SetForceActorName); |
579 | // Bullet clears the forces applied last frame. | 498 | }); |
580 | RegisterPreStepAction("BSPrim.setForce", LocalID, | 499 | } |
581 | delegate(float timeStep) | 500 | } |
582 | { | ||
583 | if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) | ||
584 | { | ||
585 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
586 | return; | ||
587 | } | ||
588 | 501 | ||
589 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | 502 | // Find and return a handle to the current vehicle actor. |
590 | if (PhysBody.HasPhysicalBody) | 503 | // Return 'null' if there is no vehicle actor. |
591 | { | 504 | public BSDynamics GetVehicleActor(bool createIfNone) |
592 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | 505 | { |
593 | ActivateIfPhysical(false); | 506 | BSDynamics ret = null; |
594 | } | 507 | BSActor actor; |
595 | } | 508 | if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) |
596 | ); | 509 | { |
597 | } | 510 | ret = actor as BSDynamics; |
598 | else | 511 | } |
512 | else | ||
513 | { | ||
514 | if (createIfNone) | ||
599 | { | 515 | { |
600 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | 516 | ret = new BSDynamics(PhysScene, this, VehicleActorName); |
517 | PhysicalActors.Add(ret.ActorName, ret); | ||
601 | } | 518 | } |
602 | } | 519 | } |
520 | return ret; | ||
603 | } | 521 | } |
604 | 522 | ||
605 | public override int VehicleType { | 523 | public override int VehicleType { |
606 | get { | 524 | get { |
607 | return (int)VehicleController.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; | ||
608 | } | 530 | } |
609 | set { | 531 | set { |
610 | Vehicle type = (Vehicle)value; | 532 | Vehicle type = (Vehicle)value; |
611 | 533 | ||
612 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 534 | PhysScene.TaintedObject("setVehicleType", delegate() |
613 | { | 535 | { |
614 | // 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 |
615 | // Vehicle code changes the parameters for this vehicle type. | 537 | // change all the parameters. Like a plane changing to CAR when on the |
616 | VehicleController.ProcessTypeChange(type); | 538 | // ground. In this case, don't want to zero motion. |
617 | ActivateIfPhysical(false); | 539 | // ZeroMotion(true /* inTaintTime */); |
618 | 540 | if (type == Vehicle.TYPE_NONE) | |
619 | // If an active vehicle, register the vehicle code to be called before each step | ||
620 | if (VehicleController.Type == Vehicle.TYPE_NONE) | ||
621 | { | 541 | { |
622 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | 542 | // Vehicle type is 'none' so get rid of any actor that may have been allocated. |
623 | UnRegisterPostStepAction("BSPrim.Vehicle", LocalID); | 543 | BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); |
544 | if (vehicleActor != null) | ||
545 | { | ||
546 | PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); | ||
547 | } | ||
624 | } | 548 | } |
625 | else | 549 | else |
626 | { | 550 | { |
627 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step); | 551 | // Vehicle type is not 'none' so create an actor and set it running. |
628 | RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep); | 552 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
553 | if (vehicleActor != null) | ||
554 | { | ||
555 | vehicleActor.ProcessTypeChange(type); | ||
556 | ActivateIfPhysical(false); | ||
557 | } | ||
629 | } | 558 | } |
630 | }); | 559 | }); |
631 | } | 560 | } |
632 | } | 561 | } |
633 | public override void VehicleFloatParam(int param, float value) | 562 | public override void VehicleFloatParam(int param, float value) |
634 | { | 563 | { |
635 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 564 | PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
636 | { | 565 | { |
637 | VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); | 566 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
638 | ActivateIfPhysical(false); | 567 | if (vehicleActor != null) |
568 | { | ||
569 | vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); | ||
570 | ActivateIfPhysical(false); | ||
571 | } | ||
639 | }); | 572 | }); |
640 | } | 573 | } |
641 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 574 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
642 | { | 575 | { |
643 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 576 | PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
644 | { | 577 | { |
645 | VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); | 578 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
646 | ActivateIfPhysical(false); | 579 | if (vehicleActor != null) |
580 | { | ||
581 | vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); | ||
582 | ActivateIfPhysical(false); | ||
583 | } | ||
647 | }); | 584 | }); |
648 | } | 585 | } |
649 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 586 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
650 | { | 587 | { |
651 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 588 | PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
652 | { | 589 | { |
653 | VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); | 590 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
654 | ActivateIfPhysical(false); | 591 | if (vehicleActor != null) |
592 | { | ||
593 | vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
594 | ActivateIfPhysical(false); | ||
595 | } | ||
655 | }); | 596 | }); |
656 | } | 597 | } |
657 | public override void VehicleFlags(int param, bool remove) | 598 | public override void VehicleFlags(int param, bool remove) |
658 | { | 599 | { |
659 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 600 | PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
660 | { | 601 | { |
661 | VehicleController.ProcessVehicleFlags(param, remove); | 602 | BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); |
603 | if (vehicleActor != null) | ||
604 | { | ||
605 | vehicleActor.ProcessVehicleFlags(param, remove); | ||
606 | } | ||
662 | }); | 607 | }); |
663 | } | 608 | } |
664 | 609 | ||
@@ -668,7 +613,7 @@ public class BSPrim : BSPhysObject | |||
668 | if (_isVolumeDetect != newValue) | 613 | if (_isVolumeDetect != newValue) |
669 | { | 614 | { |
670 | _isVolumeDetect = newValue; | 615 | _isVolumeDetect = newValue; |
671 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | 616 | PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
672 | { | 617 | { |
673 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | 618 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); |
674 | SetObjectDynamic(true); | 619 | SetObjectDynamic(true); |
@@ -676,10 +621,14 @@ public class BSPrim : BSPhysObject | |||
676 | } | 621 | } |
677 | return; | 622 | return; |
678 | } | 623 | } |
624 | public override bool IsVolumeDetect | ||
625 | { | ||
626 | get { return _isVolumeDetect; } | ||
627 | } | ||
679 | public override void SetMaterial(int material) | 628 | public override void SetMaterial(int material) |
680 | { | 629 | { |
681 | base.SetMaterial(material); | 630 | base.SetMaterial(material); |
682 | PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() | 631 | PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() |
683 | { | 632 | { |
684 | UpdatePhysicalParameters(); | 633 | UpdatePhysicalParameters(); |
685 | }); | 634 | }); |
@@ -692,7 +641,7 @@ public class BSPrim : BSPhysObject | |||
692 | if (base.Friction != value) | 641 | if (base.Friction != value) |
693 | { | 642 | { |
694 | base.Friction = value; | 643 | base.Friction = value; |
695 | PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() | 644 | PhysScene.TaintedObject("BSPrim.setFriction", delegate() |
696 | { | 645 | { |
697 | UpdatePhysicalParameters(); | 646 | UpdatePhysicalParameters(); |
698 | }); | 647 | }); |
@@ -707,7 +656,7 @@ public class BSPrim : BSPhysObject | |||
707 | if (base.Restitution != value) | 656 | if (base.Restitution != value) |
708 | { | 657 | { |
709 | base.Restitution = value; | 658 | base.Restitution = value; |
710 | PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() | 659 | PhysScene.TaintedObject("BSPrim.setRestitution", delegate() |
711 | { | 660 | { |
712 | UpdatePhysicalParameters(); | 661 | UpdatePhysicalParameters(); |
713 | }); | 662 | }); |
@@ -724,7 +673,7 @@ public class BSPrim : BSPhysObject | |||
724 | if (base.Density != value) | 673 | if (base.Density != value) |
725 | { | 674 | { |
726 | base.Density = value; | 675 | base.Density = value; |
727 | PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() | 676 | PhysScene.TaintedObject("BSPrim.setDensity", delegate() |
728 | { | 677 | { |
729 | UpdatePhysicalParameters(); | 678 | UpdatePhysicalParameters(); |
730 | }); | 679 | }); |
@@ -739,93 +688,66 @@ public class BSPrim : BSPhysObject | |||
739 | if (base.GravModifier != value) | 688 | if (base.GravModifier != value) |
740 | { | 689 | { |
741 | base.GravModifier = value; | 690 | base.GravModifier = value; |
742 | PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() | 691 | PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() |
743 | { | 692 | { |
744 | UpdatePhysicalParameters(); | 693 | UpdatePhysicalParameters(); |
745 | }); | 694 | }); |
746 | } | 695 | } |
747 | } | 696 | } |
748 | } | 697 | } |
749 | public override OMV.Vector3 RawVelocity | ||
750 | { | ||
751 | get { return _velocity; } | ||
752 | set { _velocity = value; } | ||
753 | } | ||
754 | public override OMV.Vector3 Velocity { | 698 | public override OMV.Vector3 Velocity { |
755 | get { return _velocity; } | 699 | get { return RawVelocity; } |
756 | set { | 700 | set { |
757 | _velocity = value; | 701 | RawVelocity = value; |
758 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 702 | PhysScene.TaintedObject("BSPrim.setVelocity", delegate() |
759 | { | 703 | { |
760 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 704 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
761 | ForceVelocity = _velocity; | 705 | ForceVelocity = RawVelocity; |
762 | }); | 706 | }); |
763 | } | 707 | } |
764 | } | 708 | } |
765 | public override OMV.Vector3 ForceVelocity { | 709 | public override OMV.Vector3 ForceVelocity { |
766 | get { return _velocity; } | 710 | get { return RawVelocity; } |
767 | set { | 711 | set { |
768 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | 712 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
769 | 713 | ||
770 | _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | 714 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
771 | if (PhysBody.HasPhysicalBody) | 715 | if (PhysBody.HasPhysicalBody) |
772 | { | 716 | { |
773 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); | 717 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
774 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 718 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
775 | ActivateIfPhysical(false); | 719 | ActivateIfPhysical(false); |
776 | } | 720 | } |
777 | } | 721 | } |
778 | } | 722 | } |
779 | public override OMV.Vector3 Torque { | 723 | public override OMV.Vector3 Torque { |
780 | get { return _torque; } | 724 | get { return RawTorque; } |
781 | set { | 725 | set { |
782 | _torque = value; | 726 | RawTorque = value; |
783 | if (_torque != OMV.Vector3.Zero) | 727 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() |
784 | { | ||
785 | // If the torque is non-zero, it must be reapplied each tick because | ||
786 | // Bullet clears the forces applied last frame. | ||
787 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | ||
788 | delegate(float timeStep) | ||
789 | { | ||
790 | if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero) | ||
791 | { | ||
792 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
793 | return; | ||
794 | } | ||
795 | |||
796 | if (PhysBody.HasPhysicalBody) | ||
797 | AddAngularForce(_torque, false, true); | ||
798 | } | ||
799 | ); | ||
800 | } | ||
801 | else | ||
802 | { | 728 | { |
803 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | 729 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); |
804 | } | 730 | }); |
805 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 731 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
806 | } | 732 | } |
807 | } | 733 | } |
808 | public override OMV.Vector3 Acceleration { | 734 | public override OMV.Vector3 Acceleration { |
809 | get { return _acceleration; } | 735 | get { return _acceleration; } |
810 | set { _acceleration = value; } | 736 | set { _acceleration = value; } |
811 | } | 737 | } |
812 | public override OMV.Quaternion RawOrientation | 738 | |
813 | { | ||
814 | get { return _orientation; } | ||
815 | set { _orientation = value; } | ||
816 | } | ||
817 | public override OMV.Quaternion Orientation { | 739 | public override OMV.Quaternion Orientation { |
818 | get { | 740 | get { |
819 | return _orientation; | 741 | return RawOrientation; |
820 | } | 742 | } |
821 | set { | 743 | set { |
822 | if (_orientation == value) | 744 | if (RawOrientation == value) |
823 | return; | 745 | return; |
824 | _orientation = value; | 746 | RawOrientation = value; |
825 | 747 | ||
826 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 748 | PhysScene.TaintedObject("BSPrim.setOrientation", delegate() |
827 | { | 749 | { |
828 | ForceOrientation = _orientation; | 750 | ForceOrientation = RawOrientation; |
829 | }); | 751 | }); |
830 | } | 752 | } |
831 | } | 753 | } |
@@ -834,14 +756,14 @@ public class BSPrim : BSPhysObject | |||
834 | { | 756 | { |
835 | get | 757 | get |
836 | { | 758 | { |
837 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 759 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); |
838 | return _orientation; | 760 | return RawOrientation; |
839 | } | 761 | } |
840 | set | 762 | set |
841 | { | 763 | { |
842 | _orientation = value; | 764 | RawOrientation = value; |
843 | if (PhysBody.HasPhysicalBody) | 765 | if (PhysBody.HasPhysicalBody) |
844 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 766 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
845 | } | 767 | } |
846 | } | 768 | } |
847 | public override int PhysicsActorType { | 769 | public override int PhysicsActorType { |
@@ -854,7 +776,7 @@ public class BSPrim : BSPhysObject | |||
854 | if (_isPhysical != value) | 776 | if (_isPhysical != value) |
855 | { | 777 | { |
856 | _isPhysical = value; | 778 | _isPhysical = value; |
857 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 779 | PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
858 | { | 780 | { |
859 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 781 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
860 | SetObjectDynamic(true); | 782 | SetObjectDynamic(true); |
@@ -898,24 +820,25 @@ public class BSPrim : BSPhysObject | |||
898 | // isSolid: other objects bounce off of this object | 820 | // isSolid: other objects bounce off of this object |
899 | // isVolumeDetect: other objects pass through but can generate collisions | 821 | // isVolumeDetect: other objects pass through but can generate collisions |
900 | // 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. | ||
901 | public virtual void UpdatePhysicalParameters() | 824 | public virtual void UpdatePhysicalParameters() |
902 | { | 825 | { |
903 | if (!PhysBody.HasPhysicalBody) | 826 | if (!PhysBody.HasPhysicalBody) |
904 | { | 827 | { |
905 | // 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. |
906 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); | 829 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); |
907 | return; | 830 | return; |
908 | } | 831 | } |
909 | 832 | ||
910 | // 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. |
911 | // 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). |
912 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 835 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
913 | 836 | ||
914 | // 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) |
915 | MakeDynamic(IsStatic); | 838 | MakeDynamic(IsStatic); |
916 | 839 | ||
917 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 840 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
918 | VehicleController.Refresh(); | 841 | PhysicalActors.Refresh(); |
919 | 842 | ||
920 | // Arrange for collision events if the simulator wants them | 843 | // Arrange for collision events if the simulator wants them |
921 | EnableCollisions(SubscribedEvents()); | 844 | EnableCollisions(SubscribedEvents()); |
@@ -926,10 +849,11 @@ public class BSPrim : BSPhysObject | |||
926 | AddObjectToPhysicalWorld(); | 849 | AddObjectToPhysicalWorld(); |
927 | 850 | ||
928 | // Rebuild its shape | 851 | // Rebuild its shape |
929 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 852 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
930 | 853 | ||
931 | 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}", |
932 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | 855 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), |
856 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | ||
933 | } | 857 | } |
934 | 858 | ||
935 | // "Making dynamic" means changing to and from static. | 859 | // "Making dynamic" means changing to and from static. |
@@ -942,28 +866,28 @@ public class BSPrim : BSPhysObject | |||
942 | if (makeStatic) | 866 | if (makeStatic) |
943 | { | 867 | { |
944 | // Become a Bullet 'static' object type | 868 | // Become a Bullet 'static' object type |
945 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 869 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
946 | // Stop all movement | 870 | // Stop all movement |
947 | ZeroMotion(true); | 871 | ZeroMotion(true); |
948 | 872 | ||
949 | // Set various physical properties so other object interact properly | 873 | // Set various physical properties so other object interact properly |
950 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 874 | PhysScene.PE.SetFriction(PhysBody, Friction); |
951 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 875 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
952 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 876 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
953 | 877 | ||
954 | // 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 |
955 | UpdatePhysicalMassProperties(0f, false); | 879 | UpdatePhysicalMassProperties(0f, false); |
956 | // Set collision detection parameters | 880 | // Set collision detection parameters |
957 | if (BSParam.CcdMotionThreshold > 0f) | 881 | if (BSParam.CcdMotionThreshold > 0f) |
958 | { | 882 | { |
959 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 883 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
960 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 884 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
961 | } | 885 | } |
962 | 886 | ||
963 | // 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. |
964 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); | 888 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
965 | // Start it out sleeping and physical actions could wake it up. | 889 | // Start it out sleeping and physical actions could wake it up. |
966 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); | 890 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
967 | 891 | ||
968 | // This collides like a static object | 892 | // This collides like a static object |
969 | PhysBody.collisionType = CollisionType.Static; | 893 | PhysBody.collisionType = CollisionType.Static; |
@@ -971,11 +895,11 @@ public class BSPrim : BSPhysObject | |||
971 | else | 895 | else |
972 | { | 896 | { |
973 | // Not a Bullet static object | 897 | // Not a Bullet static object |
974 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 898 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
975 | 899 | ||
976 | // Set various physical properties so other object interact properly | 900 | // Set various physical properties so other object interact properly |
977 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 901 | PhysScene.PE.SetFriction(PhysBody, Friction); |
978 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 902 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
979 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); | 903 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); |
980 | 904 | ||
981 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 905 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
@@ -983,8 +907,8 @@ public class BSPrim : BSPhysObject | |||
983 | // PhysicsScene.PE.ClearAllForces(BSBody); | 907 | // PhysicsScene.PE.ClearAllForces(BSBody); |
984 | 908 | ||
985 | // 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 |
986 | ForcePosition = _position; | 910 | ForcePosition = RawPosition; |
987 | ForceVelocity = _velocity; | 911 | ForceVelocity = RawVelocity; |
988 | ForceRotationalVelocity = _rotationalVelocity; | 912 | ForceRotationalVelocity = _rotationalVelocity; |
989 | 913 | ||
990 | // A dynamic object has mass | 914 | // A dynamic object has mass |
@@ -993,22 +917,22 @@ public class BSPrim : BSPhysObject | |||
993 | // Set collision detection parameters | 917 | // Set collision detection parameters |
994 | if (BSParam.CcdMotionThreshold > 0f) | 918 | if (BSParam.CcdMotionThreshold > 0f) |
995 | { | 919 | { |
996 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 920 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
997 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 921 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
998 | } | 922 | } |
999 | 923 | ||
1000 | // Various values for simulation limits | 924 | // Various values for simulation limits |
1001 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); | 925 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
1002 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); | 926 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
1003 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | 927 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
1004 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 928 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
1005 | 929 | ||
1006 | // This collides like an object. | 930 | // This collides like an object. |
1007 | PhysBody.collisionType = CollisionType.Dynamic; | 931 | PhysBody.collisionType = CollisionType.Dynamic; |
1008 | 932 | ||
1009 | // Force activation of the object so Bullet will act on it. | 933 | // Force activation of the object so Bullet will act on it. |
1010 | // 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. |
1011 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 935 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
1012 | } | 936 | } |
1013 | } | 937 | } |
1014 | 938 | ||
@@ -1018,7 +942,7 @@ public class BSPrim : BSPhysObject | |||
1018 | // 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. |
1019 | private void MakeSolid(bool makeSolid) | 943 | private void MakeSolid(bool makeSolid) |
1020 | { | 944 | { |
1021 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); | 945 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); |
1022 | if (makeSolid) | 946 | if (makeSolid) |
1023 | { | 947 | { |
1024 | // 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. |
@@ -1026,7 +950,7 @@ public class BSPrim : BSPhysObject | |||
1026 | { | 950 | { |
1027 | 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); |
1028 | } | 952 | } |
1029 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 953 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1030 | } | 954 | } |
1031 | else | 955 | else |
1032 | { | 956 | { |
@@ -1034,32 +958,23 @@ public class BSPrim : BSPhysObject | |||
1034 | { | 958 | { |
1035 | 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); |
1036 | } | 960 | } |
1037 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 961 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1038 | 962 | ||
1039 | // 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 |
1040 | PhysBody.collisionType = CollisionType.VolumeDetect; | 964 | PhysBody.collisionType = CollisionType.VolumeDetect; |
1041 | } | 965 | } |
1042 | } | 966 | } |
1043 | 967 | ||
1044 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
1045 | // they need waking up when parameters are changed. | ||
1046 | // Called in taint-time!! | ||
1047 | private void ActivateIfPhysical(bool forceIt) | ||
1048 | { | ||
1049 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
1050 | PhysicsScene.PE.Activate(PhysBody, forceIt); | ||
1051 | } | ||
1052 | |||
1053 | // 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. |
1054 | private void EnableCollisions(bool wantsCollisionEvents) | 969 | private void EnableCollisions(bool wantsCollisionEvents) |
1055 | { | 970 | { |
1056 | if (wantsCollisionEvents) | 971 | if (wantsCollisionEvents) |
1057 | { | 972 | { |
1058 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 973 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1059 | } | 974 | } |
1060 | else | 975 | else |
1061 | { | 976 | { |
1062 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 977 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1063 | } | 978 | } |
1064 | } | 979 | } |
1065 | 980 | ||
@@ -1070,7 +985,7 @@ public class BSPrim : BSPhysObject | |||
1070 | { | 985 | { |
1071 | if (PhysBody.HasPhysicalBody) | 986 | if (PhysBody.HasPhysicalBody) |
1072 | { | 987 | { |
1073 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 988 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
1074 | } | 989 | } |
1075 | else | 990 | else |
1076 | { | 991 | { |
@@ -1105,12 +1020,12 @@ public class BSPrim : BSPhysObject | |||
1105 | public override bool FloatOnWater { | 1020 | public override bool FloatOnWater { |
1106 | set { | 1021 | set { |
1107 | _floatOnWater = value; | 1022 | _floatOnWater = value; |
1108 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 1023 | PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
1109 | { | 1024 | { |
1110 | if (_floatOnWater) | 1025 | if (_floatOnWater) |
1111 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 1026 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1112 | else | 1027 | else |
1113 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 1028 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1114 | }); | 1029 | }); |
1115 | } | 1030 | } |
1116 | } | 1031 | } |
@@ -1122,7 +1037,7 @@ public class BSPrim : BSPhysObject | |||
1122 | _rotationalVelocity = value; | 1037 | _rotationalVelocity = value; |
1123 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | 1038 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); |
1124 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 1039 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
1125 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 1040 | PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
1126 | { | 1041 | { |
1127 | ForceRotationalVelocity = _rotationalVelocity; | 1042 | ForceRotationalVelocity = _rotationalVelocity; |
1128 | }); | 1043 | }); |
@@ -1137,7 +1052,7 @@ public class BSPrim : BSPhysObject | |||
1137 | if (PhysBody.HasPhysicalBody) | 1052 | if (PhysBody.HasPhysicalBody) |
1138 | { | 1053 | { |
1139 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 1054 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
1140 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 1055 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
1141 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 1056 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
1142 | ActivateIfPhysical(false); | 1057 | ActivateIfPhysical(false); |
1143 | } | 1058 | } |
@@ -1153,7 +1068,7 @@ public class BSPrim : BSPhysObject | |||
1153 | get { return _buoyancy; } | 1068 | get { return _buoyancy; } |
1154 | set { | 1069 | set { |
1155 | _buoyancy = value; | 1070 | _buoyancy = value; |
1156 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 1071 | PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
1157 | { | 1072 | { |
1158 | ForceBuoyancy = _buoyancy; | 1073 | ForceBuoyancy = _buoyancy; |
1159 | }); | 1074 | }); |
@@ -1171,179 +1086,54 @@ public class BSPrim : BSPhysObject | |||
1171 | } | 1086 | } |
1172 | } | 1087 | } |
1173 | 1088 | ||
1174 | // Used for MoveTo | ||
1175 | public override OMV.Vector3 PIDTarget { | ||
1176 | set | ||
1177 | { | ||
1178 | // TODO: add a sanity check -- don't move more than a region or something like that. | ||
1179 | _PIDTarget = value; | ||
1180 | } | ||
1181 | } | ||
1182 | public override float PIDTau { | ||
1183 | set { _PIDTau = value; } | ||
1184 | } | ||
1185 | public override bool PIDActive { | 1089 | public override bool PIDActive { |
1186 | set { | 1090 | set { |
1187 | if (value) | 1091 | base.MoveToTargetActive = value; |
1092 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() | ||
1188 | { | 1093 | { |
1189 | // We're taking over after this. | 1094 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); |
1190 | ZeroMotion(true); | 1095 | }); |
1191 | 1096 | } | |
1192 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | 1097 | } |
1193 | _PIDTau, // timeScale | ||
1194 | BSMotor.Infinite, // decay time scale | ||
1195 | BSMotor.InfiniteVector, // friction timescale | ||
1196 | 1f // efficiency | ||
1197 | ); | ||
1198 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1199 | _targetMotor.SetTarget(_PIDTarget); | ||
1200 | _targetMotor.SetCurrent(RawPosition); | ||
1201 | /* | ||
1202 | _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget"); | ||
1203 | _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1204 | |||
1205 | _targetMotor.SetTarget(_PIDTarget); | ||
1206 | _targetMotor.SetCurrent(RawPosition); | ||
1207 | _targetMotor.TimeScale = _PIDTau; | ||
1208 | _targetMotor.Efficiency = 1f; | ||
1209 | */ | ||
1210 | |||
1211 | RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep) | ||
1212 | { | ||
1213 | if (!IsPhysicallyActive) | ||
1214 | { | ||
1215 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | ||
1216 | return; | ||
1217 | } | ||
1218 | |||
1219 | OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below) | ||
1220 | |||
1221 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
1222 | OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep); | ||
1223 | 1098 | ||
1224 | // If we are very close to our target, turn off the movement motor. | 1099 | public override OMV.Vector3 PIDTarget |
1225 | if (_targetMotor.ErrorIsZero()) | 1100 | { |
1226 | { | 1101 | set |
1227 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | 1102 | { |
1228 | LocalID, movePosition, RawPosition, Mass); | 1103 | base.PIDTarget = value; |
1229 | ForcePosition = _targetMotor.TargetValue; | 1104 | BSActor actor; |
1230 | _targetMotor.Enabled = false; | 1105 | if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) |
1231 | } | ||
1232 | else | ||
1233 | { | ||
1234 | _position = movePosition; | ||
1235 | PositionSanityCheck(true /* intaintTime */); | ||
1236 | ForcePosition = _position; | ||
1237 | } | ||
1238 | DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition); | ||
1239 | }); | ||
1240 | } | ||
1241 | else | ||
1242 | { | 1106 | { |
1243 | // Stop any targetting | 1107 | // if the actor exists, tell it to refresh its values. |
1244 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | 1108 | actor.Refresh(); |
1245 | } | 1109 | } |
1110 | |||
1246 | } | 1111 | } |
1247 | } | 1112 | } |
1248 | |||
1249 | // Used for llSetHoverHeight and maybe vehicle height | 1113 | // Used for llSetHoverHeight and maybe vehicle height |
1250 | // Hover Height will override MoveTo target's Z | 1114 | // Hover Height will override MoveTo target's Z |
1251 | public override bool PIDHoverActive { | 1115 | public override bool PIDHoverActive { |
1252 | set { | 1116 | set { |
1253 | if (value) | 1117 | base.HoverActive = value; |
1118 | EnableActor(HoverActive, HoverActorName, delegate() | ||
1254 | { | 1119 | { |
1255 | // Turning the target on | 1120 | return new BSActorHover(PhysScene, this, HoverActorName); |
1256 | _hoverMotor = new BSFMotor("BSPrim.Hover", | 1121 | }); |
1257 | _PIDHoverTau, // timeScale | ||
1258 | BSMotor.Infinite, // decay time scale | ||
1259 | BSMotor.Infinite, // friction timescale | ||
1260 | 1f // efficiency | ||
1261 | ); | ||
1262 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1263 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1264 | _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
1265 | |||
1266 | RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep) | ||
1267 | { | ||
1268 | // Don't do hovering while the object is selected. | ||
1269 | if (!IsPhysicallyActive) | ||
1270 | return; | ||
1271 | |||
1272 | _hoverMotor.SetCurrent(RawPosition.Z); | ||
1273 | _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight()); | ||
1274 | float targetHeight = _hoverMotor.Step(timeStep); | ||
1275 | |||
1276 | // 'targetHeight' is where we'd like the Z of the prim to be at this moment. | ||
1277 | // Compute the amount of force to push us there. | ||
1278 | float moveForce = (targetHeight - RawPosition.Z) * Mass; | ||
1279 | // Undo anything the object thinks it's doing at the moment | ||
1280 | moveForce = -RawVelocity.Z * Mass; | ||
1281 | |||
1282 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce)); | ||
1283 | DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass); | ||
1284 | }); | ||
1285 | } | ||
1286 | else | ||
1287 | { | ||
1288 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | ||
1289 | } | ||
1290 | } | ||
1291 | } | ||
1292 | public override float PIDHoverHeight { | ||
1293 | set { _PIDHoverHeight = value; } | ||
1294 | } | ||
1295 | public override PIDHoverType PIDHoverType { | ||
1296 | set { _PIDHoverType = value; } | ||
1297 | } | ||
1298 | public override float PIDHoverTau { | ||
1299 | set { _PIDHoverTau = value; } | ||
1300 | } | ||
1301 | // Based on current position, determine what we should be hovering at now. | ||
1302 | // Must recompute often. What if we walked offa cliff> | ||
1303 | private float ComputeCurrentPIDHoverHeight() | ||
1304 | { | ||
1305 | float ret = _PIDHoverHeight; | ||
1306 | float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | ||
1307 | |||
1308 | switch (_PIDHoverType) | ||
1309 | { | ||
1310 | case PIDHoverType.Ground: | ||
1311 | ret = groundHeight + _PIDHoverHeight; | ||
1312 | break; | ||
1313 | case PIDHoverType.GroundAndWater: | ||
1314 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); | ||
1315 | if (groundHeight > waterHeight) | ||
1316 | { | ||
1317 | ret = groundHeight + _PIDHoverHeight; | ||
1318 | } | ||
1319 | else | ||
1320 | { | ||
1321 | ret = waterHeight + _PIDHoverHeight; | ||
1322 | } | ||
1323 | break; | ||
1324 | } | 1122 | } |
1325 | return ret; | ||
1326 | } | 1123 | } |
1327 | 1124 | ||
1328 | |||
1329 | // For RotLookAt | ||
1330 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
1331 | public override bool APIDActive { set { return; } } | ||
1332 | public override float APIDStrength { set { return; } } | ||
1333 | public override float APIDDamping { set { return; } } | ||
1334 | |||
1335 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1125 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
1336 | // Per documentation, max force is limited. | 1126 | // Per documentation, max force is limited. |
1337 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 1127 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
1338 | 1128 | ||
1339 | // 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. |
1340 | addForce /= PhysicsScene.LastTimeStep; | 1130 | addForce /= PhysScene.LastTimeStep; |
1341 | AddForce(addForce, pushforce, false /* inTaintTime */); | 1131 | AddForce(addForce, pushforce, false /* inTaintTime */); |
1342 | } | 1132 | } |
1343 | 1133 | ||
1344 | // 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. |
1345 | // This added force will only last the next simulation tick. | 1135 | // This added force will only last the next simulation tick. |
1346 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 1136 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
1347 | // 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 |
1348 | if (IsPhysicallyActive) | 1138 | if (IsPhysicallyActive) |
1349 | { | 1139 | { |
@@ -1352,13 +1142,15 @@ public class BSPrim : BSPhysObject | |||
1352 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | 1142 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
1353 | 1143 | ||
1354 | OMV.Vector3 addForce = force; | 1144 | OMV.Vector3 addForce = force; |
1355 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | 1145 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
1356 | { | 1146 | { |
1357 | // 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; | ||
1358 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | 1150 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
1359 | if (PhysBody.HasPhysicalBody) | 1151 | if (PhysBody.HasPhysicalBody) |
1360 | { | 1152 | { |
1361 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 1153 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
1362 | ActivateIfPhysical(false); | 1154 | ActivateIfPhysical(false); |
1363 | } | 1155 | } |
1364 | }); | 1156 | }); |
@@ -1380,13 +1172,13 @@ public class BSPrim : BSPhysObject | |||
1380 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); | 1172 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); |
1381 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | 1173 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); |
1382 | 1174 | ||
1383 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() | 1175 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() |
1384 | { | 1176 | { |
1385 | // Bullet adds this impulse immediately to the velocity | 1177 | // Bullet adds this impulse immediately to the velocity |
1386 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | 1178 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); |
1387 | if (PhysBody.HasPhysicalBody) | 1179 | if (PhysBody.HasPhysicalBody) |
1388 | { | 1180 | { |
1389 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | 1181 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); |
1390 | ActivateIfPhysical(false); | 1182 | ActivateIfPhysical(false); |
1391 | } | 1183 | } |
1392 | }); | 1184 | }); |
@@ -1399,20 +1191,18 @@ public class BSPrim : BSPhysObject | |||
1399 | } | 1191 | } |
1400 | } | 1192 | } |
1401 | 1193 | ||
1402 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1194 | // BSPhysObject.AddAngularForce() |
1403 | AddAngularForce(force, pushforce, false); | 1195 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
1404 | } | ||
1405 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1406 | { | 1196 | { |
1407 | if (force.IsFinite()) | 1197 | if (force.IsFinite()) |
1408 | { | 1198 | { |
1409 | OMV.Vector3 angForce = force; | 1199 | OMV.Vector3 angForce = force; |
1410 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | 1200 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
1411 | { | 1201 | { |
1412 | if (PhysBody.HasPhysicalBody) | 1202 | if (PhysBody.HasPhysicalBody) |
1413 | { | 1203 | { |
1414 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); | 1204 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); |
1415 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | 1205 | PhysScene.PE.ApplyTorque(PhysBody, angForce); |
1416 | ActivateIfPhysical(false); | 1206 | ActivateIfPhysical(false); |
1417 | } | 1207 | } |
1418 | }); | 1208 | }); |
@@ -1431,11 +1221,11 @@ public class BSPrim : BSPhysObject | |||
1431 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1221 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1432 | { | 1222 | { |
1433 | OMV.Vector3 applyImpulse = impulse; | 1223 | OMV.Vector3 applyImpulse = impulse; |
1434 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1224 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1435 | { | 1225 | { |
1436 | if (PhysBody.HasPhysicalBody) | 1226 | if (PhysBody.HasPhysicalBody) |
1437 | { | 1227 | { |
1438 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | 1228 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); |
1439 | ActivateIfPhysical(false); | 1229 | ActivateIfPhysical(false); |
1440 | } | 1230 | } |
1441 | }); | 1231 | }); |
@@ -1721,9 +1511,11 @@ public class BSPrim : BSPhysObject | |||
1721 | volume *= (profileEnd - profileBegin); | 1511 | volume *= (profileEnd - profileBegin); |
1722 | 1512 | ||
1723 | returnMass = Density * BSParam.DensityScaleFactor * volume; | 1513 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
1724 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1725 | 1514 | ||
1726 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | 1515 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
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); | ||
1727 | 1519 | ||
1728 | return returnMass; | 1520 | return returnMass; |
1729 | }// end CalculateMass | 1521 | }// end CalculateMass |
@@ -1736,13 +1528,14 @@ public class BSPrim : BSPhysObject | |||
1736 | { | 1528 | { |
1737 | // Create the correct physical representation for this type of object. | 1529 | // Create the correct physical representation for this type of object. |
1738 | // Updates base.PhysBody and base.PhysShape with the new information. | 1530 | // Updates base.PhysBody and base.PhysShape with the new information. |
1739 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1531 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
1740 | 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) |
1741 | { | 1533 | { |
1742 | // Called if the current prim body is about to be destroyed. | 1534 | // Called if the current prim body is about to be destroyed. |
1743 | // Remove all the physical dependencies on the old body. | 1535 | // Remove all the physical dependencies on the old body. |
1744 | // (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, ...) |
1745 | RemoveBodyDependencies(); | 1537 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. |
1538 | RemoveDependencies(); | ||
1746 | }); | 1539 | }); |
1747 | 1540 | ||
1748 | // Make sure the properties are set on the new object | 1541 | // Make sure the properties are set on the new object |
@@ -1750,33 +1543,74 @@ public class BSPrim : BSPhysObject | |||
1750 | return; | 1543 | return; |
1751 | } | 1544 | } |
1752 | 1545 | ||
1753 | protected virtual void RemoveBodyDependencies() | 1546 | // Called at taint-time |
1547 | protected virtual void RemoveDependencies() | ||
1754 | { | 1548 | { |
1755 | VehicleController.RemoveBodyDependencies(this); | 1549 | PhysicalActors.RemoveDependencies(); |
1550 | } | ||
1551 | |||
1552 | #region Extension | ||
1553 | public override object Extension(string pFunct, params object[] pParams) | ||
1554 | { | ||
1555 | object ret = null; | ||
1556 | switch (pFunct) | ||
1557 | { | ||
1558 | case BSScene.PhysFunctGetLinksetType: | ||
1559 | { | ||
1560 | BSPrimLinkable myHandle = this as BSPrimLinkable; | ||
1561 | if (myHandle != null) | ||
1562 | { | ||
1563 | ret = (object)myHandle.LinksetType; | ||
1564 | } | ||
1565 | m_log.DebugFormat("{0} Extension.physGetLinksetType, type={1}", LogHeader, ret); | ||
1566 | break; | ||
1567 | } | ||
1568 | case BSScene.PhysFunctSetLinksetType: | ||
1569 | { | ||
1570 | if (pParams.Length > 0) | ||
1571 | { | ||
1572 | BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[0]; | ||
1573 | BSPrimLinkable myHandle = this as BSPrimLinkable; | ||
1574 | if (myHandle != null && myHandle.Linkset.IsRoot(myHandle)) | ||
1575 | { | ||
1576 | PhysScene.TaintedObject("BSPrim.PhysFunctSetLinksetType", delegate() | ||
1577 | { | ||
1578 | // Cause the linkset type to change | ||
1579 | m_log.DebugFormat("{0} Extension.physSetLinksetType, oldType={1}, newType={2}", | ||
1580 | LogHeader, myHandle.Linkset.LinksetImpl, linksetType); | ||
1581 | myHandle.ConvertLinkset(linksetType); | ||
1582 | }); | ||
1583 | } | ||
1584 | ret = (object)(int)linksetType; | ||
1585 | } | ||
1586 | break; | ||
1587 | } | ||
1588 | default: | ||
1589 | ret = base.Extension(pFunct, pParams); | ||
1590 | break; | ||
1591 | } | ||
1592 | return ret; | ||
1756 | } | 1593 | } |
1594 | #endregion // Extension | ||
1757 | 1595 | ||
1758 | // The physics engine says that properties have updated. Update same and inform | 1596 | // The physics engine says that properties have updated. Update same and inform |
1759 | // the world that things have changed. | 1597 | // the world that things have changed. |
1598 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. | ||
1599 | // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. | ||
1760 | public override void UpdateProperties(EntityProperties entprop) | 1600 | public override void UpdateProperties(EntityProperties entprop) |
1761 | { | 1601 | { |
1602 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
1762 | TriggerPreUpdatePropertyAction(ref entprop); | 1603 | TriggerPreUpdatePropertyAction(ref entprop); |
1763 | 1604 | ||
1764 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
1765 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
1766 | if (VehicleController.IsActive) | ||
1767 | { | ||
1768 | entprop.RotationalVelocity = OMV.Vector3.Zero; | ||
1769 | } | ||
1770 | |||
1771 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG | 1605 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1772 | 1606 | ||
1773 | // Assign directly to the local variables so the normal set actions do not happen | 1607 | // Assign directly to the local variables so the normal set actions do not happen |
1774 | _position = entprop.Position; | 1608 | RawPosition = entprop.Position; |
1775 | _orientation = entprop.Rotation; | 1609 | RawOrientation = entprop.Rotation; |
1776 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be | 1610 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1777 | // very sensitive to velocity changes. | 1611 | // very sensitive to velocity changes. |
1778 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) | 1612 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
1779 | _velocity = entprop.Velocity; | 1613 | RawVelocity = entprop.Velocity; |
1780 | _acceleration = entprop.Acceleration; | 1614 | _acceleration = entprop.Acceleration; |
1781 | _rotationalVelocity = entprop.RotationalVelocity; | 1615 | _rotationalVelocity = entprop.RotationalVelocity; |
1782 | 1616 | ||
@@ -1785,29 +1619,20 @@ public class BSPrim : BSPhysObject | |||
1785 | // The sanity check can change the velocity and/or position. | 1619 | // The sanity check can change the velocity and/or position. |
1786 | if (PositionSanityCheck(true /* inTaintTime */ )) | 1620 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1787 | { | 1621 | { |
1788 | entprop.Position = _position; | 1622 | entprop.Position = RawPosition; |
1789 | entprop.Velocity = _velocity; | 1623 | entprop.Velocity = RawVelocity; |
1790 | entprop.RotationalVelocity = _rotationalVelocity; | 1624 | entprop.RotationalVelocity = _rotationalVelocity; |
1791 | entprop.Acceleration = _acceleration; | 1625 | entprop.Acceleration = _acceleration; |
1792 | } | 1626 | } |
1793 | 1627 | ||
1794 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG | 1628 | OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG |
1795 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); | 1629 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); |
1796 | 1630 | ||
1797 | // remember the current and last set values | 1631 | // remember the current and last set values |
1798 | LastEntityProperties = CurrentEntityProperties; | 1632 | LastEntityProperties = CurrentEntityProperties; |
1799 | CurrentEntityProperties = entprop; | 1633 | CurrentEntityProperties = entprop; |
1800 | 1634 | ||
1801 | base.RequestPhysicsterseUpdate(); | 1635 | PhysScene.PostUpdate(this); |
1802 | /* | ||
1803 | else | ||
1804 | { | ||
1805 | // For debugging, report the movement of children | ||
1806 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1807 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
1808 | entprop.Acceleration, entprop.RotationalVelocity); | ||
1809 | } | ||
1810 | */ | ||
1811 | } | 1636 | } |
1812 | } | 1637 | } |
1813 | } | 1638 | } |
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 | ||
33 | using System; | 28 | using System; |
@@ -44,14 +39,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
44 | { | 39 | { |
45 | public class BSPrimDisplaced : BSPrim | 40 | public 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..7179a6d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -37,19 +37,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
37 | { | 37 | { |
38 | public class BSPrimLinkable : BSPrimDisplaced | 38 | public class BSPrimLinkable : BSPrimDisplaced |
39 | { | 39 | { |
40 | // The purpose of this subclass is to add linkset functionality to the prim. This overrides | ||
41 | // operations necessary for keeping the linkset created and, additionally, this | ||
42 | // calls the linkset implementation for its creation and management. | ||
43 | |||
44 | // This adds the overrides for link() and delink() so the prim is linkable. | ||
45 | |||
40 | public BSLinkset Linkset { get; set; } | 46 | public BSLinkset Linkset { get; set; } |
41 | // The index of this child prim. | 47 | // The index of this child prim. |
42 | public int LinksetChildIndex { get; set; } | 48 | public int LinksetChildIndex { get; set; } |
43 | 49 | ||
44 | public BSLinksetInfo LinksetInfo { get; set; } | 50 | public BSLinkset.LinksetImplementation LinksetType { get; set; } |
45 | 51 | ||
46 | public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 52 | public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 53 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | 54 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) |
49 | { | 55 | { |
50 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 56 | // Default linkset implementation for this prim |
57 | LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; | ||
58 | |||
59 | Linkset = BSLinkset.Factory(PhysScene, this); | ||
51 | 60 | ||
52 | PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() | 61 | PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() |
53 | { | 62 | { |
54 | Linkset.Refresh(this); | 63 | Linkset.Refresh(this); |
55 | }); | 64 | }); |
@@ -61,16 +70,13 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
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 | ||
@@ -85,8 +91,8 @@ 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); |
92 | 98 | ||
@@ -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("BSPrimLinkset.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("BSPrimLinkset.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,22 +156,28 @@ 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)) |
@@ -163,20 +186,93 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
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 | ||
227 | { | ||
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) | ||
176 | { | 242 | { |
177 | return false; | 243 | // Set the implementation type first so the call to BSLinkset.Factory gets the new type. |
244 | this.LinksetType = newType; | ||
245 | |||
246 | BSLinkset oldLinkset = this.Linkset; | ||
247 | BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); | ||
248 | |||
249 | this.Linkset = newLinkset; | ||
250 | |||
251 | // Pick up any physical dependencies this linkset might have in the physics engine. | ||
252 | oldLinkset.RemoveDependencies(this); | ||
253 | |||
254 | // Create a list of the children (mainly because can't interate through a list that's changing) | ||
255 | List<BSPrimLinkable> children = new List<BSPrimLinkable>(); | ||
256 | oldLinkset.ForEachMember((child) => | ||
257 | { | ||
258 | if (!oldLinkset.IsRoot(child)) | ||
259 | children.Add(child); | ||
260 | return false; // 'false' says to continue to next member | ||
261 | }); | ||
262 | |||
263 | // Remove the children from the old linkset and add to the new (will be a new instance from the factory) | ||
264 | foreach (BSPrimLinkable child in children) | ||
265 | { | ||
266 | oldLinkset.RemoveMeFromLinkset(child); | ||
267 | newLinkset.AddMeToLinkset(child); | ||
268 | child.Linkset = newLinkset; | ||
269 | } | ||
270 | |||
271 | // Force the shape and linkset to get reconstructed | ||
272 | newLinkset.Refresh(this); | ||
273 | this.ForceBodyShapeRebuild(true /* inTaintTime */); | ||
178 | } | 274 | } |
179 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | 275 | return ret; |
180 | } | 276 | } |
181 | } | 277 | } |
182 | } | 278 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index e6aefd5..c92c9b9 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 | ||
@@ -188,6 +209,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
188 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | 209 | PhysObjects = new Dictionary<uint, BSPhysObject>(); |
189 | Shapes = new BSShapeCollection(this); | 210 | Shapes = new BSShapeCollection(this); |
190 | 211 | ||
212 | m_simulatedTime = 0f; | ||
213 | LastTimeStep = 0.1f; | ||
214 | |||
191 | // Allocate pinned memory to pass parameters. | 215 | // Allocate pinned memory to pass parameters. |
192 | UnmanagedParams = new ConfigurationParameters[1]; | 216 | UnmanagedParams = new ConfigurationParameters[1]; |
193 | 217 | ||
@@ -202,8 +226,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
202 | // can be left in and every call doesn't have to check for null. | 226 | // can be left in and every call doesn't have to check for null. |
203 | if (m_physicsLoggingEnabled) | 227 | if (m_physicsLoggingEnabled) |
204 | { | 228 | { |
205 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 229 | 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. | 230 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages. |
207 | } | 231 | } |
208 | else | 232 | else |
209 | { | 233 | { |
@@ -227,10 +251,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
227 | TerrainManager = new BSTerrainManager(this); | 251 | TerrainManager = new BSTerrainManager(this); |
228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 252 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
229 | 253 | ||
230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | 254 | // Put some informational messages into the log file. |
255 | m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||
231 | 256 | ||
232 | InTaintTime = false; | 257 | InTaintTime = false; |
233 | m_initialized = true; | 258 | m_initialized = true; |
259 | |||
260 | // If the physics engine runs on its own thread, start same. | ||
261 | if (BSParam.UseSeparatePhysicsThread) | ||
262 | { | ||
263 | // The physics simulation should happen independently of the heartbeat loop | ||
264 | m_physicsThread = new Thread(BulletSPluginPhysicsThread); | ||
265 | m_physicsThread.Name = BulletEngineName; | ||
266 | m_physicsThread.Start(); | ||
267 | } | ||
234 | } | 268 | } |
235 | 269 | ||
236 | // All default parameter values are set here. There should be no values set in the | 270 | // All default parameter values are set here. There should be no values set in the |
@@ -268,6 +302,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
268 | // Do any replacements in the parameters | 302 | // Do any replacements in the parameters |
269 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 303 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
270 | } | 304 | } |
305 | else | ||
306 | { | ||
307 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
308 | BulletEngineName = "BulletUnmanaged"; | ||
309 | m_physicsLoggingEnabled = false; | ||
310 | VehicleLoggingEnabled = false; | ||
311 | } | ||
271 | 312 | ||
272 | // The material characteristics. | 313 | // The material characteristics. |
273 | BSMaterials.InitializeFromDefaults(Params); | 314 | BSMaterials.InitializeFromDefaults(Params); |
@@ -311,11 +352,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
311 | 352 | ||
312 | switch (selectionName) | 353 | switch (selectionName) |
313 | { | 354 | { |
355 | case "bullet": | ||
314 | case "bulletunmanaged": | 356 | case "bulletunmanaged": |
315 | ret = new BSAPIUnman(engineName, this); | 357 | ret = new BSAPIUnman(engineName, this); |
316 | break; | 358 | break; |
317 | case "bulletxna": | 359 | case "bulletxna": |
318 | ret = new BSAPIXNA(engineName, this); | 360 | ret = new BSAPIXNA(engineName, this); |
361 | // Disable some features that are not implemented in BulletXNA | ||
362 | m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); | ||
363 | m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); | ||
364 | BSParam.ShouldUseBulletHACD = false; | ||
365 | m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); | ||
366 | BSParam.ShouldUseSingleConvexHullForPrims = false; | ||
367 | m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); | ||
368 | BSParam.ShouldUseGImpactShapeForPrims = false; | ||
369 | m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); | ||
370 | BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; | ||
319 | break; | 371 | break; |
320 | } | 372 | } |
321 | 373 | ||
@@ -325,7 +377,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
325 | } | 377 | } |
326 | else | 378 | else |
327 | { | 379 | { |
328 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | 380 | m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); |
329 | } | 381 | } |
330 | 382 | ||
331 | return ret; | 383 | return ret; |
@@ -463,7 +515,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
463 | 515 | ||
464 | if (!m_initialized) return null; | 516 | if (!m_initialized) return null; |
465 | 517 | ||
466 | DetailLog("{0},BSScene.AddPrimShape,call", localID); | 518 | // DetailLog("{0},BSScene.AddPrimShape,call", localID); |
467 | 519 | ||
468 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); | 520 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); |
469 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 521 | lock (PhysObjects) PhysObjects.Add(localID, prim); |
@@ -478,25 +530,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
478 | #endregion // Prim and Avatar addition and removal | 530 | #endregion // Prim and Avatar addition and removal |
479 | 531 | ||
480 | #region Simulation | 532 | #region Simulation |
481 | // Simulate one timestep | 533 | |
534 | // Call from the simulator to send physics information to the simulator objects. | ||
535 | // This pushes all the collision and property update events into the objects in | ||
536 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
537 | // locking of those data structures from other heartbeat events. | ||
538 | // If the physics engine is running on a separate thread, the update information | ||
539 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
482 | public override float Simulate(float timeStep) | 540 | public override float Simulate(float timeStep) |
483 | { | 541 | { |
542 | if (!BSParam.UseSeparatePhysicsThread) | ||
543 | { | ||
544 | DoPhysicsStep(timeStep); | ||
545 | } | ||
546 | return SendUpdatesToSimulator(timeStep); | ||
547 | } | ||
548 | |||
549 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
550 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
551 | private void DoPhysicsStep(float timeStep) | ||
552 | { | ||
484 | // prevent simulation until we've been initialized | 553 | // prevent simulation until we've been initialized |
485 | if (!m_initialized) return 5.0f; | 554 | if (!m_initialized) return; |
486 | 555 | ||
487 | LastTimeStep = timeStep; | 556 | LastTimeStep = timeStep; |
488 | 557 | ||
489 | int updatedEntityCount = 0; | 558 | int updatedEntityCount = 0; |
490 | int collidersCount = 0; | 559 | int collidersCount = 0; |
491 | 560 | ||
492 | int beforeTime = 0; | 561 | int beforeTime = Util.EnvironmentTickCount(); |
493 | int simTime = 0; | 562 | int simTime = 0; |
494 | 563 | ||
495 | // update the prim states while we know the physics engine is not busy | ||
496 | int numTaints = _taintOperations.Count; | 564 | int numTaints = _taintOperations.Count; |
497 | |||
498 | InTaintTime = true; // Only used for debugging so locking is not necessary. | 565 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
499 | 566 | ||
567 | // update the prim states while we know the physics engine is not busy | ||
500 | ProcessTaints(); | 568 | ProcessTaints(); |
501 | 569 | ||
502 | // Some of the physical objects requre individual, pre-step calls | 570 | // Some of the physical objects requre individual, pre-step calls |
@@ -519,18 +587,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
519 | int numSubSteps = 0; | 587 | int numSubSteps = 0; |
520 | try | 588 | try |
521 | { | 589 | { |
522 | if (PhysicsLogging.Enabled) | ||
523 | beforeTime = Util.EnvironmentTickCount(); | ||
524 | |||
525 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | 590 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
526 | 591 | ||
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 | } | 592 | } |
535 | catch (Exception e) | 593 | catch (Exception e) |
536 | { | 594 | { |
@@ -542,77 +600,63 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
542 | collidersCount = 0; | 600 | collidersCount = 0; |
543 | } | 601 | } |
544 | 602 | ||
603 | // Make the physics engine dump useful statistics periodically | ||
545 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | 604 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
546 | PE.DumpPhysicsStatistics(World); | 605 | PE.DumpPhysicsStatistics(World); |
547 | 606 | ||
548 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 607 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
549 | SimulationNowTime = Util.EnvironmentTickCount(); | 608 | SimulationNowTime = Util.EnvironmentTickCount(); |
550 | 609 | ||
551 | // If there were collisions, process them by sending the event to the prim. | 610 | // Send collision information to the colliding objects. The objects decide if the collision |
552 | // Collisions must be processed before updates. | 611 | // is 'real' (like linksets don't collide with themselves) and the individual objects |
553 | if (collidersCount > 0) | 612 | // know if the simulator has subscribed to collisions. |
613 | lock (CollisionLock) | ||
554 | { | 614 | { |
555 | for (int ii = 0; ii < collidersCount; ii++) | 615 | if (collidersCount > 0) |
556 | { | 616 | { |
557 | uint cA = m_collisionArray[ii].aID; | 617 | 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 | { | 618 | { |
574 | // If the object is done colliding, see that it's removed from the colliding list | 619 | uint cA = m_collisionArray[ii].aID; |
575 | ObjectsWithNoMoreCollisions.Add(bsp); | 620 | uint cB = m_collisionArray[ii].bID; |
621 | Vector3 point = m_collisionArray[ii].point; | ||
622 | Vector3 normal = m_collisionArray[ii].normal; | ||
623 | float penetration = m_collisionArray[ii].penetration; | ||
624 | SendCollision(cA, cB, point, normal, penetration); | ||
625 | SendCollision(cB, cA, point, -normal, penetration); | ||
576 | } | 626 | } |
627 | } | ||
577 | } | 628 | } |
578 | 629 | ||
579 | // This is a kludge to get avatar movement updates. | 630 | // 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. | 631 | // and remember that there was a change so it will be passed to the simulator. |
581 | // The event updates avatar animations and stuff. | 632 | 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 | { | 633 | { |
603 | for (int ii = 0; ii < updatedEntityCount; ii++) | 634 | if (updatedEntityCount > 0) |
604 | { | 635 | { |
605 | EntityProperties entprop = m_updateArray[ii]; | 636 | for (int ii = 0; ii < updatedEntityCount; ii++) |
606 | BSPhysObject pobj; | ||
607 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
608 | { | 637 | { |
609 | pobj.UpdateProperties(entprop); | 638 | EntityProperties entprop = m_updateArray[ii]; |
639 | BSPhysObject pobj; | ||
640 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
641 | { | ||
642 | if (pobj.IsInitialized) | ||
643 | pobj.UpdateProperties(entprop); | ||
644 | } | ||
610 | } | 645 | } |
611 | } | 646 | } |
612 | } | 647 | } |
613 | 648 | ||
649 | // Some actors want to know when the simulation step is complete. | ||
614 | TriggerPostStepEvent(timeStep); | 650 | TriggerPostStepEvent(timeStep); |
615 | 651 | ||
652 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
653 | if (PhysicsLogging.Enabled) | ||
654 | { | ||
655 | DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
656 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
657 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
658 | } | ||
659 | |||
616 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 660 | // 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. | 661 | // Only enable this in a limited test world with few objects. |
618 | if (m_physicsPhysicalDumpEnabled) | 662 | if (m_physicsPhysicalDumpEnabled) |
@@ -621,7 +665,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
621 | // The physics engine returns the number of milliseconds it simulated this call. | 665 | // 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. | 666 | // 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). | 667 | // 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; | 668 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
669 | } | ||
670 | |||
671 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
672 | // should be passed up to the simulator at the proper time. | ||
673 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
674 | // this is is under UpdateLock. | ||
675 | public void PostUpdate(BSPhysObject updatee) | ||
676 | { | ||
677 | ObjectsWithUpdates.Add(updatee); | ||
678 | } | ||
679 | |||
680 | // The simulator thinks it is physics time so return all the collisions and position | ||
681 | // updates that were collected in actual physics simulation. | ||
682 | private float SendUpdatesToSimulator(float timeStep) | ||
683 | { | ||
684 | if (!m_initialized) return 5.0f; | ||
685 | |||
686 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
687 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
688 | // Push the collisions into the simulator. | ||
689 | lock (CollisionLock) | ||
690 | { | ||
691 | if (ObjectsWithCollisions.Count > 0) | ||
692 | { | ||
693 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
694 | if (!bsp.SendCollisions()) | ||
695 | { | ||
696 | // If the object is done colliding, see that it's removed from the colliding list | ||
697 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
698 | } | ||
699 | } | ||
700 | |||
701 | // This is a kludge to get avatar movement updates. | ||
702 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
703 | // The event updates avatar animations and stuff. | ||
704 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
705 | foreach (BSPhysObject bsp in m_avatars) | ||
706 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
707 | bsp.SendCollisions(); | ||
708 | |||
709 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
710 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
711 | // This complex collision processing is required to create an empty collision | ||
712 | // event call after all real collisions have happened on an object. This allows | ||
713 | // the simulator to generate the 'collision end' event. | ||
714 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
715 | { | ||
716 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
717 | ObjectsWithCollisions.Remove(po); | ||
718 | ObjectsWithNoMoreCollisions.Clear(); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | // Call the simulator for each object that has physics property updates. | ||
723 | HashSet<BSPhysObject> updatedObjects = null; | ||
724 | lock (UpdateLock) | ||
725 | { | ||
726 | if (ObjectsWithUpdates.Count > 0) | ||
727 | { | ||
728 | updatedObjects = ObjectsWithUpdates; | ||
729 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
730 | } | ||
731 | } | ||
732 | if (updatedObjects != null) | ||
733 | { | ||
734 | foreach (BSPhysObject obj in updatedObjects) | ||
735 | { | ||
736 | obj.RequestPhysicsterseUpdate(); | ||
737 | } | ||
738 | updatedObjects.Clear(); | ||
739 | } | ||
740 | |||
741 | // Return the framerate simulated to give the above returned results. | ||
742 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
743 | float simTime = m_simulatedTime; | ||
744 | m_simulatedTime = 0f; | ||
745 | return simTime; | ||
625 | } | 746 | } |
626 | 747 | ||
627 | // Something has collided | 748 | // Something has collided |
@@ -640,21 +761,49 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
640 | return; | 761 | return; |
641 | } | 762 | } |
642 | 763 | ||
643 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 764 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. |
644 | BSPhysObject collidee = null; | 765 | BSPhysObject collidee = null; |
645 | PhysObjects.TryGetValue(collidingWith, out collidee); | 766 | PhysObjects.TryGetValue(collidingWith, out collidee); |
646 | 767 | ||
647 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | 768 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); |
648 | 769 | ||
649 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 770 | if (collider.IsInitialized) |
650 | { | 771 | { |
651 | // If a collision was posted, remember to send it to the simulator | 772 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
652 | ObjectsWithCollisions.Add(collider); | 773 | { |
774 | // If a collision was 'good', remember to send it to the simulator | ||
775 | ObjectsWithCollisions.Add(collider); | ||
776 | } | ||
653 | } | 777 | } |
654 | 778 | ||
655 | return; | 779 | return; |
656 | } | 780 | } |
657 | 781 | ||
782 | public void BulletSPluginPhysicsThread() | ||
783 | { | ||
784 | while (m_initialized) | ||
785 | { | ||
786 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
787 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
788 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
789 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
790 | |||
791 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
792 | { | ||
793 | // The simulation of the time interval took less than realtime. | ||
794 | // Do a sleep for the rest of realtime. | ||
795 | Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
796 | } | ||
797 | else | ||
798 | { | ||
799 | // The simulation took longer than realtime. | ||
800 | // Do some scaling of simulation time. | ||
801 | // TODO. | ||
802 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | |||
658 | #endregion // Simulation | 807 | #endregion // Simulation |
659 | 808 | ||
660 | public override void GetResults() { } | 809 | public override void GetResults() { } |
@@ -717,6 +866,23 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
717 | 866 | ||
718 | public override bool IsThreaded { get { return false; } } | 867 | public override bool IsThreaded { get { return false; } } |
719 | 868 | ||
869 | #region Extensions | ||
870 | // ============================================================= | ||
871 | // Per scene functions. See below. | ||
872 | |||
873 | // Per avatar functions. See BSCharacter. | ||
874 | |||
875 | // Per prim functions. See BSPrim. | ||
876 | public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType"; | ||
877 | public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType"; | ||
878 | // ============================================================= | ||
879 | |||
880 | public override object Extension(string pFunct, params object[] pParams) | ||
881 | { | ||
882 | return base.Extension(pFunct, pParams); | ||
883 | } | ||
884 | #endregion // Extensions | ||
885 | |||
720 | #region Taints | 886 | #region Taints |
721 | // The simulation execution order is: | 887 | // The simulation execution order is: |
722 | // Simulate() | 888 | // Simulate() |
@@ -780,7 +946,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
780 | 946 | ||
781 | private void ProcessRegularTaints() | 947 | private void ProcessRegularTaints() |
782 | { | 948 | { |
783 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | 949 | if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process |
784 | { | 950 | { |
785 | // swizzle a new list into the list location so we can process what's there | 951 | // swizzle a new list into the list location so we can process what's there |
786 | List<TaintCallbackEntry> oldList; | 952 | List<TaintCallbackEntry> oldList; |
@@ -823,7 +989,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
823 | // Taints that happen after the normal taint processing but before the simulation step. | 989 | // Taints that happen after the normal taint processing but before the simulation step. |
824 | private void ProcessPostTaintTaints() | 990 | private void ProcessPostTaintTaints() |
825 | { | 991 | { |
826 | if (_postTaintOperations.Count > 0) | 992 | if (m_initialized && _postTaintOperations.Count > 0) |
827 | { | 993 | { |
828 | Dictionary<string, TaintCallbackEntry> oldList; | 994 | Dictionary<string, TaintCallbackEntry> oldList; |
829 | lock (_taintLock) | 995 | lock (_taintLock) |
@@ -963,8 +1129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
963 | public void DetailLog(string msg, params Object[] args) | 1129 | public void DetailLog(string msg, params Object[] args) |
964 | { | 1130 | { |
965 | PhysicsLogging.Write(msg, args); | 1131 | PhysicsLogging.Write(msg, args); |
966 | // Add the Flush() if debugging crashes. Gets all the messages written out. | ||
967 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); | ||
968 | } | 1132 | } |
969 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1133 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
970 | public const string DetailLogZero = "0000000000"; | 1134 | 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..5a0a14c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -29,115 +29,312 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | 31 | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | using OpenSim.Region.Physics.Meshing; | ||
35 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
36 | |||
32 | using OMV = OpenMetaverse; | 37 | using OMV = OpenMetaverse; |
33 | 38 | ||
34 | namespace OpenSim.Region.Physics.BulletSPlugin | 39 | namespace OpenSim.Region.Physics.BulletSPlugin |
35 | { | 40 | { |
36 | public abstract class BSShape | 41 | public 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 being used again. | ||
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 | // ============================================================================================================ | ||
115 | public class BSShapeNull : BSShape | 280 | public 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 | // ============================================================================================================ | ||
124 | public class BSShapeNative : BSShape | 291 | public 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,855 @@ 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 | // ============================================================================================================ | ||
182 | public class BSShapeMesh : BSShape | 369 | public 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 | // ============================================================================================================ | ||
194 | public class BSShapeHull : BSShape | 557 | public 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 | // ============================================================================================================ | ||
206 | public class BSShapeCompound : BSShape | 868 | public 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 BSShapeCompound(BulletShape pShape) : base(pShape) |
210 | { | 872 | { |
211 | } | 873 | } |
212 | public static BSShape GetReference(BSPhysObject prim) | 874 | public static BSShape GetReference(BSScene physicsScene) |
213 | { | 875 | { |
214 | return new BSShapeNull(); | 876 | // Base compound shapes are not shared so this returns a raw shape. |
877 | // A built compound shape can be reused in linksets. | ||
878 | return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); | ||
879 | } | ||
880 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
881 | { | ||
882 | // Calling this reference means we want another handle to an existing compound shape | ||
883 | // (usually linksets) so return this copy. | ||
884 | IncrementReference(); | ||
885 | return this; | ||
886 | } | ||
887 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
888 | public override void Dereference(BSScene physicsScene) | ||
889 | { | ||
890 | lock (physShapeInfo) | ||
891 | { | ||
892 | this.DecrementReference(); | ||
893 | physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
894 | if (referenceCount <= 0) | ||
895 | { | ||
896 | if (!physicsScene.PE.IsCompound(physShapeInfo)) | ||
897 | { | ||
898 | // Failed the sanity check!! | ||
899 | physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
900 | LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
901 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
902 | BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
903 | return; | ||
904 | } | ||
905 | |||
906 | int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); | ||
907 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", | ||
908 | BSScene.DetailLogZero, physShapeInfo, numChildren); | ||
909 | |||
910 | // Loop through all the children dereferencing each. | ||
911 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
912 | { | ||
913 | BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); | ||
914 | DereferenceAnonCollisionShape(physicsScene, childShape); | ||
915 | } | ||
916 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
917 | } | ||
918 | } | ||
919 | } | ||
920 | private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) | ||
921 | { | ||
922 | BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); | ||
923 | return cShape; | ||
924 | } | ||
925 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
926 | // Figure out type and call the correct dereference routine. | ||
927 | // Called at taint-time. | ||
928 | private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) | ||
929 | { | ||
930 | // TODO: figure a better way to go through all the shape types and find a possible instance. | ||
931 | BSShapeMesh meshDesc; | ||
932 | if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) | ||
933 | { | ||
934 | meshDesc.Dereference(physicsScene); | ||
935 | } | ||
936 | else | ||
937 | { | ||
938 | BSShapeHull hullDesc; | ||
939 | if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) | ||
940 | { | ||
941 | hullDesc.Dereference(physicsScene); | ||
942 | } | ||
943 | else | ||
944 | { | ||
945 | BSShapeConvexHull chullDesc; | ||
946 | if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc)) | ||
947 | { | ||
948 | chullDesc.Dereference(physicsScene); | ||
949 | } | ||
950 | else | ||
951 | { | ||
952 | BSShapeGImpact gImpactDesc; | ||
953 | if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) | ||
954 | { | ||
955 | gImpactDesc.Dereference(physicsScene); | ||
956 | } | ||
957 | else | ||
958 | { | ||
959 | // Didn't find it in the lists of specific types. It could be compound. | ||
960 | if (physicsScene.PE.IsCompound(pShape)) | ||
961 | { | ||
962 | BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); | ||
963 | recursiveCompound.Dereference(physicsScene); | ||
964 | } | ||
965 | else | ||
966 | { | ||
967 | // If none of the above, maybe it is a simple native shape. | ||
968 | if (physicsScene.PE.IsNativeShape(pShape)) | ||
969 | { | ||
970 | BSShapeNative nativeShape = new BSShapeNative(pShape); | ||
971 | nativeShape.Dereference(physicsScene); | ||
972 | } | ||
973 | } | ||
974 | } | ||
975 | } | ||
976 | } | ||
977 | } | ||
215 | } | 978 | } |
216 | public override void Dereference(BSScene physicsScene) { } | ||
217 | } | 979 | } |
218 | 980 | ||
981 | // ============================================================================================================ | ||
982 | public class BSShapeConvexHull : BSShape | ||
983 | { | ||
984 | private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; | ||
985 | public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>(); | ||
986 | |||
987 | public BSShapeConvexHull(BulletShape pShape) : base(pShape) | ||
988 | { | ||
989 | } | ||
990 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
991 | { | ||
992 | float lod; | ||
993 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
994 | |||
995 | physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", | ||
996 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
997 | |||
998 | BSShapeConvexHull retConvexHull = null; | ||
999 | lock (ConvexHulls) | ||
1000 | { | ||
1001 | if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) | ||
1002 | { | ||
1003 | // The mesh has already been created. Return a new reference to same. | ||
1004 | retConvexHull.IncrementReference(); | ||
1005 | } | ||
1006 | else | ||
1007 | { | ||
1008 | retConvexHull = new BSShapeConvexHull(new BulletShape()); | ||
1009 | BulletShape convexShape = null; | ||
1010 | |||
1011 | // Get a handle to a mesh to build the hull from | ||
1012 | BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); | ||
1013 | if (baseMesh.physShapeInfo.isNativeShape) | ||
1014 | { | ||
1015 | // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. | ||
1016 | // In the short term, we return the native shape and a later ForceBodyShapeRebuild should | ||
1017 | // get back to this code with a buildable mesh. | ||
1018 | // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? | ||
1019 | convexShape = baseMesh.physShapeInfo; | ||
1020 | } | ||
1021 | else | ||
1022 | { | ||
1023 | convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); | ||
1024 | convexShape.shapeKey = newMeshKey; | ||
1025 | ConvexHulls.Add(convexShape.shapeKey, retConvexHull); | ||
1026 | } | ||
1027 | |||
1028 | // Done with the base mesh | ||
1029 | baseMesh.Dereference(physicsScene); | ||
1030 | |||
1031 | retConvexHull.physShapeInfo = convexShape; | ||
1032 | } | ||
1033 | } | ||
1034 | return retConvexHull; | ||
1035 | } | ||
1036 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
1037 | { | ||
1038 | // Calling this reference means we want another handle to an existing shape | ||
1039 | // (usually linksets) so return this copy. | ||
1040 | IncrementReference(); | ||
1041 | return this; | ||
1042 | } | ||
1043 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1044 | public override void Dereference(BSScene physicsScene) | ||
1045 | { | ||
1046 | lock (ConvexHulls) | ||
1047 | { | ||
1048 | this.DecrementReference(); | ||
1049 | physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1050 | // TODO: schedule aging and destruction of unused meshes. | ||
1051 | } | ||
1052 | } | ||
1053 | // Loop through all the known hulls and return the description based on the physical address. | ||
1054 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) | ||
1055 | { | ||
1056 | bool ret = false; | ||
1057 | BSShapeConvexHull foundDesc = null; | ||
1058 | lock (ConvexHulls) | ||
1059 | { | ||
1060 | foreach (BSShapeConvexHull sh in ConvexHulls.Values) | ||
1061 | { | ||
1062 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1063 | { | ||
1064 | foundDesc = sh; | ||
1065 | ret = true; | ||
1066 | break; | ||
1067 | } | ||
1068 | |||
1069 | } | ||
1070 | } | ||
1071 | outHull = foundDesc; | ||
1072 | return ret; | ||
1073 | } | ||
1074 | } | ||
1075 | // ============================================================================================================ | ||
1076 | public class BSShapeGImpact : BSShape | ||
1077 | { | ||
1078 | private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; | ||
1079 | public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>(); | ||
1080 | |||
1081 | public BSShapeGImpact(BulletShape pShape) : base(pShape) | ||
1082 | { | ||
1083 | } | ||
1084 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
1085 | { | ||
1086 | float lod; | ||
1087 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
1088 | |||
1089 | physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", | ||
1090 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
1091 | |||
1092 | BSShapeGImpact retGImpact = null; | ||
1093 | lock (GImpacts) | ||
1094 | { | ||
1095 | if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) | ||
1096 | { | ||
1097 | // The mesh has already been created. Return a new reference to same. | ||
1098 | retGImpact.IncrementReference(); | ||
1099 | } | ||
1100 | else | ||
1101 | { | ||
1102 | retGImpact = new BSShapeGImpact(new BulletShape()); | ||
1103 | BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
1104 | |||
1105 | // Check to see if mesh was created (might require an asset). | ||
1106 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
1107 | newShape.shapeKey = newMeshKey; | ||
1108 | if (!newShape.isNativeShape | ||
1109 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing | ||
1110 | || prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) | ||
1111 | { | ||
1112 | // If a mesh was what was created, remember the built shape for later sharing. | ||
1113 | // Also note that if meshing failed we put it in the mesh list as there is nothing | ||
1114 | // else to do about the mesh. | ||
1115 | GImpacts.Add(newMeshKey, retGImpact); | ||
1116 | } | ||
1117 | |||
1118 | retGImpact.physShapeInfo = newShape; | ||
1119 | } | ||
1120 | } | ||
1121 | return retGImpact; | ||
1122 | } | ||
1123 | |||
1124 | private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
1125 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
1126 | { | ||
1127 | return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, | ||
1128 | (w, iC, i, vC, v) => physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v) ); | ||
1129 | } | ||
1130 | |||
1131 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1132 | { | ||
1133 | BSShape ret = null; | ||
1134 | // If the underlying shape is native, the actual shape has not been build (waiting for asset) | ||
1135 | // and we must create a copy of the native shape since they are never shared. | ||
1136 | if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) | ||
1137 | { | ||
1138 | // TODO: decide when the native shapes should be freed. Check in Dereference? | ||
1139 | ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
1140 | } | ||
1141 | else | ||
1142 | { | ||
1143 | // Another reference to this shape is just counted. | ||
1144 | IncrementReference(); | ||
1145 | ret = this; | ||
1146 | } | ||
1147 | return ret; | ||
1148 | } | ||
1149 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
1150 | public override void Dereference(BSScene physicsScene) | ||
1151 | { | ||
1152 | lock (GImpacts) | ||
1153 | { | ||
1154 | this.DecrementReference(); | ||
1155 | physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
1156 | // TODO: schedule aging and destruction of unused meshes. | ||
1157 | } | ||
1158 | } | ||
1159 | // Loop through all the known hulls and return the description based on the physical address. | ||
1160 | public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) | ||
1161 | { | ||
1162 | bool ret = false; | ||
1163 | BSShapeGImpact foundDesc = null; | ||
1164 | lock (GImpacts) | ||
1165 | { | ||
1166 | foreach (BSShapeGImpact sh in GImpacts.Values) | ||
1167 | { | ||
1168 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
1169 | { | ||
1170 | foundDesc = sh; | ||
1171 | ret = true; | ||
1172 | break; | ||
1173 | } | ||
1174 | |||
1175 | } | ||
1176 | } | ||
1177 | outHull = foundDesc; | ||
1178 | return ret; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | // ============================================================================================================ | ||
219 | public class BSShapeAvatar : BSShape | 1183 | public class BSShapeAvatar : BSShape |
220 | { | 1184 | { |
221 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | 1185 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; |
222 | public BSShapeAvatar() : base() | 1186 | public BSShapeAvatar() : base() |
223 | { | 1187 | { |
224 | } | 1188 | } |
225 | public static BSShape GetReference(BSPhysObject prim) | 1189 | public static BSShape GetReference(BSPhysObject prim) |
226 | { | 1190 | { |
1191 | return new BSShapeNull(); | ||
1192 | } | ||
1193 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
1194 | { | ||
227 | return new BSShapeNull(); | 1195 | return new BSShapeNull(); |
228 | } | 1196 | } |
229 | public override void Dereference(BSScene physicsScene) { } | 1197 | public override void Dereference(BSScene physicsScene) { } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index e4fecc3..c7deb4e 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,26 @@ 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 | 114 | ||
115 | // Return the new terrain to the world of physical objects | 115 | // Return the new terrain to the world of physical objects |
116 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); | 116 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); |
117 | 117 | ||
118 | // redo its bounding box now that it is in the world | 118 | // redo its bounding box now that it is in the world |
119 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); | 119 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); |
120 | 120 | ||
121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; | 121 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
122 | m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene); | 122 | m_mapInfo.terrainBody.ApplyCollisionMask(m_physicsScene); |
123 | 123 | ||
124 | // Make it so the terrain will not move or be considered for movement. | 124 | // Make it so the terrain will not move or be considered for movement. |
125 | PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); | 125 | m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); |
126 | 126 | ||
127 | return; | 127 | return; |
128 | } | 128 | } |
@@ -134,9 +134,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
134 | { | 134 | { |
135 | if (m_mapInfo.terrainBody.HasPhysicalBody) | 135 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
136 | { | 136 | { |
137 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); | 137 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); |
138 | // Frees both the body and the shape. | 138 | // Frees both the body and the shape. |
139 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); | 139 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); |
140 | } | 140 | } |
141 | } | 141 | } |
142 | m_mapInfo = null; | 142 | m_mapInfo = null; |
@@ -155,7 +155,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
155 | catch | 155 | catch |
156 | { | 156 | { |
157 | // Sometimes they give us wonky values of X and Y. Give a warning and return something. | 157 | // 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}", | 158 | m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", |
159 | LogHeader, m_mapInfo.terrainRegionBase, pos); | 159 | LogHeader, m_mapInfo.terrainRegionBase, pos); |
160 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 160 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
161 | } | 161 | } |
@@ -165,7 +165,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
165 | // The passed position is relative to the base of the region. | 165 | // The passed position is relative to the base of the region. |
166 | public override float GetWaterLevelAtXYZ(Vector3 pos) | 166 | public override float GetWaterLevelAtXYZ(Vector3 pos) |
167 | { | 167 | { |
168 | return PhysicsScene.SimpleWaterLevel; | 168 | return m_physicsScene.SimpleWaterLevel; |
169 | } | 169 | } |
170 | } | 170 | } |
171 | } | 171 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index b2fb835..c4807c4 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,21 @@ 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); | 141 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); |
142 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); | 142 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); |
143 | // Ground plane does not move | 143 | // Ground plane does not move |
144 | PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); | 144 | m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); |
145 | // Everything collides with the ground plane. | 145 | // Everything collides with the ground plane. |
146 | m_groundPlane.collisionType = CollisionType.Groundplane; | 146 | m_groundPlane.collisionType = CollisionType.Groundplane; |
147 | m_groundPlane.ApplyCollisionMask(PhysicsScene); | 147 | m_groundPlane.ApplyCollisionMask(m_physicsScene); |
148 | 148 | ||
149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
150 | lock (m_terrains) | 150 | lock (m_terrains) |
151 | { | 151 | { |
152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
@@ -157,12 +157,12 @@ public sealed class BSTerrainManager : IDisposable | |||
157 | // Release all the terrain structures we might have allocated | 157 | // Release all the terrain structures we might have allocated |
158 | public void ReleaseGroundPlaneAndTerrain() | 158 | public void ReleaseGroundPlaneAndTerrain() |
159 | { | 159 | { |
160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, PhysicsScene.RegionName); | 160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); |
161 | if (m_groundPlane.HasPhysicalBody) | 161 | if (m_groundPlane.HasPhysicalBody) |
162 | { | 162 | { |
163 | if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) | 163 | if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) |
164 | { | 164 | { |
165 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); | 165 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); |
166 | } | 166 | } |
167 | m_groundPlane.Clear(); | 167 | m_groundPlane.Clear(); |
168 | } | 168 | } |
@@ -188,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable | |||
188 | float[] localHeightMap = heightMap; | 188 | float[] localHeightMap = heightMap; |
189 | // If there are multiple requests for changes to the same terrain between ticks, | 189 | // If there are multiple requests for changes to the same terrain between ticks, |
190 | // only do that last one. | 190 | // only do that last one. |
191 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | 191 | m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() |
192 | { | 192 | { |
193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
194 | { | 194 | { |
@@ -199,15 +199,8 @@ public sealed class BSTerrainManager : IDisposable | |||
199 | if (MegaRegionParentPhysicsScene is BSScene) | 199 | if (MegaRegionParentPhysicsScene is BSScene) |
200 | { | 200 | { |
201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); | 201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); |
202 | // This looks really odd but this region is passing its terrain to its mega-region root region | 202 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( |
203 | // and the creation of the terrain must happen on the root region's taint thread and not | 203 | BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
204 | // my taint thread. | ||
205 | ((BSScene)MegaRegionParentPhysicsScene).PostTaintObject("TerrainManager.SetTerrain.Mega-" + m_worldOffset.ToString(), 0, delegate() | ||
206 | { | ||
207 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | ||
208 | BSScene.CHILDTERRAIN_ID, localHeightMap, | ||
209 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); | ||
210 | }); | ||
211 | } | 204 | } |
212 | } | 205 | } |
213 | else | 206 | else |
@@ -215,12 +208,23 @@ public sealed class BSTerrainManager : IDisposable | |||
215 | // If not doing the mega-prim thing, just change the terrain | 208 | // If not doing the mega-prim thing, just change the terrain |
216 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | 209 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); |
217 | 210 | ||
218 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, | 211 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
219 | m_worldOffset, m_worldOffset + DefaultRegionSize, true /* inTaintTime */); | ||
220 | } | 212 | } |
221 | }); | 213 | }); |
222 | } | 214 | } |
223 | 215 | ||
216 | // 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 | // physics engine will have all the terrains. | ||
219 | private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | ||
220 | { | ||
221 | // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. | ||
222 | m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() | ||
223 | { | ||
224 | UpdateTerrain(id, heightMap, minCoords, maxCoords); | ||
225 | }); | ||
226 | } | ||
227 | |||
224 | // If called for terrain has has not been previously allocated, a new terrain will be built | 228 | // If called for terrain has has not been previously allocated, a new terrain will be built |
225 | // based on the passed information. The 'id' should be either the terrain id or | 229 | // based on the passed information. The 'id' should be either the terrain id or |
226 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. | 230 | // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. |
@@ -230,11 +234,10 @@ public sealed class BSTerrainManager : IDisposable | |||
230 | // This call is most often used to update the heightMap and parameters of the terrain. | 234 | // This call is most often used to update the heightMap and parameters of the terrain. |
231 | // (The above does suggest that some simplification/refactoring is in order.) | 235 | // (The above does suggest that some simplification/refactoring is in order.) |
232 | // Called during taint-time. | 236 | // Called during taint-time. |
233 | private void UpdateTerrain(uint id, float[] heightMap, | 237 | private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
234 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
235 | { | 238 | { |
236 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3},inTaintTime={4}", | 239 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", |
237 | BSScene.DetailLogZero, id, minCoords, maxCoords, inTaintTime); | 240 | BSScene.DetailLogZero, id, minCoords, maxCoords); |
238 | 241 | ||
239 | // Find high and low points of passed heightmap. | 242 | // Find high and low points of passed heightmap. |
240 | // The min and max passed in is usually the area objects can be in (maximum | 243 | // The min and max passed in is usually the area objects can be in (maximum |
@@ -303,7 +306,7 @@ public sealed class BSTerrainManager : IDisposable | |||
303 | newTerrainID = ++m_terrainCount; | 306 | newTerrainID = ++m_terrainCount; |
304 | 307 | ||
305 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | 308 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
306 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 309 | BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); |
307 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 310 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
308 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 311 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
309 | 312 | ||
@@ -315,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable | |||
315 | // TODO: redo terrain implementation selection to allow other base types than heightMap. | 318 | // TODO: redo terrain implementation selection to allow other base types than heightMap. |
316 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) | 319 | private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
317 | { | 320 | { |
318 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | 321 | m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
319 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | 322 | LogHeader, m_physicsScene.RegionName, terrainRegionBase, |
320 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | 323 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); |
321 | BSTerrainPhys newTerrainPhys = null; | 324 | BSTerrainPhys newTerrainPhys = null; |
322 | switch ((int)BSParam.TerrainImplementation) | 325 | switch ((int)BSParam.TerrainImplementation) |
323 | { | 326 | { |
324 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | 327 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |
325 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | 328 | newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, |
326 | heightMap, minCoords, maxCoords); | 329 | heightMap, minCoords, maxCoords); |
327 | break; | 330 | break; |
328 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | 331 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: |
329 | newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, | 332 | newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, |
330 | heightMap, minCoords, maxCoords); | 333 | heightMap, minCoords, maxCoords); |
331 | break; | 334 | break; |
332 | default: | 335 | default: |
333 | PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", | 336 | m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", |
334 | LogHeader, | 337 | LogHeader, |
335 | (int)BSParam.TerrainImplementation, | 338 | (int)BSParam.TerrainImplementation, |
336 | BSParam.TerrainImplementation, | 339 | BSParam.TerrainImplementation, |
337 | PhysicsScene.RegionName, terrainRegionBase); | 340 | m_physicsScene.RegionName, terrainRegionBase); |
338 | break; | 341 | break; |
339 | } | 342 | } |
340 | return newTerrainPhys; | 343 | return newTerrainPhys; |
@@ -426,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable | |||
426 | } | 429 | } |
427 | else | 430 | else |
428 | { | 431 | { |
429 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 432 | m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
430 | LogHeader, PhysicsScene.RegionName, tX, tY); | 433 | LogHeader, m_physicsScene.RegionName, tX, tY); |
431 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | 434 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", |
432 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | 435 | BSScene.DetailLogZero, pos, terrainBaseXYZ); |
433 | } | 436 | } |
@@ -448,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable | |||
448 | } | 451 | } |
449 | else | 452 | else |
450 | { | 453 | { |
451 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | 454 | m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", |
452 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | 455 | LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); |
453 | } | 456 | } |
454 | return ret; | 457 | return ret; |
455 | } | 458 | } |
@@ -561,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable | |||
561 | 564 | ||
562 | private void DetailLog(string msg, params Object[] args) | 565 | private void DetailLog(string msg, params Object[] args) |
563 | { | 566 | { |
564 | PhysicsScene.PhysicsLogging.Write(msg, args); | 567 | m_physicsScene.PhysicsLogging.Write(msg, args); |
565 | } | 568 | } |
566 | } | 569 | } |
567 | } | 570 | } |
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..d5060e3 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,42 @@ 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. |
227 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | 227 | public 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 | }, | 239 | }, |
240 | { CollisionType.Terrain, | 240 | { CollisionType.Terrain, |
241 | new CollisionTypeFilterGroup(CollisionType.Terrain, | 241 | new CollisionTypeFilterGroup(CollisionType.Terrain, |
242 | (uint)CollisionFilterGroups.BTerrainGroup, | 242 | (uint)CollisionFilterGroups.BTerrainGroup, |
243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | 243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) |
244 | }, | 244 | }, |
245 | { CollisionType.Static, | 245 | { CollisionType.Static, |
246 | new CollisionTypeFilterGroup(CollisionType.Static, | 246 | new CollisionTypeFilterGroup(CollisionType.Static, |
247 | (uint)CollisionFilterGroups.BStaticGroup, | 247 | (uint)CollisionFilterGroups.BStaticGroup, |
248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
249 | }, | 249 | }, |
250 | { CollisionType.Dynamic, | 250 | { CollisionType.Dynamic, |
251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | 251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, |
252 | (uint)CollisionFilterGroups.BSolidGroup, | 252 | (uint)CollisionFilterGroups.BSolidGroup, |
253 | (uint)(CollisionFilterGroups.BAllGroup)) | 253 | (uint)(CollisionFilterGroups.BAllGroup)) |
254 | }, | 254 | }, |
255 | { CollisionType.VolumeDetect, | 255 | { CollisionType.VolumeDetect, |
256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | 256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, |
257 | (uint)CollisionFilterGroups.BSensorTrigger, | 257 | (uint)CollisionFilterGroups.BSensorTrigger, |
258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | 258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) |
259 | }, | 259 | }, |
260 | { CollisionType.LinksetChild, | 260 | { CollisionType.LinksetChild, |
261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | 261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, |
262 | (uint)CollisionFilterGroups.BLinksetChildGroup, | 262 | (uint)CollisionFilterGroups.BLinksetChildGroup, |
263 | (uint)(CollisionFilterGroups.BNoneGroup)) | 263 | (uint)(CollisionFilterGroups.BNoneGroup)) |
264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
265 | }, | 265 | }, |
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 @@ | |||
1 | CURRENT PRIORITIES | 1 | CURRENT PROBLEMS TO FIX AND/OR LOOK AT |
2 | ================================================= | 2 | ================================================= |
3 | Use the HACD convex hull routine in Bullet rather than the C# version. | 3 | Vehicle 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 | ||
6 | Center-of-gravity | ||
7 | Computation of mesh mass. How done? How should it be done? | ||
5 | Enable vehicle border crossings (at least as poorly as ODE) | 8 | Enable 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) |
9 | Lock axis | 12 | User settable terrain mesh |
13 | Allow specifying as convex or concave and use different getHeight functions depending | ||
14 | Boats, when turning nose down into the water | ||
15 | Acts like rotation around Z is also effecting rotation around X and Y | ||
10 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | 16 | Deleting 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. |
12 | Linkset child rotations. | 18 | Linkset 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. |
15 | Vehicle angular vertical attraction | ||
16 | vehicle angular banking | ||
17 | Center-of-gravity | ||
18 | Vehicle angular deflection | ||
19 | Preferred orientation angular correction fix | ||
20 | when should angular and linear motor targets be zeroed? when selected? | ||
21 | Need a vehicle.clear()? Or an 'else' in prestep if not physical. | ||
22 | Teravus llMoveToTarget script debug | 21 | Teravus 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) |
25 | limitMotorUp calibration (more down?) | 24 | limitMotorUp calibration (more down?) |
26 | llRotLookAt | 25 | llRotLookAt |
27 | llLookAt | 26 | llLookAt |
28 | Avatars walking up stairs (HALF DONE) | 27 | Convert to avatar mesh capsule. Include rotation of capsule. |
29 | Avatar 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) | ||
33 | Vehicle script tuning/debugging | 28 | Vehicle script tuning/debugging |
34 | Avanti speed script | 29 | Avanti speed script |
35 | Weapon shooter script | 30 | Weapon shooter script |
36 | Move material definitions (friction, ...) into simulator. | 31 | Move material definitions (friction, ...) into simulator. |
37 | Add material densities to the material types. | 32 | osGetPhysicsEngineVerion() and create a version code for the C++ DLL |
38 | Terrain detail: double terrain mesh detail | ||
39 | One sided meshes? Should terrain be built into a closed shape? | 33 | One 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 |
37 | Small 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 | ||
44 | VEHICLES TODO LIST: | 43 | VEHICLES TODO LIST: |
45 | ================================================= | 44 | ================================================= |
46 | Border crossing with linked vehicle causes crash | 45 | LINEAR_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. |
49 | Vehicles (Move smoothly) | 48 | UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: |
49 | https://github.com/UbitUmarov/Ubit-opensim | ||
50 | Some vehicles should not be able to turn if no speed or off ground. | 50 | Some vehicles should not be able to turn if no speed or off ground. |
51 | What to do if vehicle and prim buoyancy differ? | ||
52 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | 51 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. |
53 | Neb car jiggling left and right | 52 | Neb 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. |
56 | Implement referenceFrame for all the motion routines. | 55 | Implement referenceFrame for all the motion routines. |
57 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
58 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | 56 | Verify llGetVel() is returning a smooth and good value for vehicle movement. |
59 | llGetVel() should return the root's velocity if requested in a child prim. | 57 | llGetVel() should return the root's velocity if requested in a child prim. |
60 | Implement function efficiency for lineaar and angular motion. | 58 | Implement function efficiency for lineaar and angular motion. |
61 | After 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 | ||
63 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | 59 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) |
64 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | 60 | Remove 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. |
69 | Vehicle attributes are not restored when a vehicle is rezzed on region creation | 65 | Vehicle 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. |
67 | What to do if vehicle and prim buoyancy differ? | ||
71 | 68 | ||
72 | GENERAL TODO LIST: | 69 | GENERAL TODO LIST: |
73 | ================================================= | 70 | ================================================= |
74 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
75 | Regular triangle meshes don't do physical collisions. | ||
76 | Resitution of a prim works on another prim but not on terrain. | 71 | Resitution 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. |
78 | Add a sanity check for PIDTarget location. | 73 | Add a sanity check for PIDTarget location. |
@@ -98,29 +93,15 @@ Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | |||
98 | Duplicating a physical prim causes old prim to jump away | 93 | Duplicating 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. |
100 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | 95 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. |
101 | BSPrim.Force should set a continious force on the prim. The force should be | ||
102 | applied each tick. Some limits? | ||
103 | Gun sending shooter flying. | 96 | Gun sending shooter flying. |
104 | Collision margin (gap between physical objects lying on each other) | 97 | Collision margin (gap between physical objects lying on each other) |
105 | Boundry checking (crashes related to crossing boundry) | 98 | Boundry 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. |
108 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
109 | Avatar running (what does phys engine need to do?) | ||
110 | Small 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. | ||
115 | Add PID motor for avatar movement (slow to stop, ...) | ||
116 | setForce should set a constant force. Different than AddImpulse. | ||
117 | Implement raycast. | ||
118 | Implement ShapeCollection.Dispose() | 101 | Implement ShapeCollection.Dispose() |
119 | Implement water as a plain so raycasting and collisions can happen with same. | 102 | Implement water as a plain or mesh so raycasting and collisions can happen with same. |
120 | Add collision penetration return | 103 | Add 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() |
122 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
123 | Also osGetPhysicsEngineVerion() maybe. | ||
124 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | 105 | Linkset.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!! |
126 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) | 107 | Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) |
@@ -132,9 +113,6 @@ Selecting and deselecting physical objects causes CPU processing time to jump | |||
132 | Re-implement buoyancy as a separate force on the object rather than diddling gravity. | 113 | Re-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. |
134 | More efficient memory usage when passing hull information from BSPrim to BulletSim | 115 | More efficient memory usage when passing hull information from BSPrim to BulletSim |
135 | Avatar 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. | ||
138 | Physical and phantom will drop through the terrain | 116 | Physical 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 | ||
169 | MORE | 147 | MORE |
170 | ====================================================== | 148 | ====================================================== |
149 | Compute avatar size and scale correctly. Now it is a bit off from the capsule size. | ||
171 | Create tests for different interface components | 150 | Create 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. |
178 | Debounce avatar contact so legs don't keep folding up when standing. | 157 | Debounce avatar contact so legs don't keep folding up when standing. |
179 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
180 | Add border extensions to terrain to help region crossings and objects leaving region. | 158 | Add border extensions to terrain to help region crossings and objects leaving region. |
181 | Use a different capsule shape for avatar when sitting | 159 | Use 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 | ||
210 | INTERNAL IMPROVEMENT/CLEANUP | 188 | INTERNAL IMPROVEMENT/CLEANUP |
211 | ================================================= | 189 | ================================================= |
212 | Can 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. | ||
214 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on | 190 | Create 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. |
346 | Nebadon vehicles turning funny in arena (DONE) | 322 | Nebadon vehicles turning funny in arena (DONE) |
323 | Lock axis (DONE 20130401) | ||
324 | Terrain detail: double terrain mesh detail (DONE) | ||
325 | Use the HACD convex hull routine in Bullet rather than the C# version. | ||
326 | Speed up hullifying large meshes. (DONE) | ||
327 | Vehicle 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) | ||
330 | Hitting 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) | ||
333 | Two 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) | ||
336 | Add material densities to the material types. (WILL NOT BE DONE: not how it is done) | ||
337 | Avatars walking up stairs (DONE) | ||
338 | Avatar 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) | ||
342 | After 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) | ||
345 | Explore 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) | ||
348 | Script 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) | ||
351 | Refarb 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) | ||
354 | Vehicle angular vertical attraction (DONE: vegaslon code) | ||
355 | vehicle angular banking (DONE: vegaslon code) | ||
356 | Vehicle angular deflection (DONE: vegaslon code) | ||
357 | Preferred orientation angular correction fix | ||
358 | Vehicles (Move smoothly) | ||
359 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
360 | (WILL NOT BE DONE: gravity does the job well enough) | ||
361 | BSPrim.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, ...) | ||
364 | Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE) | ||
365 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
366 | Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE) | ||
367 | Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force) | ||
368 | setForce should set a constant force. Different than AddImpulse. (DONE) | ||
369 | Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok) | ||
370 | Avatar 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) | ||
374 | Can 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/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 33232bd..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.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); | 119 | BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */); |
118 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); | 120 | if (vehicleActor != null) |
119 | TestVehicle.VehicleController.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.VehicleController.ForgetKnownVehicleProperties(); | 122 | vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); |
128 | TestVehicle.VehicleController.ComputeAngularVerticalAttraction(); | 123 | vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); |
129 | TestVehicle.VehicleController.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/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 | ||
28 | using System; | ||
28 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
29 | using System.Reflection; | 30 | using System.Reflection; |
31 | |||
30 | using log4net; | 32 | using log4net; |
31 | using Nini.Config; | 33 | using Nini.Config; |
34 | |||
32 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
33 | using OpenMetaverse; | 36 | using 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..16d65eb 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -64,6 +64,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
64 | public class Meshmerizer : IMesher | 64 | public class Meshmerizer : IMesher |
65 | { | 65 | { |
66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 66 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
67 | private static string LogHeader = "[MESH]"; | ||
67 | 68 | ||
68 | // Setting baseDir to a path will enable the dumping of raw files | 69 | // 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 | 70 | // raw files can be imported by blender so a visual inspection of the results can be done |
@@ -72,6 +73,8 @@ namespace OpenSim.Region.Physics.Meshing | |||
72 | #else | 73 | #else |
73 | private const string baseDir = null; //"rawFiles"; | 74 | private const string baseDir = null; //"rawFiles"; |
74 | #endif | 75 | #endif |
76 | // If 'true', lots of DEBUG logging of asset parsing details | ||
77 | private bool debugDetail = false; | ||
75 | 78 | ||
76 | private bool cacheSculptMaps = true; | 79 | private bool cacheSculptMaps = true; |
77 | private string decodedSculptMapPath = null; | 80 | private string decodedSculptMapPath = null; |
@@ -79,6 +82,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
79 | 82 | ||
80 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh | 83 | private float minSizeForComplexMesh = 0.2f; // prims with all dimensions smaller than this will have a bounding box mesh |
81 | 84 | ||
85 | private List<List<Vector3>> mConvexHulls = null; | ||
86 | private List<Vector3> mBoundingHull = null; | ||
87 | |||
82 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); | 88 | private Dictionary<ulong, Mesh> m_uniqueMeshes = new Dictionary<ulong, Mesh>(); |
83 | 89 | ||
84 | public Meshmerizer(IConfigSource config) | 90 | public Meshmerizer(IConfigSource config) |
@@ -88,8 +94,11 @@ namespace OpenSim.Region.Physics.Meshing | |||
88 | 94 | ||
89 | decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); | 95 | decodedSculptMapPath = start_config.GetString("DecodedSculptMapPath","j2kDecodeCache"); |
90 | cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); | 96 | cacheSculptMaps = start_config.GetBoolean("CacheSculptMaps", cacheSculptMaps); |
91 | if(mesh_config != null) | 97 | if (mesh_config != null) |
98 | { | ||
92 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); | 99 | useMeshiesPhysicsMesh = mesh_config.GetBoolean("UseMeshiesPhysicsMesh", useMeshiesPhysicsMesh); |
100 | debugDetail = mesh_config.GetBoolean("LogMeshDetails", debugDetail); | ||
101 | } | ||
93 | 102 | ||
94 | try | 103 | try |
95 | { | 104 | { |
@@ -319,6 +328,9 @@ namespace OpenSim.Region.Physics.Meshing | |||
319 | faces = new List<Face>(); | 328 | faces = new List<Face>(); |
320 | OSD meshOsd = null; | 329 | OSD meshOsd = null; |
321 | 330 | ||
331 | mConvexHulls = null; | ||
332 | mBoundingHull = null; | ||
333 | |||
322 | if (primShape.SculptData.Length <= 0) | 334 | if (primShape.SculptData.Length <= 0) |
323 | { | 335 | { |
324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this | 336 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this |
@@ -355,9 +367,139 @@ namespace OpenSim.Region.Physics.Meshing | |||
355 | OSDMap physicsParms = null; | 367 | OSDMap physicsParms = null; |
356 | OSDMap map = (OSDMap)meshOsd; | 368 | OSDMap map = (OSDMap)meshOsd; |
357 | if (map.ContainsKey("physics_shape")) | 369 | if (map.ContainsKey("physics_shape")) |
370 | { | ||
358 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format | 371 | physicsParms = (OSDMap)map["physics_shape"]; // old asset format |
372 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': using 'physics_shape' mesh data", LogHeader, primName); | ||
373 | } | ||
359 | else if (map.ContainsKey("physics_mesh")) | 374 | else if (map.ContainsKey("physics_mesh")) |
375 | { | ||
360 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format | 376 | physicsParms = (OSDMap)map["physics_mesh"]; // new asset format |
377 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'physics_mesh' mesh data", LogHeader, primName); | ||
378 | } | ||
379 | else if (map.ContainsKey("medium_lod")) | ||
380 | { | ||
381 | physicsParms = (OSDMap)map["medium_lod"]; // if no physics mesh, try to fall back to medium LOD display mesh | ||
382 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'medium_lod' mesh data", LogHeader, primName); | ||
383 | } | ||
384 | else if (map.ContainsKey("high_lod")) | ||
385 | { | ||
386 | physicsParms = (OSDMap)map["high_lod"]; // if all else fails, use highest LOD display mesh and hope it works :) | ||
387 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}':using 'high_lod' mesh data", LogHeader, primName); | ||
388 | } | ||
389 | |||
390 | if (map.ContainsKey("physics_convex")) | ||
391 | { // pull this out also in case physics engine can use it | ||
392 | OSD convexBlockOsd = null; | ||
393 | try | ||
394 | { | ||
395 | OSDMap convexBlock = (OSDMap)map["physics_convex"]; | ||
396 | { | ||
397 | int convexOffset = convexBlock["offset"].AsInteger() + (int)start; | ||
398 | int convexSize = convexBlock["size"].AsInteger(); | ||
399 | |||
400 | byte[] convexBytes = new byte[convexSize]; | ||
401 | |||
402 | System.Buffer.BlockCopy(primShape.SculptData, convexOffset, convexBytes, 0, convexSize); | ||
403 | |||
404 | try | ||
405 | { | ||
406 | convexBlockOsd = DecompressOsd(convexBytes); | ||
407 | } | ||
408 | catch (Exception e) | ||
409 | { | ||
410 | m_log.ErrorFormat("{0} prim='{1}': exception decoding convex block: {2}", LogHeader, primName, e); | ||
411 | //return false; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | if (convexBlockOsd != null && convexBlockOsd is OSDMap) | ||
416 | { | ||
417 | convexBlock = convexBlockOsd as OSDMap; | ||
418 | |||
419 | if (debugDetail) | ||
420 | { | ||
421 | string keys = LogHeader + " keys found in convexBlock: "; | ||
422 | foreach (KeyValuePair<string, OSD> kvp in convexBlock) | ||
423 | keys += "'" + kvp.Key + "' "; | ||
424 | m_log.Debug(keys); | ||
425 | } | ||
426 | |||
427 | Vector3 min = new Vector3(-0.5f, -0.5f, -0.5f); | ||
428 | if (convexBlock.ContainsKey("Min")) min = convexBlock["Min"].AsVector3(); | ||
429 | Vector3 max = new Vector3(0.5f, 0.5f, 0.5f); | ||
430 | if (convexBlock.ContainsKey("Max")) max = convexBlock["Max"].AsVector3(); | ||
431 | |||
432 | List<Vector3> boundingHull = null; | ||
433 | |||
434 | if (convexBlock.ContainsKey("BoundingVerts")) | ||
435 | { | ||
436 | byte[] boundingVertsBytes = convexBlock["BoundingVerts"].AsBinary(); | ||
437 | boundingHull = new List<Vector3>(); | ||
438 | for (int i = 0; i < boundingVertsBytes.Length; ) | ||
439 | { | ||
440 | ushort uX = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
441 | ushort uY = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
442 | ushort uZ = Utils.BytesToUInt16(boundingVertsBytes, i); i += 2; | ||
443 | |||
444 | Vector3 pos = new Vector3( | ||
445 | Utils.UInt16ToFloat(uX, min.X, max.X), | ||
446 | Utils.UInt16ToFloat(uY, min.Y, max.Y), | ||
447 | Utils.UInt16ToFloat(uZ, min.Z, max.Z) | ||
448 | ); | ||
449 | |||
450 | boundingHull.Add(pos); | ||
451 | } | ||
452 | |||
453 | mBoundingHull = boundingHull; | ||
454 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed bounding hull. nVerts={2}", LogHeader, primName, mBoundingHull.Count); | ||
455 | } | ||
456 | |||
457 | if (convexBlock.ContainsKey("HullList")) | ||
458 | { | ||
459 | byte[] hullList = convexBlock["HullList"].AsBinary(); | ||
460 | |||
461 | byte[] posBytes = convexBlock["Positions"].AsBinary(); | ||
462 | |||
463 | List<List<Vector3>> hulls = new List<List<Vector3>>(); | ||
464 | int posNdx = 0; | ||
465 | |||
466 | foreach (byte cnt in hullList) | ||
467 | { | ||
468 | int count = cnt == 0 ? 256 : cnt; | ||
469 | List<Vector3> hull = new List<Vector3>(); | ||
470 | |||
471 | for (int i = 0; i < count; i++) | ||
472 | { | ||
473 | ushort uX = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
474 | ushort uY = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
475 | ushort uZ = Utils.BytesToUInt16(posBytes, posNdx); posNdx += 2; | ||
476 | |||
477 | Vector3 pos = new Vector3( | ||
478 | Utils.UInt16ToFloat(uX, min.X, max.X), | ||
479 | Utils.UInt16ToFloat(uY, min.Y, max.Y), | ||
480 | Utils.UInt16ToFloat(uZ, min.Z, max.Z) | ||
481 | ); | ||
482 | |||
483 | hull.Add(pos); | ||
484 | } | ||
485 | |||
486 | hulls.Add(hull); | ||
487 | } | ||
488 | |||
489 | mConvexHulls = hulls; | ||
490 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}': parsed hulls. nHulls={2}", LogHeader, primName, mConvexHulls.Count); | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | if (debugDetail) m_log.DebugFormat("{0} prim='{1}' has physics_convex but no HullList", LogHeader, primName); | ||
495 | } | ||
496 | } | ||
497 | } | ||
498 | catch (Exception e) | ||
499 | { | ||
500 | m_log.WarnFormat("{0} exception decoding convex block: {1}", LogHeader, e); | ||
501 | } | ||
502 | } | ||
361 | 503 | ||
362 | if (physicsParms == null) | 504 | if (physicsParms == null) |
363 | { | 505 | { |
@@ -374,34 +516,14 @@ namespace OpenSim.Region.Physics.Meshing | |||
374 | OSD decodedMeshOsd = new OSD(); | 516 | OSD decodedMeshOsd = new OSD(); |
375 | byte[] meshBytes = new byte[physSize]; | 517 | byte[] meshBytes = new byte[physSize]; |
376 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); | 518 | System.Buffer.BlockCopy(primShape.SculptData, physOffset, meshBytes, 0, physSize); |
377 | // byte[] decompressed = new byte[physSize * 5]; | 519 | // byte[] decompressed = new byte[physSize * 5]; |
378 | try | 520 | try |
379 | { | 521 | { |
380 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | 522 | 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 | } | 523 | } |
402 | catch (Exception e) | 524 | catch (Exception e) |
403 | { | 525 | { |
404 | m_log.Error("[MESH]: exception decoding physical mesh: " + e.ToString()); | 526 | m_log.ErrorFormat("{0} prim='{1}': exception decoding physical mesh: {2}", LogHeader, primName, e); |
405 | return false; | 527 | return false; |
406 | } | 528 | } |
407 | 529 | ||
@@ -410,7 +532,7 @@ namespace OpenSim.Region.Physics.Meshing | |||
410 | // physics_shape is an array of OSDMaps, one for each submesh | 532 | // physics_shape is an array of OSDMaps, one for each submesh |
411 | if (decodedMeshOsd is OSDArray) | 533 | if (decodedMeshOsd is OSDArray) |
412 | { | 534 | { |
413 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); | 535 | // Console.WriteLine("decodedMeshOsd for {0} - {1}", primName, Util.GetFormattedXml(decodedMeshOsd)); |
414 | 536 | ||
415 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; | 537 | decodedMeshOsdArray = (OSDArray)decodedMeshOsd; |
416 | foreach (OSD subMeshOsd in decodedMeshOsdArray) | 538 | foreach (OSD subMeshOsd in decodedMeshOsdArray) |
@@ -418,12 +540,50 @@ namespace OpenSim.Region.Physics.Meshing | |||
418 | if (subMeshOsd is OSDMap) | 540 | if (subMeshOsd is OSDMap) |
419 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); | 541 | AddSubMesh(subMeshOsd as OSDMap, size, coords, faces); |
420 | } | 542 | } |
543 | if (debugDetail) | ||
544 | m_log.DebugFormat("{0} {1}: mesh decoded. offset={2}, size={3}, nCoords={4}, nFaces={5}", | ||
545 | LogHeader, primName, physOffset, physSize, coords.Count, faces.Count); | ||
421 | } | 546 | } |
422 | } | 547 | } |
423 | 548 | ||
424 | return true; | 549 | return true; |
425 | } | 550 | } |
426 | 551 | ||
552 | |||
553 | /// <summary> | ||
554 | /// decompresses a gzipped OSD object | ||
555 | /// </summary> | ||
556 | /// <param name="decodedOsd"></param> the OSD object | ||
557 | /// <param name="meshBytes"></param> | ||
558 | /// <returns></returns> | ||
559 | private static OSD DecompressOsd(byte[] meshBytes) | ||
560 | { | ||
561 | OSD decodedOsd = null; | ||
562 | |||
563 | using (MemoryStream inMs = new MemoryStream(meshBytes)) | ||
564 | { | ||
565 | using (MemoryStream outMs = new MemoryStream()) | ||
566 | { | ||
567 | using (ZOutputStream zOut = new ZOutputStream(outMs)) | ||
568 | { | ||
569 | byte[] readBuffer = new byte[2048]; | ||
570 | int readLen = 0; | ||
571 | while ((readLen = inMs.Read(readBuffer, 0, readBuffer.Length)) > 0) | ||
572 | { | ||
573 | zOut.Write(readBuffer, 0, readLen); | ||
574 | } | ||
575 | zOut.Flush(); | ||
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 | |||
427 | /// <summary> | 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> |
@@ -700,6 +860,45 @@ namespace OpenSim.Region.Physics.Meshing | |||
700 | return true; | 860 | return true; |
701 | } | 861 | } |
702 | 862 | ||
863 | /// <summary> | ||
864 | /// temporary prototype code - please do not use until the interface has been finalized! | ||
865 | /// </summary> | ||
866 | /// <param name="size">value to scale the hull points by</param> | ||
867 | /// <returns>a list of vertices in the bounding hull if it exists and has been successfully decoded, otherwise null</returns> | ||
868 | public List<Vector3> GetBoundingHull(Vector3 size) | ||
869 | { | ||
870 | if (mBoundingHull == null) | ||
871 | return null; | ||
872 | |||
873 | List<Vector3> verts = new List<Vector3>(); | ||
874 | foreach (var vert in mBoundingHull) | ||
875 | verts.Add(vert * size); | ||
876 | |||
877 | return verts; | ||
878 | } | ||
879 | |||
880 | /// <summary> | ||
881 | /// temporary prototype code - please do not use until the interface has been finalized! | ||
882 | /// </summary> | ||
883 | /// <param name="size">value to scale the hull points by</param> | ||
884 | /// <returns>a list of hulls if they exist and have been successfully decoded, otherwise null</returns> | ||
885 | public List<List<Vector3>> GetConvexHulls(Vector3 size) | ||
886 | { | ||
887 | if (mConvexHulls == null) | ||
888 | return null; | ||
889 | |||
890 | List<List<Vector3>> hulls = new List<List<Vector3>>(); | ||
891 | foreach (var hull in mConvexHulls) | ||
892 | { | ||
893 | List<Vector3> verts = new List<Vector3>(); | ||
894 | foreach (var vert in hull) | ||
895 | verts.Add(vert * size); | ||
896 | hulls.Add(verts); | ||
897 | } | ||
898 | |||
899 | return hulls; | ||
900 | } | ||
901 | |||
703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 902 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
704 | { | 903 | { |
705 | return CreateMesh(primName, primShape, size, lod, false, true); | 904 | return CreateMesh(primName, primShape, size, lod, false, true); |
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 | ||