diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
33 files changed, 4048 insertions, 2728 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..6db5f5e 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 | ||
@@ -1263,7 +1263,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1263 | } | 1263 | } |
1264 | } | 1264 | } |
1265 | return ret; | 1265 | return ret; |
1266 | 1266 | ||
1267 | } | 1267 | } |
1268 | 1268 | ||
1269 | public override float GetAngularMotionDisc(BulletShape pShape) | 1269 | public override float GetAngularMotionDisc(BulletShape pShape) |
@@ -1353,10 +1353,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | 1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1354 | gObj.SetCollisionShape(shape); | 1354 | gObj.SetCollisionShape(shape); |
1355 | gObj.SetUserPointer(pLocalID); | 1355 | gObj.SetUserPointer(pLocalID); |
1356 | 1356 | ||
1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) | 1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) |
1358 | specialCollisionObjects[pLocalID] = gObj; | 1358 | specialCollisionObjects[pLocalID] = gObj; |
1359 | else | 1359 | else |
1360 | specialCollisionObjects.Add(pLocalID, gObj); | 1360 | specialCollisionObjects.Add(pLocalID, gObj); |
1361 | 1361 | ||
1362 | // TODO: Add to Special CollisionObjects! | 1362 | // TODO: Add to Special CollisionObjects! |
@@ -1447,8 +1447,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); | 1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); |
1448 | } | 1448 | } |
1449 | 1449 | ||
1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | 1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { |
1451 | 1451 | ||
1452 | if (cShape == null) | 1452 | if (cShape == null) |
1453 | return null; | 1453 | return null; |
1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | 1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; |
@@ -1456,7 +1456,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | 1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); |
1457 | 1457 | ||
1458 | 1458 | ||
1459 | return retShape; | 1459 | return retShape; |
1460 | } | 1460 | } |
1461 | 1461 | ||
1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | 1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) |
@@ -1475,7 +1475,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
1476 | break; | 1476 | break; |
1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | 1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: |
1478 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1478 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1479 | break; | 1479 | break; |
1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | 1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: |
1481 | ret = BSPhysicsShapeType.SHAPE_HULL; | 1481 | ret = BSPhysicsShapeType.SHAPE_HULL; |
@@ -1503,7 +1503,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1503 | ret = BSPhysicsShapeType.SHAPE_CONE; | 1503 | ret = BSPhysicsShapeType.SHAPE_CONE; |
1504 | break; | 1504 | break; |
1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | 1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: |
1506 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 1506 | ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; |
1507 | break; | 1507 | break; |
1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | 1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: |
1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | 1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; |
@@ -1547,7 +1547,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1547 | break; | 1547 | break; |
1548 | ///Used for GIMPACT Trimesh integration | 1548 | ///Used for GIMPACT Trimesh integration |
1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | 1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: |
1550 | ret = BSPhysicsShapeType.SHAPE_MESH; | 1550 | ret = BSPhysicsShapeType.SHAPE_GIMPACT; |
1551 | break; | 1551 | break; |
1552 | ///Multimaterial mesh | 1552 | ///Multimaterial mesh |
1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | 1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: |
@@ -1598,8 +1598,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
1599 | } | 1599 | } |
1600 | 1600 | ||
1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | 1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | 1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
1604 | 1604 | ||
1605 | { | 1605 | { |
@@ -1745,7 +1745,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1745 | { | 1745 | { |
1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | 1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1747 | CompoundShape compoundshape = new CompoundShape(false); | 1747 | CompoundShape compoundshape = new CompoundShape(false); |
1748 | 1748 | ||
1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | 1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); |
1750 | int ii = 1; | 1750 | int ii = 1; |
1751 | 1751 | ||
@@ -1761,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1761 | int ender = ((ii + 4) + (vertexCount*3)); | 1761 | int ender = ((ii + 4) + (vertexCount*3)); |
1762 | for (int iii = ii + 4; iii < ender; iii+=3) | 1762 | for (int iii = ii + 4; iii < ender; iii+=3) |
1763 | { | 1763 | { |
1764 | 1764 | ||
1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); | 1765 | virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); |
1766 | } | 1766 | } |
1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | 1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); |
@@ -1769,26 +1769,35 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1769 | compoundshape.AddChildShape(ref childTrans, convexShape); | 1769 | compoundshape.AddChildShape(ref childTrans, convexShape); |
1770 | ii += (vertexCount*3 + 4); | 1770 | ii += (vertexCount*3 + 4); |
1771 | } | 1771 | } |
1772 | 1772 | ||
1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | 1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); |
1774 | } | 1774 | } |
1775 | 1775 | ||
1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 1776 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
1777 | { | ||
1778 | /* TODO */ return null; | ||
1779 | } | ||
1780 | |||
1781 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
1777 | { | 1782 | { |
1778 | /* TODO */ return null; | 1783 | /* TODO */ return null; |
1784 | } | ||
1779 | 1785 | ||
1786 | public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1787 | { | ||
1788 | /* TODO */ return null; | ||
1780 | } | 1789 | } |
1781 | 1790 | ||
1782 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | 1791 | public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) |
1783 | { | 1792 | { |
1784 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | 1793 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); |
1785 | 1794 | ||
1786 | for (int iter = 0; iter < pVerticesCount; iter++) | 1795 | for (int iter = 0; iter < pVerticesCount; iter++) |
1787 | { | 1796 | { |
1788 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | 1797 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; |
1789 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | 1798 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; |
1790 | } | 1799 | } |
1791 | 1800 | ||
1792 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | 1801 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); |
1793 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | 1802 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); |
1794 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | 1803 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); |
@@ -1802,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1802 | mesh.m_vertexStride = 3; | 1811 | mesh.m_vertexStride = 3; |
1803 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1812 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1804 | mesh.m_triangleIndexStride = 3; | 1813 | mesh.m_triangleIndexStride = 3; |
1805 | 1814 | ||
1806 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1815 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1807 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1816 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1808 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | 1817 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); |
@@ -1811,9 +1820,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1811 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); | 1820 | return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); |
1812 | 1821 | ||
1813 | } | 1822 | } |
1823 | public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1824 | { | ||
1825 | // TODO: | ||
1826 | return null; | ||
1827 | } | ||
1814 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | 1828 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) |
1815 | { | 1829 | { |
1816 | 1830 | ||
1817 | String fileName = "objTest3.raw"; | 1831 | String fileName = "objTest3.raw"; |
1818 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | 1832 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); |
1819 | StreamWriter sw = new StreamWriter(completePath); | 1833 | StreamWriter sw = new StreamWriter(completePath); |
@@ -1839,7 +1853,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1839 | string s = vertices[indices[i * 3]].ToString("0.0000"); | 1853 | string s = vertices[indices[i * 3]].ToString("0.0000"); |
1840 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | 1854 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); |
1841 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | 1855 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); |
1842 | 1856 | ||
1843 | sw.Write(s + "\n"); | 1857 | sw.Write(s + "\n"); |
1844 | } | 1858 | } |
1845 | 1859 | ||
@@ -1861,7 +1875,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1861 | mesh.m_vertexStride = 3; | 1875 | mesh.m_vertexStride = 3; |
1862 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1876 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1863 | mesh.m_triangleIndexStride = 3; | 1877 | mesh.m_triangleIndexStride = 3; |
1864 | 1878 | ||
1865 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1879 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1866 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1880 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1867 | 1881 | ||
@@ -1892,7 +1906,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1892 | sw.Close(); | 1906 | sw.Close(); |
1893 | } | 1907 | } |
1894 | 1908 | ||
1895 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 1909 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
1896 | float scaleFactor, float collisionMargin) | 1910 | float scaleFactor, float collisionMargin) |
1897 | { | 1911 | { |
1898 | const int upAxis = 2; | 1912 | const int upAxis = 2; |
@@ -1934,14 +1948,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1934 | /* TODO */ | 1948 | /* TODO */ |
1935 | updatedEntityCount = 0; | 1949 | updatedEntityCount = 0; |
1936 | collidersCount = 0; | 1950 | collidersCount = 0; |
1937 | 1951 | ||
1938 | 1952 | ||
1939 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | 1953 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); |
1940 | 1954 | ||
1941 | return ret; | 1955 | return ret; |
1942 | } | 1956 | } |
1943 | 1957 | ||
1944 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | 1958 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, |
1945 | out int updatedEntityCount, out EntityProperties[] updatedEntities, | 1959 | out int updatedEntityCount, out EntityProperties[] updatedEntities, |
1946 | out int collidersCount, out CollisionDesc[] colliders) | 1960 | out int collidersCount, out CollisionDesc[] colliders) |
1947 | { | 1961 | { |
@@ -1950,24 +1964,24 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1950 | return epic; | 1964 | return epic; |
1951 | } | 1965 | } |
1952 | 1966 | ||
1953 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, | 1967 | 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) | 1968 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) |
1955 | { | 1969 | { |
1956 | int numSimSteps = 0; | 1970 | int numSimSteps = 0; |
1957 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | 1971 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); |
1958 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | 1972 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); |
1959 | LastEntityProperty=0; | 1973 | LastEntityProperty=0; |
1960 | 1974 | ||
1961 | 1975 | ||
1962 | 1976 | ||
1963 | 1977 | ||
1964 | 1978 | ||
1965 | 1979 | ||
1966 | LastCollisionDesc=0; | 1980 | LastCollisionDesc=0; |
1967 | 1981 | ||
1968 | updatedEntityCount = 0; | 1982 | updatedEntityCount = 0; |
1969 | collidersCount = 0; | 1983 | collidersCount = 0; |
1970 | 1984 | ||
1971 | 1985 | ||
1972 | if (pWorld is BulletWorldXNA) | 1986 | if (pWorld is BulletWorldXNA) |
1973 | { | 1987 | { |
@@ -2024,7 +2038,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2024 | 2038 | ||
2025 | collidersCount = LastCollisionDesc; | 2039 | collidersCount = LastCollisionDesc; |
2026 | colliders = UpdatedCollisions; | 2040 | colliders = UpdatedCollisions; |
2027 | 2041 | ||
2028 | 2042 | ||
2029 | } | 2043 | } |
2030 | else | 2044 | else |
@@ -2032,15 +2046,15 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2032 | //if (updatedEntities is null) | 2046 | //if (updatedEntities is null) |
2033 | //updatedEntities = new List<BulletXNA.EntityProperties>(); | 2047 | //updatedEntities = new List<BulletXNA.EntityProperties>(); |
2034 | //updatedEntityCount = 0; | 2048 | //updatedEntityCount = 0; |
2035 | 2049 | ||
2036 | 2050 | ||
2037 | //collidersCount = 0; | 2051 | //collidersCount = 0; |
2038 | 2052 | ||
2039 | updatedEntities = new EntityProperties[0]; | 2053 | updatedEntities = new EntityProperties[0]; |
2040 | 2054 | ||
2041 | 2055 | ||
2042 | colliders = new CollisionDesc[0]; | 2056 | colliders = new CollisionDesc[0]; |
2043 | 2057 | ||
2044 | } | 2058 | } |
2045 | return numSimSteps; | 2059 | return numSimSteps; |
2046 | } | 2060 | } |
@@ -2048,7 +2062,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2048 | { | 2062 | { |
2049 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | 2063 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); |
2050 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | 2064 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); |
2051 | 2065 | ||
2052 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | 2066 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; |
2053 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | 2067 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); |
2054 | BroadphasePair collisionPair; | 2068 | BroadphasePair collisionPair; |
@@ -2060,7 +2074,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2060 | ManifoldPoint pt; | 2074 | ManifoldPoint pt; |
2061 | 2075 | ||
2062 | int numPairs = pairs.Count; | 2076 | int numPairs = pairs.Count; |
2063 | 2077 | ||
2064 | for (int i = 0; i < numPairs; i++) | 2078 | for (int i = 0; i < numPairs; i++) |
2065 | { | 2079 | { |
2066 | manifoldArray.Clear(); | 2080 | manifoldArray.Clear(); |
@@ -2069,7 +2083,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2069 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | 2083 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); |
2070 | if (collisionPair == null) | 2084 | if (collisionPair == null) |
2071 | continue; | 2085 | continue; |
2072 | 2086 | ||
2073 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | 2087 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); |
2074 | for (int j = 0; j < manifoldArray.Count; j++) | 2088 | for (int j = 0; j < manifoldArray.Count; j++) |
2075 | { | 2089 | { |
@@ -2092,7 +2106,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2092 | } | 2106 | } |
2093 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | 2107 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) |
2094 | { | 2108 | { |
2095 | 2109 | ||
2096 | IndexedVector3 contactNormal = norm; | 2110 | IndexedVector3 contactNormal = norm; |
2097 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | 2111 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && |
2098 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | 2112 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) |
@@ -2162,11 +2176,11 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2162 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | 2176 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) |
2163 | { | 2177 | { |
2164 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; | 2178 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; |
2165 | 2179 | ||
2166 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | 2180 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); |
2167 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | 2181 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); |
2168 | using ( | 2182 | using ( |
2169 | ClosestNotMeRayResultCallback rayCallback = | 2183 | ClosestNotMeRayResultCallback rayCallback = |
2170 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | 2184 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) |
2171 | ) | 2185 | ) |
2172 | { | 2186 | { |
@@ -2182,9 +2196,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2182 | return false; | 2196 | return false; |
2183 | } | 2197 | } |
2184 | } | 2198 | } |
2185 | |||
2186 | 2199 | ||
2187 | 2200 | ||
2201 | |||
2188 | 2202 | ||
2189 | public class SimMotionState : DefaultMotionState | 2203 | public class SimMotionState : DefaultMotionState |
2190 | { | 2204 | { |
@@ -2277,12 +2291,12 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2277 | m_lastProperties = m_properties; | 2291 | m_lastProperties = m_properties; |
2278 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | 2292 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) |
2279 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | 2293 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); |
2280 | 2294 | ||
2281 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | 2295 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; |
2282 | } | 2296 | } |
2283 | 2297 | ||
2284 | 2298 | ||
2285 | 2299 | ||
2286 | 2300 | ||
2287 | } | 2301 | } |
2288 | public override void SetRigidBody(RigidBody body) | 2302 | public override void SetRigidBody(RigidBody body) |
@@ -2305,7 +2319,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
2305 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | 2319 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && |
2306 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | 2320 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); |
2307 | } | 2321 | } |
2308 | 2322 | ||
2309 | } | 2323 | } |
2310 | } | 2324 | } |
2311 | 2325 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs new file mode 100755 index 0000000..ac8c30c --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs | |||
@@ -0,0 +1,351 @@ | |||
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 | float m_lastStepUp; | ||
47 | |||
48 | public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
49 | : base(physicsScene, pObj, actorName) | ||
50 | { | ||
51 | m_velocityMotor = null; | ||
52 | m_walkingUpStairs = 0; | ||
53 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); | ||
54 | } | ||
55 | |||
56 | // BSActor.isActive | ||
57 | public override bool isActive | ||
58 | { | ||
59 | get { return Enabled && m_controllingPrim.IsPhysicallyActive; } | ||
60 | } | ||
61 | |||
62 | // Release any connections and resources used by the actor. | ||
63 | // BSActor.Dispose() | ||
64 | public override void Dispose() | ||
65 | { | ||
66 | Enabled = false; | ||
67 | } | ||
68 | |||
69 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
70 | // Called at taint-time. | ||
71 | // BSActor.Refresh() | ||
72 | public override void Refresh() | ||
73 | { | ||
74 | m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); | ||
75 | |||
76 | // If the object is physically active, add the hoverer prestep action | ||
77 | if (isActive) | ||
78 | { | ||
79 | ActivateAvatarMove(); | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | DeactivateAvatarMove(); | ||
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 | // Usually called when target velocity changes to set the current velocity and the target | ||
97 | // into the movement motor. | ||
98 | public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) | ||
99 | { | ||
100 | m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate() | ||
101 | { | ||
102 | if (m_velocityMotor != null) | ||
103 | { | ||
104 | m_velocityMotor.Reset(); | ||
105 | m_velocityMotor.SetTarget(targ); | ||
106 | m_velocityMotor.SetCurrent(vel); | ||
107 | m_velocityMotor.Enabled = true; | ||
108 | } | ||
109 | }); | ||
110 | } | ||
111 | |||
112 | // If a hover motor has not been created, create one and start the hovering. | ||
113 | private void ActivateAvatarMove() | ||
114 | { | ||
115 | if (m_velocityMotor == null) | ||
116 | { | ||
117 | // Infinite decay and timescale values so motor only changes current to target values. | ||
118 | m_velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
119 | 0.2f, // time scale | ||
120 | BSMotor.Infinite, // decay time scale | ||
121 | 1f // efficiency | ||
122 | ); | ||
123 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
124 | SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); | ||
125 | |||
126 | m_physicsScene.BeforeStep += Mover; | ||
127 | |||
128 | m_walkingUpStairs = 0; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | private void DeactivateAvatarMove() | ||
133 | { | ||
134 | if (m_velocityMotor != null) | ||
135 | { | ||
136 | m_physicsScene.BeforeStep -= Mover; | ||
137 | m_velocityMotor = null; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
142 | private void Mover(float timeStep) | ||
143 | { | ||
144 | // Don't do movement while the object is selected. | ||
145 | if (!isActive) | ||
146 | return; | ||
147 | |||
148 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
149 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
150 | |||
151 | // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity | ||
152 | // specified for the avatar is the one that should be used. For falling, if the avatar | ||
153 | // is not flying and is not colliding then it is presumed to be falling and the Z | ||
154 | // component is not fooled with (thus allowing gravity to do its thing). | ||
155 | // When the avatar is standing, though, the user has specified a velocity of zero and | ||
156 | // the avatar should be standing. But if the avatar is pushed by something in the world | ||
157 | // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to | ||
158 | // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity | ||
159 | // errors can creap in and the avatar will slowly float off in some direction. | ||
160 | // So, the problem is that, when an avatar is standing, we cannot tell creaping error | ||
161 | // from real pushing. | ||
162 | // The code below uses whether the collider is static or moving to decide whether to zero motion. | ||
163 | |||
164 | m_velocityMotor.Step(timeStep); | ||
165 | m_controllingPrim.IsStationary = false; | ||
166 | |||
167 | // If we're not supposed to be moving, make sure things are zero. | ||
168 | if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) | ||
169 | { | ||
170 | // The avatar shouldn't be moving | ||
171 | m_velocityMotor.Zero(); | ||
172 | |||
173 | if (m_controllingPrim.IsColliding) | ||
174 | { | ||
175 | // If we are colliding with a stationary object, presume we're standing and don't move around | ||
176 | if (!m_controllingPrim.ColliderIsMoving) | ||
177 | { | ||
178 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); | ||
179 | m_controllingPrim.IsStationary = true; | ||
180 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
181 | } | ||
182 | |||
183 | // Standing has more friction on the ground | ||
184 | if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) | ||
185 | { | ||
186 | m_controllingPrim.Friction = BSParam.AvatarStandingFriction; | ||
187 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
188 | } | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | if (m_controllingPrim.Flying) | ||
193 | { | ||
194 | // Flying and not collising and velocity nearly zero. | ||
195 | m_controllingPrim.ZeroMotion(true /* inTaintTime */); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", | ||
200 | m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // Supposed to be moving. | ||
205 | OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; | ||
206 | |||
207 | if (m_controllingPrim.Friction != BSParam.AvatarFriction) | ||
208 | { | ||
209 | // Probably starting up walking. Set friction to moving friction. | ||
210 | m_controllingPrim.Friction = BSParam.AvatarFriction; | ||
211 | m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); | ||
212 | } | ||
213 | |||
214 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
215 | // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force). | ||
216 | if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding) | ||
217 | { | ||
218 | if (m_controllingPrim.RawVelocity.Z < 0) | ||
219 | stepVelocity.Z = m_controllingPrim.RawVelocity.Z; | ||
220 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
221 | } | ||
222 | |||
223 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
224 | OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; | ||
225 | |||
226 | // Add special movement force to allow avatars to walk up stepped surfaces. | ||
227 | moveForce += WalkUpStairs(); | ||
228 | |||
229 | m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", | ||
230 | m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); | ||
231 | m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | // Decide if the character is colliding with a low object and compute a force to pop the | ||
236 | // avatar up so it can walk up and over the low objects. | ||
237 | private OMV.Vector3 WalkUpStairs() | ||
238 | { | ||
239 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
240 | |||
241 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", | ||
242 | m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, | ||
243 | m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); | ||
244 | // This test is done if moving forward, not flying and is colliding with something. | ||
245 | // Check for stairs climbing if colliding, not flying and moving forward | ||
246 | if ( m_controllingPrim.IsColliding | ||
247 | && !m_controllingPrim.Flying | ||
248 | && m_controllingPrim.TargetVelocitySpeed > 0.1f ) | ||
249 | { | ||
250 | // The range near the character's feet where we will consider stairs | ||
251 | // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; | ||
252 | // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off | ||
253 | // from the height. Revisit size and this computation when height is scaled properly. | ||
254 | float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f; | ||
255 | float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; | ||
256 | |||
257 | // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. | ||
258 | // Find the highest 'good' collision. | ||
259 | OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; | ||
260 | foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) | ||
261 | { | ||
262 | // Don't care about collisions with the terrain | ||
263 | if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) | ||
264 | { | ||
265 | OMV.Vector3 touchPosition = kvp.Value.Position; | ||
266 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", | ||
267 | m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); | ||
268 | if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) | ||
269 | { | ||
270 | // This contact is within the 'near the feet' range. | ||
271 | // The normal should be our contact point to the object so it is pointing away | ||
272 | // thus the difference between our facing orientation and the normal should be small. | ||
273 | OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; | ||
274 | OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); | ||
275 | float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); | ||
276 | if (diff < BSParam.AvatarStepApproachFactor) | ||
277 | { | ||
278 | if (highestTouchPosition.Z < touchPosition.Z) | ||
279 | highestTouchPosition = touchPosition; | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | m_walkingUpStairs = 0; | ||
285 | // If there is a good step sensing, move the avatar over the step. | ||
286 | if (highestTouchPosition != OMV.Vector3.Zero) | ||
287 | { | ||
288 | // Remember that we are going up stairs. This is needed because collisions | ||
289 | // will stop when we move up so this smoothes out that effect. | ||
290 | m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; | ||
291 | |||
292 | m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; | ||
293 | ret = ComputeStairCorrection(m_lastStepUp); | ||
294 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", | ||
295 | m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); | ||
296 | } | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | // If we used to be going up stairs but are not now, smooth the case where collision goes away while | ||
301 | // we are bouncing up the stairs. | ||
302 | if (m_walkingUpStairs > 0) | ||
303 | { | ||
304 | m_walkingUpStairs--; | ||
305 | ret = ComputeStairCorrection(m_lastStepUp); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | return ret; | ||
310 | } | ||
311 | |||
312 | private OMV.Vector3 ComputeStairCorrection(float stepUp) | ||
313 | { | ||
314 | OMV.Vector3 ret = OMV.Vector3.Zero; | ||
315 | OMV.Vector3 displacement = OMV.Vector3.Zero; | ||
316 | |||
317 | if (stepUp > 0f) | ||
318 | { | ||
319 | // Found the stairs contact point. Push up a little to raise the character. | ||
320 | if (BSParam.AvatarStepForceFactor > 0f) | ||
321 | { | ||
322 | float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; | ||
323 | ret = new OMV.Vector3(0f, 0f, upForce); | ||
324 | } | ||
325 | |||
326 | // Also move the avatar up for the new height | ||
327 | if (BSParam.AvatarStepUpCorrectionFactor > 0f) | ||
328 | { | ||
329 | // Move the avatar up related to the height of the collision | ||
330 | displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); | ||
331 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | if (BSParam.AvatarStepUpCorrectionFactor < 0f) | ||
336 | { | ||
337 | // Move the avatar up about the specified step height | ||
338 | displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); | ||
339 | m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; | ||
340 | } | ||
341 | } | ||
342 | m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}", | ||
343 | m_controllingPrim.LocalID, displacement, ret); | ||
344 | |||
345 | } | ||
346 | return ret; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | |||
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..75ff24e --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs | |||
@@ -0,0 +1,157 @@ | |||
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 | 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},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", | ||
69 | m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, | ||
70 | m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); | ||
71 | |||
72 | // If not active any more... | ||
73 | if (!m_controllingPrim.MoveToTargetActive) | ||
74 | { | ||
75 | Enabled = false; | ||
76 | } | ||
77 | |||
78 | if (isActive) | ||
79 | { | ||
80 | ActivateMoveToTarget(); | ||
81 | } | ||
82 | else | ||
83 | { | ||
84 | DeactivateMoveToTarget(); | ||
85 | } | ||
86 | } | ||
87 | |||
88 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
89 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
90 | // Called at taint-time. | ||
91 | // BSActor.RemoveDependencies() | ||
92 | public override void RemoveDependencies() | ||
93 | { | ||
94 | // Nothing to do for the moveToTarget since it is all software at pre-step action time. | ||
95 | } | ||
96 | |||
97 | // If a hover motor has not been created, create one and start the hovering. | ||
98 | private void ActivateMoveToTarget() | ||
99 | { | ||
100 | if (m_targetMotor == null) | ||
101 | { | ||
102 | // We're taking over after this. | ||
103 | m_controllingPrim.ZeroMotion(true); | ||
104 | |||
105 | m_targetMotor = new BSVMotor("BSActorMoveToTargget.Activate", | ||
106 | m_controllingPrim.MoveToTargetTau, // timeScale | ||
107 | BSMotor.Infinite, // decay time scale | ||
108 | 1f // efficiency | ||
109 | ); | ||
110 | m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
111 | m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); | ||
112 | m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); | ||
113 | |||
114 | m_physicsScene.BeforeStep += Mover; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | private void DeactivateMoveToTarget() | ||
119 | { | ||
120 | if (m_targetMotor != null) | ||
121 | { | ||
122 | m_physicsScene.BeforeStep -= Mover; | ||
123 | m_targetMotor = null; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | // Called just before the simulation step. Update the vertical position for hoverness. | ||
128 | private void Mover(float timeStep) | ||
129 | { | ||
130 | // Don't do hovering while the object is selected. | ||
131 | if (!isActive) | ||
132 | return; | ||
133 | |||
134 | OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) | ||
135 | |||
136 | // 'movePosition' is where we'd like the prim to be at this moment. | ||
137 | OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); | ||
138 | |||
139 | // If we are very close to our target, turn off the movement motor. | ||
140 | if (m_targetMotor.ErrorIsZero()) | ||
141 | { | ||
142 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", | ||
143 | m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); | ||
144 | m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; | ||
145 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
146 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | m_controllingPrim.ForcePosition = movePosition; | ||
151 | // Setting the position does not cause the physics engine to generate a property update. Force it. | ||
152 | m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); | ||
153 | } | ||
154 | m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition); | ||
155 | } | ||
156 | } | ||
157 | } | ||
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..fff63e4 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs | |||
@@ -0,0 +1,160 @@ | |||
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 | Release(); | ||
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 Release() | ||
102 | { | ||
103 | ForEachActor(a => a.Dispose()); | ||
104 | } | ||
105 | public void Refresh() | ||
106 | { | ||
107 | ForEachActor(a => a.Refresh()); | ||
108 | } | ||
109 | public void RemoveDependencies() | ||
110 | { | ||
111 | ForEachActor(a => a.RemoveDependencies()); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // ============================================================================= | ||
116 | /// <summary> | ||
117 | /// Each physical object can have 'actors' who are pushing the object around. | ||
118 | /// This can be used for hover, locking axis, making vehicles, etc. | ||
119 | /// Each physical object can have multiple actors acting on it. | ||
120 | /// | ||
121 | /// An actor usually registers itself with physics scene events (pre-step action) | ||
122 | /// and modifies the parameters on the host physical object. | ||
123 | /// </summary> | ||
124 | public abstract class BSActor | ||
125 | { | ||
126 | protected BSScene m_physicsScene { get; private set; } | ||
127 | protected BSPhysObject m_controllingPrim { get; private set; } | ||
128 | public virtual bool Enabled { get; set; } | ||
129 | public string ActorName { get; private set; } | ||
130 | |||
131 | public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) | ||
132 | { | ||
133 | m_physicsScene = physicsScene; | ||
134 | m_controllingPrim = pObj; | ||
135 | ActorName = actorName; | ||
136 | Enabled = true; | ||
137 | } | ||
138 | |||
139 | // Return 'true' if activily updating the prim | ||
140 | public virtual bool isActive | ||
141 | { | ||
142 | get { return Enabled; } | ||
143 | } | ||
144 | |||
145 | // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. | ||
146 | // Anyone else should assign true/false to 'Enabled'. | ||
147 | public void SetEnabled(bool setEnabled) | ||
148 | { | ||
149 | Enabled = setEnabled; | ||
150 | } | ||
151 | // Release any connections and resources used by the actor. | ||
152 | public abstract void Dispose(); | ||
153 | // Called when physical parameters (properties set in Bullet) need to be re-applied. | ||
154 | public abstract void Refresh(); | ||
155 | // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). | ||
156 | // Register a prestep action to restore physical requirements before the next simulation step. | ||
157 | public abstract void RemoveDependencies(); | ||
158 | |||
159 | } | ||
160 | } | ||
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..48f842e 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 | * |
@@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject | |||
46 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
47 | private float _mass; | 47 | private float _mass; |
48 | private float _avatarVolume; | 48 | private float _avatarVolume; |
49 | private OMV.Vector3 _force; | ||
50 | private OMV.Vector3 _velocity; | ||
51 | private OMV.Vector3 _torque; | ||
52 | private float _collisionScore; | 49 | private float _collisionScore; |
53 | private OMV.Vector3 _acceleration; | 50 | private OMV.Vector3 _acceleration; |
54 | private OMV.Quaternion _orientation; | 51 | private OMV.Quaternion _orientation; |
@@ -62,15 +59,12 @@ public sealed class BSCharacter : BSPhysObject | |||
62 | private bool _kinematic; | 59 | private bool _kinematic; |
63 | private float _buoyancy; | 60 | private float _buoyancy; |
64 | 61 | ||
65 | private BSVMotor _velocityMotor; | 62 | private BSActorAvatarMove m_moveActor; |
63 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; | ||
66 | 64 | ||
67 | private OMV.Vector3 _PIDTarget; | 65 | private OMV.Vector3 _PIDTarget; |
68 | private bool _usePID; | 66 | private bool _usePID; |
69 | private float _PIDTau; | 67 | private float _PIDTau; |
70 | private bool _useHoverPID; | ||
71 | private float _PIDHoverHeight; | ||
72 | private PIDHoverType _PIDHoverType; | ||
73 | private float _PIDHoverTao; | ||
74 | 68 | ||
75 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | 69 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) |
76 | : base(parent_scene, localID, avName, "BSCharacter") | 70 | : base(parent_scene, localID, avName, "BSCharacter") |
@@ -80,7 +74,7 @@ public sealed class BSCharacter : BSPhysObject | |||
80 | 74 | ||
81 | _flying = isFlying; | 75 | _flying = isFlying; |
82 | _orientation = OMV.Quaternion.Identity; | 76 | _orientation = OMV.Quaternion.Identity; |
83 | _velocity = OMV.Vector3.Zero; | 77 | RawVelocity = OMV.Vector3.Zero; |
84 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 78 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
85 | Friction = BSParam.AvatarStandingFriction; | 79 | Friction = BSParam.AvatarStandingFriction; |
86 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; | 80 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; |
@@ -97,17 +91,22 @@ public sealed class BSCharacter : BSPhysObject | |||
97 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 91 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
98 | ComputeAvatarVolumeAndMass(); | 92 | ComputeAvatarVolumeAndMass(); |
99 | 93 | ||
100 | SetupMovementMotor(); | 94 | // The avatar's movement is controlled by this motor that speeds up and slows down |
95 | // the avatar seeking to reach the motor's target speed. | ||
96 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
97 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
98 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); | ||
99 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | ||
101 | 100 | ||
102 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 101 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
103 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 102 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
104 | 103 | ||
105 | // do actual creation in taint time | 104 | // do actual creation in taint time |
106 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 105 | PhysScene.TaintedObject("BSCharacter.create", delegate() |
107 | { | 106 | { |
108 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 107 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
109 | // New body and shape into PhysBody and PhysShape | 108 | // New body and shape into PhysBody and PhysShape |
110 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | 109 | PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); |
111 | 110 | ||
112 | SetPhysicalProperties(); | 111 | SetPhysicalProperties(); |
113 | }); | 112 | }); |
@@ -120,214 +119,63 @@ public sealed class BSCharacter : BSPhysObject | |||
120 | base.Destroy(); | 119 | base.Destroy(); |
121 | 120 | ||
122 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 121 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
123 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 122 | PhysScene.TaintedObject("BSCharacter.destroy", delegate() |
124 | { | 123 | { |
125 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); | 124 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
126 | PhysBody.Clear(); | 125 | PhysBody.Clear(); |
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); | 126 | PhysShape.Dereference(PhysScene); |
128 | PhysShape.Clear(); | 127 | PhysShape = new BSShapeNull(); |
129 | }); | 128 | }); |
130 | } | 129 | } |
131 | 130 | ||
132 | private void SetPhysicalProperties() | 131 | private void SetPhysicalProperties() |
133 | { | 132 | { |
134 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 133 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
135 | 134 | ||
136 | ZeroMotion(true); | 135 | ZeroMotion(true); |
137 | ForcePosition = _position; | 136 | ForcePosition = _position; |
138 | 137 | ||
139 | // Set the velocity | 138 | // Set the velocity |
140 | _velocityMotor.Reset(); | 139 | if (m_moveActor != null) |
141 | _velocityMotor.SetTarget(_velocity); | 140 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); |
142 | _velocityMotor.SetCurrent(_velocity); | 141 | |
143 | ForceVelocity = _velocity; | 142 | ForceVelocity = RawVelocity; |
144 | 143 | ||
145 | // This will enable or disable the flying buoyancy of the avatar. | 144 | // 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. | 145 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
147 | Flying = _flying; | 146 | Flying = _flying; |
148 | 147 | ||
149 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | 148 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
150 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | 149 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); |
151 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 150 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
152 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 151 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
153 | if (BSParam.CcdMotionThreshold > 0f) | 152 | if (BSParam.CcdMotionThreshold > 0f) |
154 | { | 153 | { |
155 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 154 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
156 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 155 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
157 | } | 156 | } |
158 | 157 | ||
159 | UpdatePhysicalMassProperties(RawMass, false); | 158 | UpdatePhysicalMassProperties(RawMass, false); |
160 | 159 | ||
161 | // Make so capsule does not fall over | 160 | // Make so capsule does not fall over |
162 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | 161 | PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
162 | |||
163 | // The avatar mover sets some parameters. | ||
164 | PhysicalActors.Refresh(); | ||
163 | 165 | ||
164 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 166 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
165 | 167 | ||
166 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 168 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
167 | 169 | ||
168 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 170 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
169 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | 171 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
170 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 172 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
171 | 173 | ||
172 | // Do this after the object has been added to the world | 174 | // Do this after the object has been added to the world |
173 | PhysBody.collisionType = CollisionType.Avatar; | 175 | PhysBody.collisionType = CollisionType.Avatar; |
174 | PhysBody.ApplyCollisionMask(PhysicsScene); | 176 | 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 | } | 177 | } |
279 | 178 | ||
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 | 179 | ||
332 | public override void RequestPhysicsterseUpdate() | 180 | public override void RequestPhysicsterseUpdate() |
333 | { | 181 | { |
@@ -355,14 +203,14 @@ public sealed class BSCharacter : BSPhysObject | |||
355 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 203 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
356 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); | 204 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
357 | 205 | ||
358 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 206 | PhysScene.TaintedObject("BSCharacter.setSize", delegate() |
359 | { | 207 | { |
360 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | 208 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) |
361 | { | 209 | { |
362 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 210 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
363 | UpdatePhysicalMassProperties(RawMass, true); | 211 | UpdatePhysicalMassProperties(RawMass, true); |
364 | // Make sure this change appears as a property update event | 212 | // Make sure this change appears as a property update event |
365 | PhysicsScene.PE.PushUpdate(PhysBody); | 213 | PhysScene.PE.PushUpdate(PhysBody); |
366 | } | 214 | } |
367 | }); | 215 | }); |
368 | 216 | ||
@@ -373,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject | |||
373 | { | 221 | { |
374 | set { BaseShape = value; } | 222 | set { BaseShape = value; } |
375 | } | 223 | } |
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 | 224 | ||
382 | public override bool Grabbed { | 225 | public override bool Grabbed { |
383 | set { _grabbed = value; } | 226 | set { _grabbed = value; } |
@@ -399,29 +242,29 @@ public sealed class BSCharacter : BSPhysObject | |||
399 | // Called at taint time! | 242 | // Called at taint time! |
400 | public override void ZeroMotion(bool inTaintTime) | 243 | public override void ZeroMotion(bool inTaintTime) |
401 | { | 244 | { |
402 | _velocity = OMV.Vector3.Zero; | 245 | RawVelocity = OMV.Vector3.Zero; |
403 | _acceleration = OMV.Vector3.Zero; | 246 | _acceleration = OMV.Vector3.Zero; |
404 | _rotationalVelocity = OMV.Vector3.Zero; | 247 | _rotationalVelocity = OMV.Vector3.Zero; |
405 | 248 | ||
406 | // Zero some other properties directly into the physics engine | 249 | // Zero some other properties directly into the physics engine |
407 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 250 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
408 | { | 251 | { |
409 | if (PhysBody.HasPhysicalBody) | 252 | if (PhysBody.HasPhysicalBody) |
410 | PhysicsScene.PE.ClearAllForces(PhysBody); | 253 | PhysScene.PE.ClearAllForces(PhysBody); |
411 | }); | 254 | }); |
412 | } | 255 | } |
413 | public override void ZeroAngularMotion(bool inTaintTime) | 256 | public override void ZeroAngularMotion(bool inTaintTime) |
414 | { | 257 | { |
415 | _rotationalVelocity = OMV.Vector3.Zero; | 258 | _rotationalVelocity = OMV.Vector3.Zero; |
416 | 259 | ||
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 260 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
418 | { | 261 | { |
419 | if (PhysBody.HasPhysicalBody) | 262 | if (PhysBody.HasPhysicalBody) |
420 | { | 263 | { |
421 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | 264 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
422 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | 265 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
423 | // The next also get rid of applied linear force but the linear velocity is untouched. | 266 | // The next also get rid of applied linear force but the linear velocity is untouched. |
424 | PhysicsScene.PE.ClearForces(PhysBody); | 267 | PhysScene.PE.ClearForces(PhysBody); |
425 | } | 268 | } |
426 | }); | 269 | }); |
427 | } | 270 | } |
@@ -443,7 +286,7 @@ public sealed class BSCharacter : BSPhysObject | |||
443 | set { | 286 | set { |
444 | _position = value; | 287 | _position = value; |
445 | 288 | ||
446 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 289 | PhysScene.TaintedObject("BSCharacter.setPosition", delegate() |
447 | { | 290 | { |
448 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 291 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
449 | PositionSanityCheck(); | 292 | PositionSanityCheck(); |
@@ -453,14 +296,14 @@ public sealed class BSCharacter : BSPhysObject | |||
453 | } | 296 | } |
454 | public override OMV.Vector3 ForcePosition { | 297 | public override OMV.Vector3 ForcePosition { |
455 | get { | 298 | get { |
456 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 299 | _position = PhysScene.PE.GetPosition(PhysBody); |
457 | return _position; | 300 | return _position; |
458 | } | 301 | } |
459 | set { | 302 | set { |
460 | _position = value; | 303 | _position = value; |
461 | if (PhysBody.HasPhysicalBody) | 304 | if (PhysBody.HasPhysicalBody) |
462 | { | 305 | { |
463 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 306 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
464 | } | 307 | } |
465 | } | 308 | } |
466 | } | 309 | } |
@@ -474,18 +317,18 @@ public sealed class BSCharacter : BSPhysObject | |||
474 | bool ret = false; | 317 | bool ret = false; |
475 | 318 | ||
476 | // TODO: check for out of bounds | 319 | // TODO: check for out of bounds |
477 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 320 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
478 | { | 321 | { |
479 | // The character is out of the known/simulated area. | 322 | // The character is out of the known/simulated area. |
480 | // Force the avatar position to be within known. ScenePresence will use the position | 323 | // 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. | 324 | // plus the velocity to decide if the avatar is moving out of the region. |
482 | RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); | 325 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); |
483 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | 326 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); |
484 | return true; | 327 | return true; |
485 | } | 328 | } |
486 | 329 | ||
487 | // If below the ground, move the avatar up | 330 | // If below the ground, move the avatar up |
488 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 331 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
489 | if (Position.Z < terrainHeight) | 332 | if (Position.Z < terrainHeight) |
490 | { | 333 | { |
491 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 334 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
@@ -494,7 +337,7 @@ public sealed class BSCharacter : BSPhysObject | |||
494 | } | 337 | } |
495 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 338 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
496 | { | 339 | { |
497 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 340 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
498 | if (Position.Z < waterHeight) | 341 | if (Position.Z < waterHeight) |
499 | { | 342 | { |
500 | _position.Z = waterHeight; | 343 | _position.Z = waterHeight; |
@@ -515,7 +358,7 @@ public sealed class BSCharacter : BSPhysObject | |||
515 | { | 358 | { |
516 | // The new position value must be pushed into the physics engine but we can't | 359 | // 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. | 360 | // just assign to "Position" because of potential call loops. |
518 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 361 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
519 | { | 362 | { |
520 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 363 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
521 | ForcePosition = _position; | 364 | ForcePosition = _position; |
@@ -528,25 +371,25 @@ public sealed class BSCharacter : BSPhysObject | |||
528 | public override float Mass { get { return _mass; } } | 371 | public override float Mass { get { return _mass; } } |
529 | 372 | ||
530 | // used when we only want this prim's mass and not the linkset thing | 373 | // used when we only want this prim's mass and not the linkset thing |
531 | public override float RawMass { | 374 | public override float RawMass { |
532 | get {return _mass; } | 375 | get {return _mass; } |
533 | } | 376 | } |
534 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 377 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
535 | { | 378 | { |
536 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 379 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
537 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | 380 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
538 | } | 381 | } |
539 | 382 | ||
540 | public override OMV.Vector3 Force { | 383 | public override OMV.Vector3 Force { |
541 | get { return _force; } | 384 | get { return RawForce; } |
542 | set { | 385 | set { |
543 | _force = value; | 386 | RawForce = value; |
544 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 387 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
545 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 388 | PhysScene.TaintedObject("BSCharacter.SetForce", delegate() |
546 | { | 389 | { |
547 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 390 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
548 | if (PhysBody.HasPhysicalBody) | 391 | if (PhysBody.HasPhysicalBody) |
549 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 392 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); |
550 | }); | 393 | }); |
551 | } | 394 | } |
552 | } | 395 | } |
@@ -569,61 +412,49 @@ public sealed class BSCharacter : BSPhysObject | |||
569 | { | 412 | { |
570 | get | 413 | get |
571 | { | 414 | { |
572 | return m_targetVelocity; | 415 | return base.m_targetVelocity; |
573 | } | 416 | } |
574 | set | 417 | set |
575 | { | 418 | { |
576 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | 419 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); |
577 | m_targetVelocity = value; | 420 | m_targetVelocity = value; |
578 | OMV.Vector3 targetVel = value; | 421 | OMV.Vector3 targetVel = value; |
579 | if (_setAlwaysRun) | 422 | if (_setAlwaysRun && !_flying) |
580 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); | 423 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); |
581 | 424 | ||
582 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 425 | if (m_moveActor != null) |
583 | { | 426 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
584 | _velocityMotor.Reset(); | ||
585 | _velocityMotor.SetTarget(targetVel); | ||
586 | _velocityMotor.SetCurrent(_velocity); | ||
587 | _velocityMotor.Enabled = true; | ||
588 | }); | ||
589 | } | 427 | } |
590 | } | 428 | } |
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. | 429 | // Directly setting velocity means this is what the user really wants now. |
597 | public override OMV.Vector3 Velocity { | 430 | public override OMV.Vector3 Velocity { |
598 | get { return _velocity; } | 431 | get { return RawVelocity; } |
599 | set { | 432 | set { |
600 | _velocity = value; | 433 | RawVelocity = value; |
601 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 434 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); |
602 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 435 | PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() |
603 | { | 436 | { |
604 | _velocityMotor.Reset(); | 437 | if (m_moveActor != null) |
605 | _velocityMotor.SetCurrent(_velocity); | 438 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); |
606 | _velocityMotor.SetTarget(_velocity); | ||
607 | _velocityMotor.Enabled = false; | ||
608 | 439 | ||
609 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 440 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); |
610 | ForceVelocity = _velocity; | 441 | ForceVelocity = RawVelocity; |
611 | }); | 442 | }); |
612 | } | 443 | } |
613 | } | 444 | } |
614 | public override OMV.Vector3 ForceVelocity { | 445 | public override OMV.Vector3 ForceVelocity { |
615 | get { return _velocity; } | 446 | get { return RawVelocity; } |
616 | set { | 447 | set { |
617 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 448 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
618 | 449 | ||
619 | _velocity = value; | 450 | RawVelocity = value; |
620 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 451 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
621 | PhysicsScene.PE.Activate(PhysBody, true); | 452 | PhysScene.PE.Activate(PhysBody, true); |
622 | } | 453 | } |
623 | } | 454 | } |
624 | public override OMV.Vector3 Torque { | 455 | public override OMV.Vector3 Torque { |
625 | get { return _torque; } | 456 | get { return RawTorque; } |
626 | set { _torque = value; | 457 | set { RawTorque = value; |
627 | } | 458 | } |
628 | } | 459 | } |
629 | public override float CollisionScore { | 460 | public override float CollisionScore { |
@@ -648,9 +479,19 @@ public sealed class BSCharacter : BSPhysObject | |||
648 | if (_orientation != value) | 479 | if (_orientation != value) |
649 | { | 480 | { |
650 | _orientation = value; | 481 | _orientation = value; |
651 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 482 | PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() |
652 | { | 483 | { |
653 | ForceOrientation = _orientation; | 484 | // Bullet assumes we know what we are doing when forcing orientation |
485 | // so it lets us go against all the rules and just compensates for them later. | ||
486 | // This forces rotation to be only around the Z axis and doesn't change any of the other axis. | ||
487 | // This keeps us from flipping the capsule over which the veiwer does not understand. | ||
488 | float oRoll, oPitch, oYaw; | ||
489 | _orientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); | ||
490 | OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); | ||
491 | // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", | ||
492 | // LocalID, _orientation, OMV.Vector3.UnitX * _orientation, | ||
493 | // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); | ||
494 | ForceOrientation = trimmedOrientation; | ||
654 | }); | 495 | }); |
655 | } | 496 | } |
656 | } | 497 | } |
@@ -660,7 +501,7 @@ public sealed class BSCharacter : BSPhysObject | |||
660 | { | 501 | { |
661 | get | 502 | get |
662 | { | 503 | { |
663 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 504 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
664 | return _orientation; | 505 | return _orientation; |
665 | } | 506 | } |
666 | set | 507 | set |
@@ -669,7 +510,7 @@ public sealed class BSCharacter : BSPhysObject | |||
669 | if (PhysBody.HasPhysicalBody) | 510 | if (PhysBody.HasPhysicalBody) |
670 | { | 511 | { |
671 | // _position = PhysicsScene.PE.GetPosition(BSBody); | 512 | // _position = PhysicsScene.PE.GetPosition(BSBody); |
672 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 513 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
673 | } | 514 | } |
674 | } | 515 | } |
675 | } | 516 | } |
@@ -718,14 +559,14 @@ public sealed class BSCharacter : BSPhysObject | |||
718 | public override bool FloatOnWater { | 559 | public override bool FloatOnWater { |
719 | set { | 560 | set { |
720 | _floatOnWater = value; | 561 | _floatOnWater = value; |
721 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 562 | PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
722 | { | 563 | { |
723 | if (PhysBody.HasPhysicalBody) | 564 | if (PhysBody.HasPhysicalBody) |
724 | { | 565 | { |
725 | if (_floatOnWater) | 566 | if (_floatOnWater) |
726 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 567 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
727 | else | 568 | else |
728 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 569 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
729 | } | 570 | } |
730 | }); | 571 | }); |
731 | } | 572 | } |
@@ -746,7 +587,7 @@ public sealed class BSCharacter : BSPhysObject | |||
746 | public override float Buoyancy { | 587 | public override float Buoyancy { |
747 | get { return _buoyancy; } | 588 | get { return _buoyancy; } |
748 | set { _buoyancy = value; | 589 | set { _buoyancy = value; |
749 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 590 | PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
750 | { | 591 | { |
751 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 592 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
752 | ForceBuoyancy = _buoyancy; | 593 | ForceBuoyancy = _buoyancy; |
@@ -755,8 +596,8 @@ public sealed class BSCharacter : BSPhysObject | |||
755 | } | 596 | } |
756 | public override float ForceBuoyancy { | 597 | public override float ForceBuoyancy { |
757 | get { return _buoyancy; } | 598 | get { return _buoyancy; } |
758 | set { | 599 | set { |
759 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | 600 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); |
760 | 601 | ||
761 | _buoyancy = value; | 602 | _buoyancy = value; |
762 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 603 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
@@ -764,7 +605,7 @@ public sealed class BSCharacter : BSPhysObject | |||
764 | float grav = BSParam.Gravity * (1f - _buoyancy); | 605 | float grav = BSParam.Gravity * (1f - _buoyancy); |
765 | Gravity = new OMV.Vector3(0f, 0f, grav); | 606 | Gravity = new OMV.Vector3(0f, 0f, grav); |
766 | if (PhysBody.HasPhysicalBody) | 607 | if (PhysBody.HasPhysicalBody) |
767 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 608 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
768 | } | 609 | } |
769 | } | 610 | } |
770 | 611 | ||
@@ -779,31 +620,10 @@ public sealed class BSCharacter : BSPhysObject | |||
779 | set { _PIDTau = value; } | 620 | set { _PIDTau = value; } |
780 | } | 621 | } |
781 | 622 | ||
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) | 623 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
804 | { | 624 | { |
805 | // Since this force is being applied in only one step, make this a force per second. | 625 | // Since this force is being applied in only one step, make this a force per second. |
806 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 626 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; |
807 | AddForce(addForce, pushforce, false); | 627 | AddForce(addForce, pushforce, false); |
808 | } | 628 | } |
809 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 629 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
@@ -812,13 +632,13 @@ public sealed class BSCharacter : BSPhysObject | |||
812 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 632 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
813 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | 633 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
814 | 634 | ||
815 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | 635 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() |
816 | { | 636 | { |
817 | // Bullet adds this central force to the total force for this tick | 637 | // Bullet adds this central force to the total force for this tick |
818 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | 638 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
819 | if (PhysBody.HasPhysicalBody) | 639 | if (PhysBody.HasPhysicalBody) |
820 | { | 640 | { |
821 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 641 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
822 | } | 642 | } |
823 | }); | 643 | }); |
824 | } | 644 | } |
@@ -829,7 +649,7 @@ public sealed class BSCharacter : BSPhysObject | |||
829 | } | 649 | } |
830 | } | 650 | } |
831 | 651 | ||
832 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 652 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
833 | } | 653 | } |
834 | public override void SetMomentum(OMV.Vector3 momentum) { | 654 | public override void SetMomentum(OMV.Vector3 momentum) { |
835 | } | 655 | } |
@@ -837,14 +657,14 @@ public sealed class BSCharacter : BSPhysObject | |||
837 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | 657 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
838 | { | 658 | { |
839 | OMV.Vector3 newScale; | 659 | OMV.Vector3 newScale; |
840 | 660 | ||
841 | // Bullet's capsule total height is the "passed height + radius * 2"; | 661 | // 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) | 662 | // 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 | 663 | // The number we pass in for 'scaling' is the multiplier to get that base |
844 | // shape to be the size desired. | 664 | // shape to be the size desired. |
845 | // So, when creating the scale for the avatar height, we take the passed height | 665 | // So, when creating the scale for the avatar height, we take the passed height |
846 | // (size.Z) and remove the caps. | 666 | // (size.Z) and remove the caps. |
847 | // Another oddity of the Bullet capsule implementation is that it presumes the Y | 667 | // 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 | 668 | // 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. | 669 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. |
850 | 670 | ||
@@ -852,8 +672,27 @@ public sealed class BSCharacter : BSPhysObject | |||
852 | newScale.X = size.X / 2f; | 672 | newScale.X = size.X / 2f; |
853 | newScale.Y = size.Y / 2f; | 673 | newScale.Y = size.Y / 2f; |
854 | 674 | ||
675 | float heightAdjust = BSParam.AvatarHeightMidFudge; | ||
676 | if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) | ||
677 | { | ||
678 | // An avatar is between 1.61 and 2.12 meters. Midpoint is 1.87m. | ||
679 | // The "times 4" relies on the fact that the difference from the midpoint to the extremes is exactly 0.25 | ||
680 | float midHeightOffset = size.Z - 1.87f; | ||
681 | if (midHeightOffset < 0f) | ||
682 | { | ||
683 | // Small avatar. Add the adjustment based on the distance from midheight | ||
684 | heightAdjust += -1f * midHeightOffset * 4f * BSParam.AvatarHeightLowFudge; | ||
685 | } | ||
686 | else | ||
687 | { | ||
688 | // Large avatar. Add the adjustment based on the distance from midheight | ||
689 | heightAdjust += midHeightOffset * 4f * BSParam.AvatarHeightHighFudge; | ||
690 | } | ||
691 | } | ||
855 | // The total scale height is the central cylindar plus the caps on the two ends. | 692 | // 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; | 693 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; |
694 | // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); | ||
695 | |||
857 | // If smaller than the endcaps, just fake like we're almost that small | 696 | // If smaller than the endcaps, just fake like we're almost that small |
858 | if (newScale.Z < 0) | 697 | if (newScale.Z < 0) |
859 | newScale.Z = 0.1f; | 698 | newScale.Z = 0.1f; |
@@ -882,15 +721,18 @@ public sealed class BSCharacter : BSPhysObject | |||
882 | // the world that things have changed. | 721 | // the world that things have changed. |
883 | public override void UpdateProperties(EntityProperties entprop) | 722 | public override void UpdateProperties(EntityProperties entprop) |
884 | { | 723 | { |
885 | _position = entprop.Position; | 724 | // Don't change position if standing on a stationary object. |
725 | if (!IsStationary) | ||
726 | _position = entprop.Position; | ||
727 | |||
886 | _orientation = entprop.Rotation; | 728 | _orientation = entprop.Rotation; |
887 | 729 | ||
888 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | 730 | // 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 | 731 | // 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 | 732 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many |
891 | // extra updates. | 733 | // extra updates. |
892 | if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) | 734 | if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) |
893 | _velocity = entprop.Velocity; | 735 | RawVelocity = entprop.Velocity; |
894 | 736 | ||
895 | _acceleration = entprop.Acceleration; | 737 | _acceleration = entprop.Acceleration; |
896 | _rotationalVelocity = entprop.RotationalVelocity; | 738 | _rotationalVelocity = entprop.RotationalVelocity; |
@@ -913,7 +755,7 @@ public sealed class BSCharacter : BSPhysObject | |||
913 | // base.RequestPhysicsterseUpdate(); | 755 | // base.RequestPhysicsterseUpdate(); |
914 | 756 | ||
915 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 757 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
916 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 758 | LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); |
917 | } | 759 | } |
918 | } | 760 | } |
919 | } | 761 | } |
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..311cf4f 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 BSPrim 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; |
@@ -129,11 +130,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
129 | public bool enableAngularDeflection; | 130 | public bool enableAngularDeflection; |
130 | public bool enableAngularBanking; | 131 | public bool enableAngularBanking; |
131 | 132 | ||
132 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 133 | public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) |
134 | : base(myScene, myPrim, actorName) | ||
133 | { | 135 | { |
134 | PhysicsScene = myScene; | 136 | ControllingPrim = myPrim; |
135 | Prim = myPrim; | ||
136 | Type = Vehicle.TYPE_NONE; | 137 | Type = Vehicle.TYPE_NONE; |
138 | m_haveRegisteredForSceneEvents = false; | ||
137 | SetupVehicleDebugging(); | 139 | SetupVehicleDebugging(); |
138 | } | 140 | } |
139 | 141 | ||
@@ -144,7 +146,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
144 | enableAngularVerticalAttraction = true; | 146 | enableAngularVerticalAttraction = true; |
145 | enableAngularDeflection = false; | 147 | enableAngularDeflection = false; |
146 | enableAngularBanking = true; | 148 | enableAngularBanking = true; |
147 | if (BSParam.VehicleDebuggingEnabled) | 149 | if (BSParam.VehicleDebuggingEnable) |
148 | { | 150 | { |
149 | enableAngularVerticalAttraction = true; | 151 | enableAngularVerticalAttraction = true; |
150 | enableAngularDeflection = false; | 152 | enableAngularDeflection = false; |
@@ -155,7 +157,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
155 | // Return 'true' if this vehicle is doing vehicle things | 157 | // Return 'true' if this vehicle is doing vehicle things |
156 | public bool IsActive | 158 | public bool IsActive |
157 | { | 159 | { |
158 | get { return (Type != Vehicle.TYPE_NONE && Prim.IsPhysicallyActive); } | 160 | get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } |
159 | } | 161 | } |
160 | 162 | ||
161 | // Return 'true' if this a vehicle that should be sitting on the ground | 163 | // Return 'true' if this a vehicle that should be sitting on the ground |
@@ -167,7 +169,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | #region Vehicle parameter setting | 169 | #region Vehicle parameter setting |
168 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 170 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
169 | { | 171 | { |
170 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 172 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
171 | switch (pParam) | 173 | switch (pParam) |
172 | { | 174 | { |
173 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 175 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
@@ -195,7 +197,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
195 | break; | 197 | break; |
196 | case Vehicle.BUOYANCY: | 198 | case Vehicle.BUOYANCY: |
197 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | 199 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
198 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 200 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); |
199 | break; | 201 | break; |
200 | case Vehicle.HOVER_EFFICIENCY: | 202 | case Vehicle.HOVER_EFFICIENCY: |
201 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); | 203 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
@@ -233,7 +235,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
233 | // set all of the components to the same value | 235 | // set all of the components to the same value |
234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
235 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 237 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
237 | break; | 238 | break; |
238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
239 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 240 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -242,7 +243,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
242 | break; | 243 | break; |
243 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 244 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
244 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 245 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
245 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
246 | break; | 246 | break; |
247 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 247 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -258,12 +258,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
258 | 258 | ||
259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) |
260 | { | 260 | { |
261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
262 | switch (pParam) | 262 | switch (pParam) |
263 | { | 263 | { |
264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
266 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
267 | break; | 266 | break; |
268 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 267 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
269 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 268 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
@@ -276,7 +275,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
276 | break; | 275 | break; |
277 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 276 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
278 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 277 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
279 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
280 | break; | 278 | break; |
281 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 279 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
282 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 280 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -294,7 +292,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
294 | 292 | ||
295 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 293 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
296 | { | 294 | { |
297 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 295 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
298 | switch (pParam) | 296 | switch (pParam) |
299 | { | 297 | { |
300 | case Vehicle.REFERENCE_FRAME: | 298 | case Vehicle.REFERENCE_FRAME: |
@@ -308,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
308 | 306 | ||
309 | internal void ProcessVehicleFlags(int pParam, bool remove) | 307 | internal void ProcessVehicleFlags(int pParam, bool remove) |
310 | { | 308 | { |
311 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 309 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); |
312 | VehicleFlag parm = (VehicleFlag)pParam; | 310 | VehicleFlag parm = (VehicleFlag)pParam; |
313 | if (pParam == -1) | 311 | if (pParam == -1) |
314 | m_flags = (VehicleFlag)0; | 312 | m_flags = (VehicleFlag)0; |
@@ -323,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
323 | 321 | ||
324 | public void ProcessTypeChange(Vehicle pType) | 322 | public void ProcessTypeChange(Vehicle pType) |
325 | { | 323 | { |
326 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 324 | VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); |
327 | // Set Defaults For Type | 325 | // Set Defaults For Type |
328 | Type = pType; | 326 | Type = pType; |
329 | switch (pType) | 327 | switch (pType) |
@@ -557,34 +555,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
557 | break; | 555 | break; |
558 | } | 556 | } |
559 | 557 | ||
560 | // Update any physical parameters based on this type. | 558 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); |
561 | Refresh(); | 559 | m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
562 | |||
563 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
564 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
565 | 1f); | ||
566 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
567 | 560 | ||
568 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | 561 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); |
569 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | 562 | m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
570 | 1f); | ||
571 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
572 | 563 | ||
573 | /* Not implemented | 564 | /* Not implemented |
574 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | 565 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, |
575 | BSMotor.Infinite, BSMotor.InfiniteVector, | 566 | BSMotor.Infinite, BSMotor.InfiniteVector, |
576 | m_verticalAttractionEfficiency); | 567 | m_verticalAttractionEfficiency); |
577 | // Z goes away and we keep X and Y | 568 | // 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) | 569 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
580 | */ | 570 | */ |
571 | |||
572 | if (this.Type == Vehicle.TYPE_NONE) | ||
573 | { | ||
574 | UnregisterForSceneEvents(); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | RegisterForSceneEvents(); | ||
579 | } | ||
580 | |||
581 | // Update any physical parameters based on this type. | ||
582 | Refresh(); | ||
581 | } | 583 | } |
582 | #endregion // Vehicle parameter setting | 584 | #endregion // Vehicle parameter setting |
583 | 585 | ||
584 | public void Refresh() | 586 | // BSActor.Refresh() |
587 | public override void Refresh() | ||
585 | { | 588 | { |
586 | // If asking for a refresh, reset the physical parameters before the next simulation step. | 589 | // If asking for a refresh, reset the physical parameters before the next simulation step. |
587 | PhysicsScene.PostTaintObject("BSDynamics.Refresh", Prim.LocalID, delegate() | 590 | // Called whether active or not since the active state may be updated before the next step. |
591 | m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate() | ||
588 | { | 592 | { |
589 | SetPhysicalParameters(); | 593 | SetPhysicalParameters(); |
590 | }); | 594 | }); |
@@ -597,49 +601,91 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
597 | if (IsActive) | 601 | if (IsActive) |
598 | { | 602 | { |
599 | // Remember the mass so we don't have to fetch it every step | 603 | // Remember the mass so we don't have to fetch it every step |
600 | m_vehicleMass = Prim.TotalMass; | 604 | m_vehicleMass = ControllingPrim.TotalMass; |
601 | 605 | ||
602 | // Friction affects are handled by this vehicle code | 606 | // Friction affects are handled by this vehicle code |
603 | PhysicsScene.PE.SetFriction(Prim.PhysBody, BSParam.VehicleFriction); | 607 | m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); |
604 | PhysicsScene.PE.SetRestitution(Prim.PhysBody, BSParam.VehicleRestitution); | 608 | m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); |
605 | 609 | ||
606 | // Moderate angular movement introduced by Bullet. | 610 | // Moderate angular movement introduced by Bullet. |
607 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | 611 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. |
608 | // Maybe compute linear and angular factor and damping from params. | 612 | // Maybe compute linear and angular factor and damping from params. |
609 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, BSParam.VehicleAngularDamping); | 613 | m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); |
610 | PhysicsScene.PE.SetLinearFactor(Prim.PhysBody, BSParam.VehicleLinearFactor); | 614 | m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); |
611 | PhysicsScene.PE.SetAngularFactorV(Prim.PhysBody, BSParam.VehicleAngularFactor); | 615 | m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); |
612 | 616 | ||
613 | // Vehicles report collision events so we know when it's on the ground | 617 | // Vehicles report collision events so we know when it's on the ground |
614 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 618 | m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
615 | 619 | ||
616 | Prim.Inertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | 620 | Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); |
617 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, Prim.Inertia); | 621 | ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; |
618 | PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); | 622 | m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); |
623 | m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); | ||
619 | 624 | ||
620 | // Set the gravity for the vehicle depending on the buoyancy | 625 | // Set the gravity for the vehicle depending on the buoyancy |
621 | // TODO: what should be done if prim and vehicle buoyancy differ? | 626 | // TODO: what should be done if prim and vehicle buoyancy differ? |
622 | m_VehicleGravity = Prim.ComputeGravity(m_VehicleBuoyancy); | 627 | 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. | 628 | // 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); | 629 | m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); |
625 | 630 | ||
626 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", | 631 | 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, | 632 | ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, |
628 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | 633 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, |
629 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | 634 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor |
630 | ); | 635 | ); |
631 | } | 636 | } |
632 | else | 637 | else |
633 | { | 638 | { |
634 | if (Prim.PhysBody.HasPhysicalBody) | 639 | if (ControllingPrim.PhysBody.HasPhysicalBody) |
635 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 640 | m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
636 | } | 641 | } |
637 | } | 642 | } |
638 | 643 | ||
639 | public bool RemoveBodyDependencies(BSPhysObject prim) | 644 | // BSActor.RemoveBodyDependencies |
645 | public override void RemoveDependencies() | ||
640 | { | 646 | { |
641 | Refresh(); | 647 | Refresh(); |
642 | return IsActive; | 648 | } |
649 | |||
650 | // BSActor.Release() | ||
651 | public override void Dispose() | ||
652 | { | ||
653 | UnregisterForSceneEvents(); | ||
654 | Type = Vehicle.TYPE_NONE; | ||
655 | Enabled = false; | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | private void RegisterForSceneEvents() | ||
660 | { | ||
661 | if (!m_haveRegisteredForSceneEvents) | ||
662 | { | ||
663 | m_physicsScene.BeforeStep += this.Step; | ||
664 | m_physicsScene.AfterStep += this.PostStep; | ||
665 | ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; | ||
666 | m_haveRegisteredForSceneEvents = true; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | private void UnregisterForSceneEvents() | ||
671 | { | ||
672 | if (m_haveRegisteredForSceneEvents) | ||
673 | { | ||
674 | m_physicsScene.BeforeStep -= this.Step; | ||
675 | m_physicsScene.AfterStep -= this.PostStep; | ||
676 | ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; | ||
677 | m_haveRegisteredForSceneEvents = false; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | private void PreUpdateProperty(ref EntityProperties entprop) | ||
682 | { | ||
683 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
684 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
685 | if (IsActive) | ||
686 | { | ||
687 | entprop.RotationalVelocity = Vector3.Zero; | ||
688 | } | ||
643 | } | 689 | } |
644 | 690 | ||
645 | #region Known vehicle value functions | 691 | #region Known vehicle value functions |
@@ -686,14 +732,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
686 | if (m_knownChanged != 0) | 732 | if (m_knownChanged != 0) |
687 | { | 733 | { |
688 | if ((m_knownChanged & m_knownChangedPosition) != 0) | 734 | if ((m_knownChanged & m_knownChangedPosition) != 0) |
689 | Prim.ForcePosition = m_knownPosition; | 735 | ControllingPrim.ForcePosition = m_knownPosition; |
690 | 736 | ||
691 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | 737 | if ((m_knownChanged & m_knownChangedOrientation) != 0) |
692 | Prim.ForceOrientation = m_knownOrientation; | 738 | ControllingPrim.ForceOrientation = m_knownOrientation; |
693 | 739 | ||
694 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | 740 | if ((m_knownChanged & m_knownChangedVelocity) != 0) |
695 | { | 741 | { |
696 | Prim.ForceVelocity = m_knownVelocity; | 742 | ControllingPrim.ForceVelocity = m_knownVelocity; |
697 | // Fake out Bullet by making it think the velocity is the same as last time. | 743 | // 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. | 744 | // Bullet does a bunch of smoothing for changing parameters. |
699 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | 745 | // Since the vehicle is demanding this setting, we override Bullet's smoothing |
@@ -702,28 +748,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
702 | } | 748 | } |
703 | 749 | ||
704 | if ((m_knownChanged & m_knownChangedForce) != 0) | 750 | if ((m_knownChanged & m_knownChangedForce) != 0) |
705 | Prim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); | 751 | ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); |
706 | 752 | ||
707 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | 753 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) |
708 | Prim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | 754 | ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); |
709 | 755 | ||
710 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | 756 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) |
711 | { | 757 | { |
712 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | 758 | ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; |
713 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | 759 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); |
714 | } | 760 | } |
715 | 761 | ||
716 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | 762 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) |
717 | Prim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | 763 | ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); |
718 | 764 | ||
719 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | 765 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) |
720 | { | 766 | { |
721 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | 767 | ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); |
722 | } | 768 | } |
723 | 769 | ||
724 | // If we set one of the values (ie, the physics engine didn't do it) we must force | 770 | // 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. | 771 | // an UpdateProperties event to send the changes up to the simulator. |
726 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | 772 | m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); |
727 | } | 773 | } |
728 | m_knownChanged = 0; | 774 | m_knownChanged = 0; |
729 | } | 775 | } |
@@ -736,7 +782,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
736 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) | 782 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) |
737 | { | 783 | { |
738 | lastRememberedHeightPos = pos; | 784 | lastRememberedHeightPos = pos; |
739 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 785 | m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); |
740 | m_knownHas |= m_knownChangedTerrainHeight; | 786 | m_knownHas |= m_knownChangedTerrainHeight; |
741 | } | 787 | } |
742 | return m_knownTerrainHeight; | 788 | return m_knownTerrainHeight; |
@@ -748,7 +794,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
748 | { | 794 | { |
749 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | 795 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) |
750 | { | 796 | { |
751 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | 797 | m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); |
752 | m_knownHas |= m_knownChangedWaterLevel; | 798 | m_knownHas |= m_knownChangedWaterLevel; |
753 | } | 799 | } |
754 | return (float)m_knownWaterLevel; | 800 | return (float)m_knownWaterLevel; |
@@ -760,7 +806,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
760 | { | 806 | { |
761 | if ((m_knownHas & m_knownChangedPosition) == 0) | 807 | if ((m_knownHas & m_knownChangedPosition) == 0) |
762 | { | 808 | { |
763 | m_knownPosition = Prim.ForcePosition; | 809 | m_knownPosition = ControllingPrim.ForcePosition; |
764 | m_knownHas |= m_knownChangedPosition; | 810 | m_knownHas |= m_knownChangedPosition; |
765 | } | 811 | } |
766 | return m_knownPosition; | 812 | return m_knownPosition; |
@@ -779,7 +825,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
779 | { | 825 | { |
780 | if ((m_knownHas & m_knownChangedOrientation) == 0) | 826 | if ((m_knownHas & m_knownChangedOrientation) == 0) |
781 | { | 827 | { |
782 | m_knownOrientation = Prim.ForceOrientation; | 828 | m_knownOrientation = ControllingPrim.ForceOrientation; |
783 | m_knownHas |= m_knownChangedOrientation; | 829 | m_knownHas |= m_knownChangedOrientation; |
784 | } | 830 | } |
785 | return m_knownOrientation; | 831 | return m_knownOrientation; |
@@ -798,7 +844,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
798 | { | 844 | { |
799 | if ((m_knownHas & m_knownChangedVelocity) == 0) | 845 | if ((m_knownHas & m_knownChangedVelocity) == 0) |
800 | { | 846 | { |
801 | m_knownVelocity = Prim.ForceVelocity; | 847 | m_knownVelocity = ControllingPrim.ForceVelocity; |
802 | m_knownHas |= m_knownChangedVelocity; | 848 | m_knownHas |= m_knownChangedVelocity; |
803 | } | 849 | } |
804 | return m_knownVelocity; | 850 | return m_knownVelocity; |
@@ -839,7 +885,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
839 | { | 885 | { |
840 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | 886 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) |
841 | { | 887 | { |
842 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | 888 | m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; |
843 | m_knownHas |= m_knownChangedRotationalVelocity; | 889 | m_knownHas |= m_knownChangedRotationalVelocity; |
844 | } | 890 | } |
845 | return (Vector3)m_knownRotationalVelocity; | 891 | return (Vector3)m_knownRotationalVelocity; |
@@ -914,11 +960,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
914 | // for the physics engine to note the changes so an UpdateProperties event will happen. | 960 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
915 | PushKnownChanged(); | 961 | PushKnownChanged(); |
916 | 962 | ||
917 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 963 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
918 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 964 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
919 | 965 | ||
920 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", | 966 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", |
921 | Prim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); | 967 | ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); |
922 | } | 968 | } |
923 | 969 | ||
924 | // Called after the simulation step | 970 | // Called after the simulation step |
@@ -926,8 +972,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
926 | { | 972 | { |
927 | if (!IsActive) return; | 973 | if (!IsActive) return; |
928 | 974 | ||
929 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 975 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
930 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 976 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
931 | } | 977 | } |
932 | 978 | ||
933 | // Apply the effect of the linear motor and other linear motions (like hover and float). | 979 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
@@ -966,13 +1012,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
966 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG | 1012 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG |
967 | VehicleVelocity /= VehicleVelocity.Length(); | 1013 | VehicleVelocity /= VehicleVelocity.Length(); |
968 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | 1014 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; |
969 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", | 1015 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", |
970 | Prim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | 1016 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); |
971 | } | 1017 | } |
972 | else if (newVelocityLengthSq < 0.001f) | 1018 | else if (newVelocityLengthSq < 0.001f) |
973 | VehicleVelocity = Vector3.Zero; | 1019 | VehicleVelocity = Vector3.Zero; |
974 | 1020 | ||
975 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", Prim.LocalID, Prim.IsColliding, VehicleVelocity ); | 1021 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); |
976 | 1022 | ||
977 | } // end MoveLinear() | 1023 | } // end MoveLinear() |
978 | 1024 | ||
@@ -983,6 +1029,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
983 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); | 1029 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); |
984 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); | 1030 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); |
985 | 1031 | ||
1032 | // Friction reduces vehicle motion | ||
1033 | Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); | ||
1034 | linearMotorCorrectionV -= (currentVelV * frictionFactorW); | ||
1035 | |||
986 | // Motor is vehicle coordinates. Rotate it to world coordinates | 1036 | // Motor is vehicle coordinates. Rotate it to world coordinates |
987 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; | 1037 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; |
988 | 1038 | ||
@@ -996,8 +1046,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
996 | // Add this correction to the velocity to make it faster/slower. | 1046 | // Add this correction to the velocity to make it faster/slower. |
997 | VehicleVelocity += linearMotorVelocityW; | 1047 | VehicleVelocity += linearMotorVelocityW; |
998 | 1048 | ||
999 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5}", | 1049 | |
1000 | Prim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, linearMotorVelocityW, VehicleVelocity); | 1050 | |
1051 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", | ||
1052 | ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, | ||
1053 | linearMotorVelocityW, VehicleVelocity, frictionFactorW); | ||
1001 | } | 1054 | } |
1002 | 1055 | ||
1003 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | 1056 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) |
@@ -1011,7 +1064,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1011 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | 1064 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
1012 | VehiclePosition = newPosition; | 1065 | VehiclePosition = newPosition; |
1013 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | 1066 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", |
1014 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | 1067 | ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
1015 | } | 1068 | } |
1016 | } | 1069 | } |
1017 | 1070 | ||
@@ -1041,7 +1094,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1041 | if (VehiclePosition.Z > m_VhoverTargetHeight) | 1094 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
1042 | m_VhoverTargetHeight = VehiclePosition.Z; | 1095 | m_VhoverTargetHeight = VehiclePosition.Z; |
1043 | } | 1096 | } |
1044 | 1097 | ||
1045 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 1098 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
1046 | { | 1099 | { |
1047 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | 1100 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
@@ -1050,7 +1103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1050 | pos.Z = m_VhoverTargetHeight; | 1103 | pos.Z = m_VhoverTargetHeight; |
1051 | VehiclePosition = pos; | 1104 | VehiclePosition = pos; |
1052 | 1105 | ||
1053 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", Prim.LocalID, pos); | 1106 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); |
1054 | } | 1107 | } |
1055 | } | 1108 | } |
1056 | else | 1109 | else |
@@ -1079,7 +1132,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1079 | */ | 1132 | */ |
1080 | 1133 | ||
1081 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", | 1134 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", |
1082 | Prim.LocalID, VehiclePosition, m_VhoverEfficiency, | 1135 | ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, |
1083 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | 1136 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, |
1084 | verticalError, verticalCorrection); | 1137 | verticalError, verticalCorrection); |
1085 | } | 1138 | } |
@@ -1124,7 +1177,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1124 | { | 1177 | { |
1125 | VehiclePosition = pos; | 1178 | VehiclePosition = pos; |
1126 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1179 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
1127 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1180 | ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); |
1128 | } | 1181 | } |
1129 | } | 1182 | } |
1130 | return changed; | 1183 | return changed; |
@@ -1135,7 +1188,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1135 | // used with conjunction with banking: the strength of the banking will decay when the | 1188 | // 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 | 1189 | // 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 | 1190 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering |
1138 | // when they are in mid jump. | 1191 | // when they are in mid jump. |
1139 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | 1192 | // 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 | 1193 | // This is just using the ground and a general collision check. Should really be using |
1141 | // a downward raycast to find what is below. | 1194 | // a downward raycast to find what is below. |
@@ -1164,7 +1217,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1164 | 1217 | ||
1165 | // Another approach is to measure if we're going up. If going up and not colliding, | 1218 | // 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. | 1219 | // the vehicle is in the air. Fix that by pushing down. |
1167 | if (!Prim.IsColliding && VehicleVelocity.Z > 0.1) | 1220 | if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) |
1168 | { | 1221 | { |
1169 | // Get rid of any of the velocity vector that is pushing us up. | 1222 | // Get rid of any of the velocity vector that is pushing us up. |
1170 | float upVelocity = VehicleVelocity.Z; | 1223 | float upVelocity = VehicleVelocity.Z; |
@@ -1186,7 +1239,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1186 | } | 1239 | } |
1187 | */ | 1240 | */ |
1188 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | 1241 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", |
1189 | Prim.LocalID, Prim.IsColliding, upVelocity, VehicleVelocity); | 1242 | ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); |
1190 | } | 1243 | } |
1191 | } | 1244 | } |
1192 | } | 1245 | } |
@@ -1196,14 +1249,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1196 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; | 1249 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; |
1197 | 1250 | ||
1198 | // Hack to reduce downward force if the vehicle is probably sitting on the ground | 1251 | // Hack to reduce downward force if the vehicle is probably sitting on the ground |
1199 | if (Prim.IsColliding && IsGroundVehicle) | 1252 | if (ControllingPrim.IsColliding && IsGroundVehicle) |
1200 | appliedGravity *= BSParam.VehicleGroundGravityFudge; | 1253 | appliedGravity *= BSParam.VehicleGroundGravityFudge; |
1201 | 1254 | ||
1202 | VehicleAddForce(appliedGravity); | 1255 | VehicleAddForce(appliedGravity); |
1203 | 1256 | ||
1204 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", | 1257 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", |
1205 | Prim.LocalID, m_VehicleGravity, | 1258 | ControllingPrim.LocalID, m_VehicleGravity, |
1206 | Prim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | 1259 | ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); |
1207 | } | 1260 | } |
1208 | 1261 | ||
1209 | // ======================================================================= | 1262 | // ======================================================================= |
@@ -1227,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1227 | { | 1280 | { |
1228 | // The vehicle is not adding anything angular wise. | 1281 | // The vehicle is not adding anything angular wise. |
1229 | VehicleRotationalVelocity = Vector3.Zero; | 1282 | VehicleRotationalVelocity = Vector3.Zero; |
1230 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | 1283 | VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); |
1231 | } | 1284 | } |
1232 | else | 1285 | else |
1233 | { | 1286 | { |
1234 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", Prim.LocalID, VehicleRotationalVelocity); | 1287 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); |
1235 | } | 1288 | } |
1236 | 1289 | ||
1237 | // ================================================================== | 1290 | // ================================================================== |
@@ -1262,7 +1315,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1262 | torqueFromOffset.Z = 0; | 1315 | torqueFromOffset.Z = 0; |
1263 | 1316 | ||
1264 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | 1317 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1265 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1318 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); |
1266 | } | 1319 | } |
1267 | 1320 | ||
1268 | } | 1321 | } |
@@ -1277,7 +1330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1277 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | 1330 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
1278 | // This flag prevents linear deflection parallel to world z-axis. This is useful | 1331 | // 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, | 1332 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
1280 | // from climbing their linear deflection into the sky. | 1333 | // 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 | 1334 | // 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 | 1335 | // 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? | 1336 | // is a linear effect. Where should this check go? |
@@ -1287,8 +1340,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1287 | // angularMotorContributionV.Y = 0f; | 1340 | // angularMotorContributionV.Y = 0f; |
1288 | // } | 1341 | // } |
1289 | 1342 | ||
1343 | // Reduce any velocity by friction. | ||
1344 | Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); | ||
1345 | angularMotorContributionV -= (currentAngularV * frictionFactorW); | ||
1346 | |||
1290 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; | 1347 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; |
1291 | VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV); | 1348 | |
1349 | |||
1350 | |||
1351 | VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); | ||
1292 | } | 1352 | } |
1293 | 1353 | ||
1294 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | 1354 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
@@ -1305,6 +1365,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1305 | // If vertical attaction timescale is reasonable | 1365 | // If vertical attaction timescale is reasonable |
1306 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1366 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1307 | { | 1367 | { |
1368 | //Another formula to try got from : | ||
1369 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1370 | |||
1371 | Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; | ||
1372 | |||
1373 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1374 | // since only computing half the distance between the angles. | ||
1375 | float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1376 | |||
1377 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1378 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1379 | Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1380 | |||
1381 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1382 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1383 | |||
1384 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1385 | Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; | ||
1386 | |||
1387 | VehicleRotationalVelocity += vertContributionV; | ||
1388 | |||
1389 | VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", | ||
1390 | ControllingPrim.LocalID, | ||
1391 | VehicleUpAxis, | ||
1392 | predictedUp, | ||
1393 | torqueVector, | ||
1394 | vertContributionV); | ||
1395 | //===================================================================== | ||
1396 | /* | ||
1308 | // Possible solution derived from a discussion at: | 1397 | // Possible solution derived from a discussion at: |
1309 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | 1398 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no |
1310 | 1399 | ||
@@ -1334,11 +1423,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1334 | VehicleRotationalVelocity += vertContributionV; | 1423 | VehicleRotationalVelocity += vertContributionV; |
1335 | 1424 | ||
1336 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", | 1425 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", |
1337 | Prim.LocalID, | 1426 | ControllingPrim.LocalID, |
1338 | differenceAxis, | 1427 | differenceAxis, |
1339 | differenceAngle, | 1428 | differenceAngle, |
1340 | correctionRotation, | 1429 | correctionRotation, |
1341 | vertContributionV); | 1430 | vertContributionV); |
1431 | */ | ||
1342 | 1432 | ||
1343 | // =================================================================== | 1433 | // =================================================================== |
1344 | /* | 1434 | /* |
@@ -1380,7 +1470,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1380 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); | 1470 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); |
1381 | 1471 | ||
1382 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", | 1472 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", |
1383 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, | 1473 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, |
1384 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); | 1474 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); |
1385 | */ | 1475 | */ |
1386 | } | 1476 | } |
@@ -1433,9 +1523,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1433 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | 1523 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; |
1434 | 1524 | ||
1435 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | 1525 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", |
1436 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); | 1526 | ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); |
1437 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | 1527 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", |
1438 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | 1528 | ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); |
1439 | } | 1529 | } |
1440 | } | 1530 | } |
1441 | 1531 | ||
@@ -1447,13 +1537,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1447 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | 1537 | // 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 | 1538 | // of the yaw effect will be proportional to the |
1449 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | 1539 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's |
1450 | // velocity along its preferred axis of motion. | 1540 | // velocity along its preferred axis of motion. |
1451 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | 1541 | // 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 | 1542 | // 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 | 1543 | // (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. | 1544 | // 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 | 1545 | // 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?). | 1546 | // 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 | 1547 | // 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. | 1548 | // 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 | 1549 | // For example, consider a real motorcycle...it must be moving forward in order for |
@@ -1465,11 +1555,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1465 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | 1555 | // 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 | 1556 | // 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 | 1557 | // 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. | 1558 | // 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 | 1559 | // 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 | 1560 | // 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 | 1561 | // 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. | 1562 | // make a sluggish vehicle by giving it a timescale of several seconds. |
1473 | public void ComputeAngularBanking() | 1563 | public void ComputeAngularBanking() |
1474 | { | 1564 | { |
1475 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1565 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
@@ -1498,10 +1588,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1498 | 1588 | ||
1499 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; | 1589 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; |
1500 | VehicleRotationalVelocity += bankingContributionV; | 1590 | VehicleRotationalVelocity += bankingContributionV; |
1501 | 1591 | ||
1502 | 1592 | ||
1503 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", | 1593 | 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); | 1594 | ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); |
1505 | } | 1595 | } |
1506 | } | 1596 | } |
1507 | 1597 | ||
@@ -1540,11 +1630,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1540 | if (rotq != m_rot) | 1630 | if (rotq != m_rot) |
1541 | { | 1631 | { |
1542 | VehicleOrientation = m_rot; | 1632 | VehicleOrientation = m_rot; |
1543 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1633 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); |
1544 | } | 1634 | } |
1545 | 1635 | ||
1546 | } | 1636 | } |
1547 | 1637 | ||
1638 | // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce | ||
1639 | // some value by to apply this friction. | ||
1640 | private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) | ||
1641 | { | ||
1642 | Vector3 frictionFactor = Vector3.Zero; | ||
1643 | if (friction != BSMotor.InfiniteVector) | ||
1644 | { | ||
1645 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
1646 | // Individual friction components can be 'infinite' so compute each separately. | ||
1647 | frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); | ||
1648 | frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); | ||
1649 | frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); | ||
1650 | frictionFactor *= pTimestep; | ||
1651 | } | ||
1652 | return frictionFactor; | ||
1653 | } | ||
1654 | |||
1548 | private float ClampInRange(float low, float val, float high) | 1655 | private float ClampInRange(float low, float val, float high) |
1549 | { | 1656 | { |
1550 | return Math.Max(low, Math.Min(val, high)); | 1657 | return Math.Max(low, Math.Min(val, high)); |
@@ -1554,8 +1661,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1554 | // Invoke the detailed logger and output something if it's enabled. | 1661 | // Invoke the detailed logger and output something if it's enabled. |
1555 | private void VDetailLog(string msg, params Object[] args) | 1662 | private void VDetailLog(string msg, params Object[] args) |
1556 | { | 1663 | { |
1557 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 1664 | if (ControllingPrim.PhysScene.VehicleLoggingEnabled) |
1558 | Prim.PhysicsScene.DetailLog(msg, args); | 1665 | ControllingPrim.PhysScene.DetailLog(msg, args); |
1559 | } | 1666 | } |
1560 | } | 1667 | } |
1561 | } | 1668 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4ece1eb..76c2187 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -80,7 +80,7 @@ public abstract class BSLinkset | |||
80 | 80 | ||
81 | public BSPrimLinkable LinksetRoot { get; protected set; } | 81 | public BSPrimLinkable LinksetRoot { get; protected set; } |
82 | 82 | ||
83 | public BSScene PhysicsScene { get; private set; } | 83 | protected BSScene m_physicsScene { get; private set; } |
84 | 84 | ||
85 | static int m_nextLinksetID = 1; | 85 | static int m_nextLinksetID = 1; |
86 | public int LinksetID { get; private set; } | 86 | public int LinksetID { get; private set; } |
@@ -93,13 +93,6 @@ public abstract class BSLinkset | |||
93 | // to the physical representation is done via the tainting mechenism. | 93 | // to the physical representation is done via the tainting mechenism. |
94 | protected object m_linksetActivityLock = new Object(); | 94 | protected object m_linksetActivityLock = new Object(); |
95 | 95 | ||
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 | 96 | // 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; } | 97 | public float LinksetMass { get; protected set; } |
105 | 98 | ||
@@ -122,7 +115,7 @@ public abstract class BSLinkset | |||
122 | // We create LOTS of linksets. | 115 | // We create LOTS of linksets. |
123 | if (m_nextLinksetID <= 0) | 116 | if (m_nextLinksetID <= 0) |
124 | m_nextLinksetID = 1; | 117 | m_nextLinksetID = 1; |
125 | PhysicsScene = scene; | 118 | m_physicsScene = scene; |
126 | LinksetRoot = parent; | 119 | LinksetRoot = parent; |
127 | m_children = new HashSet<BSPrimLinkable>(); | 120 | m_children = new HashSet<BSPrimLinkable>(); |
128 | LinksetMass = parent.RawMass; | 121 | LinksetMass = parent.RawMass; |
@@ -165,7 +158,7 @@ public abstract class BSLinkset | |||
165 | } | 158 | } |
166 | 159 | ||
167 | // The child is down to a linkset of just itself | 160 | // The child is down to a linkset of just itself |
168 | return BSLinkset.Factory(PhysicsScene, child); | 161 | return BSLinkset.Factory(m_physicsScene, child); |
169 | } | 162 | } |
170 | 163 | ||
171 | // Return 'true' if the passed object is the root object of this linkset | 164 | // Return 'true' if the passed object is the root object of this linkset |
@@ -221,7 +214,7 @@ public abstract class BSLinkset | |||
221 | // I am the root of a linkset and a new child is being added | 214 | // I am the root of a linkset and a new child is being added |
222 | // Called while LinkActivity is locked. | 215 | // Called while LinkActivity is locked. |
223 | protected abstract void AddChildToLinkset(BSPrimLinkable child); | 216 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
224 | 217 | ||
225 | // I am the root of a linkset and one of my children is being removed. | 218 | // 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. | 219 | // Safe to call even if the child is not really in my linkset. |
227 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); | 220 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); |
@@ -263,7 +256,7 @@ public abstract class BSLinkset | |||
263 | // This is called when the root body is changing. | 256 | // This is called when the root body is changing. |
264 | // Returns 'true' of something was actually removed and would need restoring | 257 | // Returns 'true' of something was actually removed and would need restoring |
265 | // Called at taint-time!! | 258 | // Called at taint-time!! |
266 | public abstract bool RemoveBodyDependencies(BSPrimLinkable child); | 259 | public abstract bool RemoveDependencies(BSPrimLinkable child); |
267 | 260 | ||
268 | // ================================================================ | 261 | // ================================================================ |
269 | protected virtual float ComputeLinksetMass() | 262 | protected virtual float ComputeLinksetMass() |
@@ -323,8 +316,8 @@ public abstract class BSLinkset | |||
323 | // Invoke the detailed logger and output something if it's enabled. | 316 | // Invoke the detailed logger and output something if it's enabled. |
324 | protected void DetailLog(string msg, params Object[] args) | 317 | protected void DetailLog(string msg, params Object[] args) |
325 | { | 318 | { |
326 | if (PhysicsScene.PhysicsLogging.Enabled) | 319 | if (m_physicsScene.PhysicsLogging.Enabled) |
327 | PhysicsScene.DetailLog(msg, args); | 320 | m_physicsScene.DetailLog(msg, args); |
328 | } | 321 | } |
329 | 322 | ||
330 | } | 323 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e05562a..350a5d1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,6 +35,7 @@ using OMV = OpenMetaverse; | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | 37 | ||
38 | /* | ||
38 | // When a child is linked, the relationship position of the child to the parent | 39 | // When a child is linked, the relationship position of the child to the parent |
39 | // is remembered so the child's world position can be recomputed when it is | 40 | // is remembered so the child's world position can be recomputed when it is |
40 | // removed from the linkset. | 41 | // removed from the linkset. |
@@ -88,6 +89,7 @@ sealed class BSLinksetCompoundInfo : BSLinksetInfo | |||
88 | return buff.ToString(); | 89 | return buff.ToString(); |
89 | } | 90 | } |
90 | }; | 91 | }; |
92 | */ | ||
91 | 93 | ||
92 | public sealed class BSLinksetCompound : BSLinkset | 94 | public sealed class BSLinksetCompound : BSLinkset |
93 | { | 95 | { |
@@ -98,19 +100,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
98 | { | 100 | { |
99 | } | 101 | } |
100 | 102 | ||
101 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
102 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) | ||
103 | { | ||
104 | // Returning 'unknown' means we don't have a preference. | ||
105 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
106 | if (IsRoot(requestor) && HasAnyChildren) | ||
107 | { | ||
108 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
109 | } | ||
110 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | // When physical properties are changed the linkset needs to recalculate | 103 | // When physical properties are changed the linkset needs to recalculate |
115 | // its internal properties. | 104 | // its internal properties. |
116 | public override void Refresh(BSPrimLinkable requestor) | 105 | public override void Refresh(BSPrimLinkable requestor) |
@@ -124,14 +113,14 @@ public sealed class BSLinksetCompound : BSLinkset | |||
124 | // Schedule a refresh to happen after all the other taint processing. | 113 | // Schedule a refresh to happen after all the other taint processing. |
125 | private void ScheduleRebuild(BSPrimLinkable requestor) | 114 | private void ScheduleRebuild(BSPrimLinkable requestor) |
126 | { | 115 | { |
127 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | 116 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
128 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | 117 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
129 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | 118 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
130 | // If already rebuilding, don't request another rebuild. | 119 | // 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. | 120 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. |
132 | if (!Rebuilding && HasAnyChildren) | 121 | if (!Rebuilding && HasAnyChildren) |
133 | { | 122 | { |
134 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 123 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
135 | { | 124 | { |
136 | if (HasAnyChildren) | 125 | if (HasAnyChildren) |
137 | RecomputeLinksetCompound(); | 126 | RecomputeLinksetCompound(); |
@@ -153,26 +142,11 @@ public sealed class BSLinksetCompound : BSLinkset | |||
153 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 142 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
154 | ScheduleRebuild(LinksetRoot); | 143 | ScheduleRebuild(LinksetRoot); |
155 | } | 144 | } |
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; | 145 | return ret; |
170 | } | 146 | } |
171 | 147 | ||
172 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 148 | // 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. | 149 | // 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! | 150 | // Called at taint-time! |
177 | public override bool MakeStatic(BSPrimLinkable child) | 151 | public override bool MakeStatic(BSPrimLinkable child) |
178 | { | 152 | { |
@@ -180,19 +154,9 @@ public sealed class BSLinksetCompound : BSLinkset | |||
180 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
181 | if (IsRoot(child)) | 155 | if (IsRoot(child)) |
182 | { | 156 | { |
157 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
183 | ScheduleRebuild(LinksetRoot); | 158 | ScheduleRebuild(LinksetRoot); |
184 | } | 159 | } |
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; | 160 | return ret; |
197 | } | 161 | } |
198 | 162 | ||
@@ -200,13 +164,20 @@ public sealed class BSLinksetCompound : BSLinkset | |||
200 | // Called at taint-time. | 164 | // Called at taint-time. |
201 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | 165 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) |
202 | { | 166 | { |
167 | if (!LinksetRoot.IsPhysicallyActive) | ||
168 | { | ||
169 | // No reason to do this physical stuff for static linksets. | ||
170 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
171 | return; | ||
172 | } | ||
173 | |||
203 | // The user moving a child around requires the rebuilding of the linkset compound shape | 174 | // 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 | 175 | // 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 | 176 | // stores the position into the group which causes the move of the object |
206 | // but it also means all the child positions get updated. | 177 | // 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 | 178 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
208 | // region before bothering to do a rebuild. | 179 | // region before bothering to do a rebuild. |
209 | if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | 180 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
210 | { | 181 | { |
211 | // If a child of the linkset is updating only the position or rotation, that can be done | 182 | // If a child of the linkset is updating only the position or rotation, that can be done |
212 | // without rebuilding the linkset. | 183 | // without rebuilding the linkset. |
@@ -218,22 +189,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
218 | // and that is caused by us updating the object. | 189 | // and that is caused by us updating the object. |
219 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | 190 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) |
220 | { | 191 | { |
221 | // Find the physical instance of the child | 192 | // Find the physical instance of the child |
222 | if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) | 193 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) |
223 | { | 194 | { |
224 | // It is possible that the linkset is still under construction and the child is not yet | 195 | // 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 | 196 | // 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. | 197 | // 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 | 198 | // The index must be checked because Bullet references the child array but does no validity |
228 | // checking of the child index passed. | 199 | // checking of the child index passed. |
229 | int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); | 200 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); |
230 | if (updated.LinksetChildIndex < numLinksetChildren) | 201 | if (updated.LinksetChildIndex < numLinksetChildren) |
231 | { | 202 | { |
232 | BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); | 203 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); |
233 | if (linksetChildShape.HasPhysicalShape) | 204 | if (linksetChildShape.HasPhysicalShape) |
234 | { | 205 | { |
235 | // Found the child shape within the compound shape | 206 | // Found the child shape within the compound shape |
236 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, | 207 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, |
237 | updated.RawPosition - LinksetRoot.RawPosition, | 208 | updated.RawPosition - LinksetRoot.RawPosition, |
238 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | 209 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), |
239 | true /* shouldRecalculateLocalAabb */); | 210 | true /* shouldRecalculateLocalAabb */); |
@@ -275,75 +246,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
275 | } | 246 | } |
276 | 247 | ||
277 | // Routine called when rebuilding the body of some member of the linkset. | 248 | // 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. | 249 | // If one of the bodies is being changed, the linkset needs rebuilding. |
250 | // 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 | 251 | // Returns 'true' of something was actually removed and would need restoring |
280 | // Called at taint-time!! | 252 | // Called at taint-time!! |
281 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 253 | public override bool RemoveDependencies(BSPrimLinkable child) |
282 | { | 254 | { |
283 | bool ret = false; | 255 | bool ret = false; |
284 | 256 | ||
285 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 257 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
286 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | 258 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
287 | 259 | ||
288 | if (!IsRoot(child)) | 260 | 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 | 261 | ||
300 | return ret; | 262 | return ret; |
301 | } | 263 | } |
302 | 264 | ||
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 | // ================================================================ | 265 | // ================================================================ |
348 | 266 | ||
349 | // Add a new child to the linkset. | 267 | // Add a new child to the linkset. |
@@ -376,7 +294,6 @@ public sealed class BSLinksetCompound : BSLinkset | |||
376 | child.LocalID, child.PhysBody.AddrString); | 294 | child.LocalID, child.PhysBody.AddrString); |
377 | 295 | ||
378 | // Cause the child's body to be rebuilt and thus restored to normal operation | 296 | // Cause the child's body to be rebuilt and thus restored to normal operation |
379 | RecomputeChildWorldPosition(child, false); | ||
380 | child.LinksetInfo = null; | 297 | child.LinksetInfo = null; |
381 | child.ForceBodyShapeRebuild(false); | 298 | child.ForceBodyShapeRebuild(false); |
382 | 299 | ||
@@ -399,108 +316,105 @@ public sealed class BSLinksetCompound : BSLinkset | |||
399 | // Constraint linksets are rebuilt every time. | 316 | // Constraint linksets are rebuilt every time. |
400 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 317 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
401 | // Called at taint time!! | 318 | // Called at taint time!! |
402 | private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged | 319 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape |
320 | private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting | ||
403 | private void RecomputeLinksetCompound() | 321 | private void RecomputeLinksetCompound() |
404 | { | 322 | { |
405 | try | 323 | try |
406 | { | 324 | { |
407 | // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) | ||
408 | Rebuilding = true; | 325 | Rebuilding = true; |
409 | 326 | ||
410 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 327 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set |
411 | LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); | 328 | // to what they should be as if the root was not in a linkset. |
329 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
330 | // something has been updated/changed. | ||
331 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
412 | 332 | ||
413 | // The center of mass for the linkset is the geometric center of the group. | 333 | // 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. | 334 | 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 | { | 335 | { |
419 | // Compute a center-of-mass in world coordinates. | 336 | // Clean up any old linkset shape and make sure the root shape is set to the root object. |
420 | centerOfMassW = ComputeLinksetCenterOfMass(); | 337 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); |
421 | } | ||
422 | 338 | ||
423 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 339 | return; // Note the 'finally' clause at the botton which will get executed. |
424 | 340 | } | |
425 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
426 | OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
427 | LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); | ||
428 | 341 | ||
429 | // This causes the physical position of the root prim to be offset to accomodate for the displacements | 342 | // Get a new compound shape to build the linkset shape in. |
430 | LinksetRoot.ForcePosition = LinksetRoot.RawPosition; | 343 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); |
431 | 344 | ||
432 | // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM | 345 | // The center of mass for the linkset is the geometric center of the group. |
433 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, | 346 | // Compute a displacement for each component so it is relative to the center-of-mass. |
434 | -centerDisplacement, | 347 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass |
435 | OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, | 348 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); |
436 | false /* shouldRecalculateLocalAabb (is done later after linkset built) */); | ||
437 | 349 | ||
438 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", | 350 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); |
439 | LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); | ||
440 | 351 | ||
441 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 352 | // 'centerDisplacement' is the value to subtract from children to give physical offset position |
442 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 353 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; |
354 | if (UseBulletSimRootOffsetHack || disableCOM) | ||
355 | { | ||
356 | centerDisplacementV = OMV.Vector3.Zero; | ||
357 | LinksetRoot.ClearDisplacement(); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
362 | } | ||
363 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", | ||
364 | LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV); | ||
443 | 365 | ||
444 | // Add a shape for each of the other children in the linkset | 366 | // Add the shapes of all the components of the linkset |
445 | int memberIndex = 1; | 367 | int memberIndex = 1; |
446 | ForEachMember(delegate(BSPrimLinkable cPrim) | 368 | ForEachMember(delegate(BSPrimLinkable cPrim) |
447 | { | 369 | { |
448 | if (IsRoot(cPrim)) | 370 | // Root shape is always index zero. |
371 | cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex; | ||
372 | |||
373 | // Get a reference to the shape of the child and add that shape to the linkset compound shape | ||
374 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); | ||
375 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV; | ||
376 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
377 | m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); | ||
378 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", | ||
379 | LinksetRoot.LocalID, memberIndex, childShape, offsetPos, offsetRot); | ||
380 | |||
381 | // Since we are borrowing the shape of the child, disable the origional child body | ||
382 | if (!IsRoot(cPrim)) | ||
449 | { | 383 | { |
450 | cPrim.LinksetChildIndex = 0; | 384 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
385 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
386 | // We don't want collisions from the old linkset children. | ||
387 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
388 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; | ||
451 | } | 389 | } |
452 | else | ||
453 | { | ||
454 | cPrim.LinksetChildIndex = memberIndex; | ||
455 | 390 | ||
456 | if (cPrim.PhysShape.isNativeShape) | 391 | memberIndex++; |
457 | { | ||
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 | 392 | ||
492 | } | ||
493 | memberIndex++; | ||
494 | } | ||
495 | return false; // 'false' says to move onto the next child in the list | 393 | return false; // 'false' says to move onto the next child in the list |
496 | }); | 394 | }); |
497 | 395 | ||
396 | // Replace the root shape with the built compound shape. | ||
397 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
398 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
399 | LinksetRoot.PhysShape = linksetShape; | ||
400 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
401 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
402 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
403 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
404 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
405 | |||
498 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 406 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
499 | LinksetMass = ComputeLinksetMass(); | 407 | LinksetMass = ComputeLinksetMass(); |
500 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 408 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
501 | 409 | ||
502 | // Enable the physical position updator to return the position and rotation of the root shape | 410 | if (UseBulletSimRootOffsetHack) |
503 | PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | 411 | { |
412 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
413 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
414 | // compound shape. This eleviates the need to offset the returned physical position by the | ||
415 | // center-of-mass offset. | ||
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..a06a44d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -51,7 +51,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
51 | if (HasAnyChildren && IsRoot(requestor)) | 51 | if (HasAnyChildren && IsRoot(requestor)) |
52 | { | 52 | { |
53 | // Queue to happen after all the other taint processing | 53 | // Queue to happen after all the other taint processing |
54 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 54 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
55 | { | 55 | { |
56 | if (HasAnyChildren && IsRoot(requestor)) | 56 | if (HasAnyChildren && IsRoot(requestor)) |
57 | RecomputeLinksetConstraints(); | 57 | RecomputeLinksetConstraints(); |
@@ -93,11 +93,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
93 | // up to rebuild the constraints before the next simulation step. | 93 | // up to rebuild the constraints before the next simulation step. |
94 | // Returns 'true' of something was actually removed and would need restoring | 94 | // Returns 'true' of something was actually removed and would need restoring |
95 | // Called at taint-time!! | 95 | // Called at taint-time!! |
96 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 96 | public override bool RemoveDependencies(BSPrimLinkable child) |
97 | { | 97 | { |
98 | bool ret = false; | 98 | bool ret = false; |
99 | 99 | ||
100 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 100 | DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); | 101 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); |
102 | 102 | ||
103 | lock (m_linksetActivityLock) | 103 | lock (m_linksetActivityLock) |
@@ -142,7 +142,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
142 | rootx.LocalID, rootx.PhysBody.AddrString, | 142 | rootx.LocalID, rootx.PhysBody.AddrString, |
143 | childx.LocalID, childx.PhysBody.AddrString); | 143 | childx.LocalID, childx.PhysBody.AddrString); |
144 | 144 | ||
145 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 145 | m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
146 | { | 146 | { |
147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
148 | }); | 148 | }); |
@@ -187,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
187 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 187 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
188 | 188 | ||
189 | BSConstraint6Dof constrain = new BSConstraint6Dof( | 189 | BSConstraint6Dof constrain = new BSConstraint6Dof( |
190 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); | 190 | m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); |
191 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | 191 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); |
192 | 192 | ||
193 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 193 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
@@ -216,7 +216,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
216 | // ================================================================================== | 216 | // ================================================================================== |
217 | */ | 217 | */ |
218 | 218 | ||
219 | PhysicsScene.Constraints.AddConstraint(constrain); | 219 | m_physicsScene.Constraints.AddConstraint(constrain); |
220 | 220 | ||
221 | // zero linear and angular limits makes the objects unable to move in relation to each other | 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); | 222 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
@@ -248,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
248 | childPrim.LocalID, childPrim.PhysBody.AddrString); | 248 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
249 | 249 | ||
250 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 250 | // 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)) | 251 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
252 | { | 252 | { |
253 | // Make the child refresh its location | 253 | // Make the child refresh its location |
254 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); | 254 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); |
255 | ret = true; | 255 | ret = true; |
256 | } | 256 | } |
257 | 257 | ||
@@ -265,7 +265,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
265 | { | 265 | { |
266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
267 | 267 | ||
268 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | 268 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); |
269 | } | 269 | } |
270 | 270 | ||
271 | // Call each of the constraints that make up this linkset and recompute the | 271 | // Call each of the constraints that make up this linkset and recompute the |
@@ -289,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
289 | child.UpdatePhysicalMassProperties(linksetMass, true); | 289 | child.UpdatePhysicalMassProperties(linksetMass, true); |
290 | 290 | ||
291 | BSConstraint constrain; | 291 | BSConstraint constrain; |
292 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | 292 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
293 | { | 293 | { |
294 | // If constraint doesn't exist yet, create it. | 294 | // If constraint doesn't exist yet, create it. |
295 | constrain = BuildConstraint(LinksetRoot, child); | 295 | constrain = BuildConstraint(LinksetRoot, child); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 9501e2d..ef662b5 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 | } |
@@ -165,26 +160,11 @@ public class BSVMotor : BSMotor | |||
165 | TargetValue *= (1f - decayFactor); | 160 | TargetValue *= (1f - decayFactor); |
166 | } | 161 | } |
167 | 162 | ||
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}", | 163 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", |
182 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | 164 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
183 | timeStep, error, correction); | 165 | timeStep, error, correction); |
184 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | 166 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", |
185 | BSScene.DetailLogZero, UseName, | 167 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); |
186 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
187 | TargetValue, CurrentValue); | ||
188 | } | 168 | } |
189 | else | 169 | else |
190 | { | 170 | { |
@@ -235,9 +215,9 @@ public class BSVMotor : BSMotor | |||
235 | // maximum number of outputs to generate. | 215 | // maximum number of outputs to generate. |
236 | int maxOutput = 50; | 216 | int maxOutput = 50; |
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | 217 | 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}", | 218 | MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", |
239 | BSScene.DetailLogZero, UseName, | 219 | BSScene.DetailLogZero, UseName, |
240 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | 220 | TimeScale, TargetValueDecayTimeScale, Efficiency, |
241 | CurrentValue, TargetValue); | 221 | CurrentValue, TargetValue); |
242 | 222 | ||
243 | LastError = BSMotor.InfiniteVector; | 223 | LastError = BSMotor.InfiniteVector; |
@@ -248,14 +228,14 @@ public class BSVMotor : BSMotor | |||
248 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | 228 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); |
249 | } | 229 | } |
250 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | 230 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); |
251 | 231 | ||
252 | 232 | ||
253 | } | 233 | } |
254 | 234 | ||
255 | public override string ToString() | 235 | public override string ToString() |
256 | { | 236 | { |
257 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | 237 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", |
258 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | 238 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); |
259 | } | 239 | } |
260 | } | 240 | } |
261 | 241 | ||
@@ -265,7 +245,6 @@ public class BSFMotor : BSMotor | |||
265 | { | 245 | { |
266 | public virtual float TimeScale { get; set; } | 246 | public virtual float TimeScale { get; set; } |
267 | public virtual float TargetValueDecayTimeScale { get; set; } | 247 | public virtual float TargetValueDecayTimeScale { get; set; } |
268 | public virtual float FrictionTimescale { get; set; } | ||
269 | public virtual float Efficiency { get; set; } | 248 | public virtual float Efficiency { get; set; } |
270 | 249 | ||
271 | public virtual float ErrorZeroThreshold { get; set; } | 250 | public virtual float ErrorZeroThreshold { get; set; } |
@@ -279,16 +258,15 @@ public class BSFMotor : BSMotor | |||
279 | return ErrorIsZero(LastError); | 258 | return ErrorIsZero(LastError); |
280 | } | 259 | } |
281 | public virtual bool ErrorIsZero(float err) | 260 | public virtual bool ErrorIsZero(float err) |
282 | { | 261 | { |
283 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | 262 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); |
284 | } | 263 | } |
285 | 264 | ||
286 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | 265 | public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) |
287 | : base(useName) | 266 | : base(useName) |
288 | { | 267 | { |
289 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | 268 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
290 | Efficiency = 1f; | 269 | Efficiency = 1f; |
291 | FrictionTimescale = BSMotor.Infinite; | ||
292 | CurrentValue = TargetValue = 0f; | 270 | CurrentValue = TargetValue = 0f; |
293 | ErrorZeroThreshold = 0.01f; | 271 | ErrorZeroThreshold = 0.01f; |
294 | } | 272 | } |
@@ -331,24 +309,11 @@ public class BSFMotor : BSMotor | |||
331 | TargetValue *= (1f - decayFactor); | 309 | TargetValue *= (1f - decayFactor); |
332 | } | 310 | } |
333 | 311 | ||
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}", | 312 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", |
346 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | 313 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
347 | timeStep, error, correction); | 314 | timeStep, error, correction); |
348 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", | 315 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", |
349 | BSScene.DetailLogZero, UseName, | 316 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); |
350 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
351 | TargetValue, CurrentValue); | ||
352 | } | 317 | } |
353 | else | 318 | else |
354 | { | 319 | { |
@@ -390,8 +355,8 @@ public class BSFMotor : BSMotor | |||
390 | 355 | ||
391 | public override string ToString() | 356 | public override string ToString() |
392 | { | 357 | { |
393 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", | 358 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", |
394 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | 359 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); |
395 | } | 360 | } |
396 | 361 | ||
397 | } | 362 | } |
@@ -410,7 +375,7 @@ public class BSPIDVMotor : BSVMotor | |||
410 | // The factors are vectors for the three dimensions. This is the proportional of each | 375 | // 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 | 376 | // 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. | 377 | // is sometimes easier to manipulate the factors and their mix separately. |
413 | // to | 378 | // to |
414 | public Vector3 FactorMix; | 379 | public Vector3 FactorMix; |
415 | 380 | ||
416 | // Arbritrary factor range. | 381 | // Arbritrary factor range. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 385ed9e..aad1108 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,16 @@ 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; } |
126 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | 137 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } |
127 | public static float AvatarStepHeight { get; private set; } | 138 | public static float AvatarStepHeight { get; private set; } |
128 | public static float AvatarStepApproachFactor { get; private set; } | 139 | public static float AvatarStepApproachFactor { get; private set; } |
129 | public static float AvatarStepForceFactor { get; private set; } | 140 | public static float AvatarStepForceFactor { get; private set; } |
141 | public static float AvatarStepUpCorrectionFactor { get; private set; } | ||
142 | public static int AvatarStepSmoothingSteps { get; private set; } | ||
130 | 143 | ||
131 | // Vehicle parameters | 144 | // Vehicle parameters |
132 | public static float VehicleMaxLinearVelocity { get; private set; } | 145 | public static float VehicleMaxLinearVelocity { get; private set; } |
@@ -138,9 +151,10 @@ public static class BSParam | |||
138 | public static float VehicleRestitution { get; private set; } | 151 | public static float VehicleRestitution { get; private set; } |
139 | public static Vector3 VehicleLinearFactor { get; private set; } | 152 | public static Vector3 VehicleLinearFactor { get; private set; } |
140 | public static Vector3 VehicleAngularFactor { get; private set; } | 153 | public static Vector3 VehicleAngularFactor { get; private set; } |
154 | public static Vector3 VehicleInertiaFactor { get; private set; } | ||
141 | public static float VehicleGroundGravityFudge { get; private set; } | 155 | public static float VehicleGroundGravityFudge { get; private set; } |
142 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | 156 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } |
143 | public static bool VehicleDebuggingEnabled { get; private set; } | 157 | public static bool VehicleDebuggingEnable { get; private set; } |
144 | 158 | ||
145 | // Convex Hulls | 159 | // Convex Hulls |
146 | public static int CSHullMaxDepthSplit { get; private set; } | 160 | public static int CSHullMaxDepthSplit { get; private set; } |
@@ -149,6 +163,15 @@ public static class BSParam | |||
149 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | 163 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } |
150 | public static int CSHullMaxVertices { get; private set; } | 164 | public static int CSHullMaxVertices { get; private set; } |
151 | public static float CSHullMaxSkinWidth { get; private set; } | 165 | public static float CSHullMaxSkinWidth { get; private set; } |
166 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
167 | public static float BHullMinClusters { get; private set; } // 2 | ||
168 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
169 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
170 | public static float BHullConcavity { get; private set; } // 100 | ||
171 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
172 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
173 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
174 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
152 | 175 | ||
153 | // Linkset implementation parameters | 176 | // Linkset implementation parameters |
154 | public static float LinksetImplementation { get; private set; } | 177 | public static float LinksetImplementation { get; private set; } |
@@ -223,16 +246,41 @@ public static class BSParam | |||
223 | getter = pGetter; | 246 | getter = pGetter; |
224 | objectSet = pObjSetter; | 247 | objectSet = pObjSetter; |
225 | } | 248 | } |
226 | /* Wish I could simplify using this definition but CLR doesn't store references so closure around delegates of references won't work | 249 | // 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) | 250 | // and the value is only a simple get and set. |
251 | public ParameterDefn(string pName, string pDesc, T pDefault) | ||
228 | : base(pName, pDesc) | 252 | : base(pName, pDesc) |
229 | { | 253 | { |
230 | defaultValue = pDefault; | 254 | defaultValue = pDefault; |
231 | setter = (s, v) => { loc = v; }; | 255 | setter = (s, v) => { SetValueByName(s, name, v); }; |
232 | getter = (s) => { return loc; }; | 256 | getter = (s) => { return GetValueByName(s, name); }; |
233 | objectSet = null; | 257 | objectSet = null; |
234 | } | 258 | } |
235 | */ | 259 | // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. |
260 | private void SetValueByName(BSScene s, string pName, T val) | ||
261 | { | ||
262 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
263 | if (prop == null) | ||
264 | { | ||
265 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
266 | s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | prop.SetValue(null, val, null); | ||
271 | } | ||
272 | } | ||
273 | // Use reflection to find the property named 'pName' in BSParam and return the value in same. | ||
274 | private T GetValueByName(BSScene s, string pName) | ||
275 | { | ||
276 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
277 | if (prop == null) | ||
278 | { | ||
279 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
280 | s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); | ||
281 | } | ||
282 | return (T)prop.GetValue(null, null); | ||
283 | } | ||
236 | public override void AssignDefault(BSScene s) | 284 | public override void AssignDefault(BSScene s) |
237 | { | 285 | { |
238 | setter(s, defaultValue); | 286 | setter(s, defaultValue); |
@@ -309,6 +357,11 @@ public static class BSParam | |||
309 | // v = value (appropriate type) | 357 | // v = value (appropriate type) |
310 | private static ParameterDefnBase[] ParameterDefinitions = | 358 | private static ParameterDefnBase[] ParameterDefinitions = |
311 | { | 359 | { |
360 | new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", | ||
361 | false ), | ||
362 | new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", | ||
363 | 0.089f ), | ||
364 | |||
312 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", | 365 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
313 | true, | 366 | true, |
314 | (s) => { return ShouldMeshSculptedPrim; }, | 367 | (s) => { return ShouldMeshSculptedPrim; }, |
@@ -322,18 +375,20 @@ public static class BSParam | |||
322 | (s) => { return ShouldUseHullsForPhysicalObjects; }, | 375 | (s) => { return ShouldUseHullsForPhysicalObjects; }, |
323 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), | 376 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), |
324 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", | 377 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", |
325 | true, | 378 | true ), |
326 | (s) => { return ShouldRemoveZeroWidthTriangles; }, | 379 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", |
327 | (s,v) => { ShouldRemoveZeroWidthTriangles = v; } ), | 380 | false ), |
381 | new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", | ||
382 | true ), | ||
383 | new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", | ||
384 | false ), | ||
385 | new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", | ||
386 | true ), | ||
328 | 387 | ||
329 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | 388 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", |
330 | 5, | 389 | 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", | 390 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", |
334 | 0.1f, | 391 | 0.1f ), |
335 | (s) => { return UpdateVelocityChangeThreshold; }, | ||
336 | (s,v) => { UpdateVelocityChangeThreshold = v; } ), | ||
337 | 392 | ||
338 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 393 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
339 | 32f, | 394 | 32f, |
@@ -400,18 +455,12 @@ public static class BSParam | |||
400 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | 455 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), |
401 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. | 456 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. |
402 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", | 457 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", |
403 | 0.01f, | 458 | 0.01f ), |
404 | (s) => { return DensityScaleFactor; }, | ||
405 | (s,v) => { DensityScaleFactor = v; } ), | ||
406 | 459 | ||
407 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | 460 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", |
408 | 2200f, | 461 | 2200f ), |
409 | (s) => { return (float)PID_D; }, | ||
410 | (s,v) => { PID_D = v; } ), | ||
411 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | 462 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", |
412 | 900f, | 463 | 900f ), |
413 | (s) => { return (float)PID_P; }, | ||
414 | (s,v) => { PID_P = v; } ), | ||
415 | 464 | ||
416 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | 465 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", |
417 | 0.2f, | 466 | 0.2f, |
@@ -478,86 +527,56 @@ public static class BSParam | |||
478 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), | 527 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), |
479 | 528 | ||
480 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | 529 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", |
481 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | 530 | (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" , | 531 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , |
485 | 2, | 532 | 2 ), |
486 | (s) => { return TerrainMeshMagnification; }, | ||
487 | (s,v) => { TerrainMeshMagnification = v; } ), | ||
488 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , | 533 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , |
489 | 0.3f, | 534 | 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" , | 535 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , |
493 | 0.8f, | 536 | 0.8f ), |
494 | (s) => { return TerrainHitFraction; }, | ||
495 | (s,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | ||
496 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , | 537 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , |
497 | 0f, | 538 | 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" , | 539 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , |
501 | 0.0f, | 540 | 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" , | 541 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , |
505 | 0.08f, | 542 | 0.08f ), |
506 | (s) => { return TerrainCollisionMargin; }, | ||
507 | (s,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
508 | 543 | ||
509 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 544 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
510 | 0.2f, | 545 | 0.2f ), |
511 | (s) => { return AvatarFriction; }, | ||
512 | (s,v) => { AvatarFriction = v; } ), | ||
513 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 546 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
514 | 0.95f, | 547 | 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", | 548 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", |
518 | 1.3f, | 549 | 1.3f ), |
519 | (s) => { return AvatarAlwaysRunFactor; }, | ||
520 | (s,v) => { AvatarAlwaysRunFactor = v; } ), | ||
521 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 550 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
522 | 3.5f, | 551 | 3.5f) , |
523 | (s) => { return AvatarDensity; }, | ||
524 | (s,v) => { AvatarDensity = v; } ), | ||
525 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | 552 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", |
526 | 0f, | 553 | 0f ), |
527 | (s) => { return AvatarRestitution; }, | ||
528 | (s,v) => { AvatarRestitution = v; } ), | ||
529 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | 554 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", |
530 | 0.6f, | 555 | 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", | 556 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", |
534 | 0.45f, | 557 | 0.45f ), |
535 | (s) => { return AvatarCapsuleDepth; }, | ||
536 | (s,v) => { AvatarCapsuleDepth = v; } ), | ||
537 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | 558 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", |
538 | 1.5f, | 559 | 1.5f ), |
539 | (s) => { return AvatarCapsuleHeight; }, | 560 | new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", |
540 | (s,v) => { AvatarCapsuleHeight = v; } ), | 561 | -0.2f ), |
562 | new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", | ||
563 | 0.1f ), | ||
564 | new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", | ||
565 | 0.1f ), | ||
541 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 566 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", |
542 | 0.1f, | 567 | 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", | 568 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", |
546 | 1.0f, | 569 | 1.0f ), |
547 | (s) => { return AvatarBelowGroundUpCorrectionMeters; }, | ||
548 | (s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ), | ||
549 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | 570 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", |
550 | 0.3f, | 571 | 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)", | 572 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", |
554 | 0.6f, | 573 | 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", | 574 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", |
558 | 2.0f, | 575 | 1.0f ), |
559 | (s) => { return AvatarStepForceFactor; }, | 576 | new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", |
560 | (s,v) => { AvatarStepForceFactor = v; } ), | 577 | 1.0f ), |
578 | new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", | ||
579 | 2 ), | ||
561 | 580 | ||
562 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | 581 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", |
563 | 1000.0f, | 582 | 1000.0f, |
@@ -568,37 +587,23 @@ public static class BSParam | |||
568 | (s) => { return (float)VehicleMaxAngularVelocity; }, | 587 | (s) => { return (float)VehicleMaxAngularVelocity; }, |
569 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | 588 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), |
570 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | 589 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", |
571 | 0.0f, | 590 | 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>)", | 591 | 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), | 592 | 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>)", | 593 | 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), | 594 | new Vector3(1f, 1f, 1f) ), |
580 | (s) => { return VehicleAngularFactor; }, | 595 | new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", |
581 | (s,v) => { VehicleAngularFactor = v; } ), | 596 | new Vector3(1f, 1f, 1f) ), |
582 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | 597 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", |
583 | 0.0f, | 598 | 0.0f ), |
584 | (s) => { return VehicleFriction; }, | ||
585 | (s,v) => { VehicleFriction = v; } ), | ||
586 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | 599 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", |
587 | 0.0f, | 600 | 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)", | 601 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", |
591 | 0.2f, | 602 | 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.", | 603 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", |
595 | 60.0f, | 604 | 60.0f ), |
596 | (s) => { return VehicleAngularBankingTimescaleFudge; }, | ||
597 | (s,v) => { VehicleAngularBankingTimescaleFudge = v; } ), | ||
598 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | 605 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", |
599 | false, | 606 | false ), |
600 | (s) => { return VehicleDebuggingEnabled; }, | ||
601 | (s,v) => { VehicleDebuggingEnabled = v; } ), | ||
602 | 607 | ||
603 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 608 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
604 | 0f, | 609 | 0f, |
@@ -611,7 +616,7 @@ public static class BSParam | |||
611 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | 616 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", |
612 | false, | 617 | false, |
613 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, | 618 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, |
614 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; | 619 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; |
615 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), | 620 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), |
616 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | 621 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", |
617 | false, | 622 | false, |
@@ -643,62 +648,53 @@ public static class BSParam | |||
643 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), | 648 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), |
644 | 649 | ||
645 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", | 650 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", |
646 | 7, | 651 | 7 ), |
647 | (s) => { return CSHullMaxDepthSplit; }, | ||
648 | (s,v) => { CSHullMaxDepthSplit = v; } ), | ||
649 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | 652 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", |
650 | 2, | 653 | 2 ), |
651 | (s) => { return CSHullMaxDepthSplitForSimpleShapes; }, | ||
652 | (s,v) => { CSHullMaxDepthSplitForSimpleShapes = v; } ), | ||
653 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | 654 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", |
654 | 5f, | 655 | 5f ), |
655 | (s) => { return CSHullConcavityThresholdPercent; }, | ||
656 | (s,v) => { CSHullConcavityThresholdPercent = v; } ), | ||
657 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | 656 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", |
658 | 5f, | 657 | 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.", | 658 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", |
662 | 32, | 659 | 32 ), |
663 | (s) => { return CSHullMaxVertices; }, | ||
664 | (s,v) => { CSHullMaxVertices = v; } ), | ||
665 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | 660 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", |
666 | 0, | 661 | 0f ), |
667 | (s) => { return CSHullMaxSkinWidth; }, | 662 | |
668 | (s,v) => { CSHullMaxSkinWidth = v; } ), | 663 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", |
664 | 100f ), | ||
665 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
666 | 2f ), | ||
667 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
668 | 0.1f ), | ||
669 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
670 | 0f ), | ||
671 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
672 | 100f ), | ||
673 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
674 | false ), | ||
675 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
676 | false ), | ||
677 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
678 | false ), | ||
679 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
680 | false ), | ||
669 | 681 | ||
670 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | 682 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", |
671 | (float)BSLinkset.LinksetImplementation.Compound, | 683 | (float)BSLinkset.LinksetImplementation.Compound ), |
672 | (s) => { return LinksetImplementation; }, | ||
673 | (s,v) => { LinksetImplementation = v; } ), | ||
674 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | 684 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
675 | false, | 685 | false ), |
676 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
677 | (s,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
678 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | 686 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", |
679 | true, | 687 | 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", | 688 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", |
683 | 5.0f, | 689 | 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", | 690 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", |
687 | 0.1f, | 691 | 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", | 692 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
691 | 0.1f, | 693 | 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", | 694 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
695 | 0.1f, | 695 | 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)", | 696 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", |
699 | 40, | 697 | 40 ), |
700 | (s) => { return LinkConstraintSolverIterations; }, | ||
701 | (s,v) => { LinkConstraintSolverIterations = v; } ), | ||
702 | 698 | ||
703 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | 699 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", |
704 | 0, | 700 | 0, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 6bb88c7..a4c5e08 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,23 @@ 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 | PhysScene = parentScene; |
76 | LocalID = localID; | 76 | LocalID = localID; |
77 | PhysObjectName = name; | 77 | PhysObjectName = name; |
78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. | 78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. |
79 | TypeName = typeName; | 79 | TypeName = typeName; |
80 | 80 | ||
81 | // The collection of things that push me around | ||
82 | PhysicalActors = new BSActorCollection(PhysScene); | ||
83 | |||
81 | // Initialize variables kept in base. | 84 | // Initialize variables kept in base. |
82 | GravModifier = 1.0f; | 85 | GravModifier = 1.0f; |
83 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | 86 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); |
87 | HoverActive = false; | ||
84 | 88 | ||
85 | // We don't have any physical representation yet. | 89 | // We don't have any physical representation yet. |
86 | PhysBody = new BulletBody(localID); | 90 | PhysBody = new BulletBody(localID); |
87 | PhysShape = new BulletShape(); | 91 | PhysShape = new BSShapeNull(); |
88 | 92 | ||
89 | PrimAssetState = PrimAssetCondition.Unknown; | 93 | PrimAssetState = PrimAssetCondition.Unknown; |
90 | 94 | ||
@@ -92,7 +96,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
92 | SetMaterial((int)MaterialAttributes.Material.Wood); | 96 | SetMaterial((int)MaterialAttributes.Material.Wood); |
93 | 97 | ||
94 | CollisionCollection = new CollisionEventUpdate(); | 98 | CollisionCollection = new CollisionEventUpdate(); |
95 | CollisionsLastTick = CollisionCollection; | 99 | CollisionsLastReported = CollisionCollection; |
100 | CollisionsLastTick = new CollisionEventUpdate(); | ||
101 | CollisionsLastTickStep = -1; | ||
102 | |||
96 | SubscribedEventsMs = 0; | 103 | SubscribedEventsMs = 0; |
97 | CollidingStep = 0; | 104 | CollidingStep = 0; |
98 | CollidingGroundStep = 0; | 105 | CollidingGroundStep = 0; |
@@ -101,17 +108,21 @@ public abstract class BSPhysObject : PhysicsActor | |||
101 | CollisionScore = 0; | 108 | CollisionScore = 0; |
102 | 109 | ||
103 | // All axis free. | 110 | // All axis free. |
104 | LockedAxis = LockedAxisFree; | 111 | LockedLinearAxis = LockedAxisFree; |
112 | LockedAngularAxis = LockedAxisFree; | ||
105 | } | 113 | } |
106 | 114 | ||
107 | // Tell the object to clean up. | 115 | // Tell the object to clean up. |
108 | public virtual void Destroy() | 116 | public virtual void Destroy() |
109 | { | 117 | { |
110 | UnRegisterAllPreStepActions(); | 118 | PhysicalActors.Enable(false); |
111 | UnRegisterAllPostStepActions(); | 119 | PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() |
120 | { | ||
121 | PhysicalActors.Dispose(); | ||
122 | }); | ||
112 | } | 123 | } |
113 | 124 | ||
114 | public BSScene PhysicsScene { get; protected set; } | 125 | public BSScene PhysScene { get; protected set; } |
115 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor | 126 | // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor |
116 | public string PhysObjectName { get; protected set; } | 127 | public string PhysObjectName { get; protected set; } |
117 | public string TypeName { get; protected set; } | 128 | public string TypeName { get; protected set; } |
@@ -131,26 +142,19 @@ public abstract class BSPhysObject : PhysicsActor | |||
131 | // Reference to the physical body (btCollisionObject) of this object | 142 | // Reference to the physical body (btCollisionObject) of this object |
132 | public BulletBody PhysBody; | 143 | public BulletBody PhysBody; |
133 | // Reference to the physical shape (btCollisionShape) of this object | 144 | // Reference to the physical shape (btCollisionShape) of this object |
134 | public BulletShape PhysShape; | 145 | public BSShape PhysShape; |
135 | 146 | ||
136 | // The physical representation of the prim might require an asset fetch. | 147 | // 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'. | 148 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. |
138 | public enum PrimAssetCondition | 149 | public enum PrimAssetCondition |
139 | { | 150 | { |
140 | Unknown, Waiting, Failed, Fetched | 151 | Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched |
141 | } | 152 | } |
142 | public PrimAssetCondition PrimAssetState { get; set; } | 153 | public PrimAssetCondition PrimAssetState { get; set; } |
143 | 154 | ||
144 | // The objects base shape information. Null if not a prim type shape. | 155 | // The objects base shape information. Null if not a prim type shape. |
145 | public PrimitiveBaseShape BaseShape { get; protected set; } | 156 | public PrimitiveBaseShape BaseShape { get; protected set; } |
146 | 157 | ||
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. | 158 | // When the physical properties are updated, an EntityProperty holds the update values. |
155 | // Keep the current and last EntityProperties to enable computation of differences | 159 | // Keep the current and last EntityProperties to enable computation of differences |
156 | // between the current update and the previous values. | 160 | // between the current update and the previous values. |
@@ -180,7 +184,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
180 | Friction = matAttrib.friction; | 184 | Friction = matAttrib.friction; |
181 | Restitution = matAttrib.restitution; | 185 | Restitution = matAttrib.restitution; |
182 | Density = matAttrib.density / BSParam.DensityScaleFactor; | 186 | Density = matAttrib.density / BSParam.DensityScaleFactor; |
183 | DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); | 187 | // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); |
184 | } | 188 | } |
185 | 189 | ||
186 | // Stop all physical motion. | 190 | // Stop all physical motion. |
@@ -196,15 +200,48 @@ public abstract class BSPhysObject : PhysicsActor | |||
196 | public abstract OMV.Quaternion RawOrientation { get; set; } | 200 | public abstract OMV.Quaternion RawOrientation { get; set; } |
197 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 201 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
198 | 202 | ||
199 | public abstract OMV.Vector3 RawVelocity { get; set; } | 203 | public OMV.Vector3 RawVelocity { get; set; } |
200 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 204 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
201 | 205 | ||
206 | public OMV.Vector3 RawForce { get; set; } | ||
207 | public OMV.Vector3 RawTorque { get; set; } | ||
208 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) | ||
209 | { | ||
210 | AddAngularForce(force, pushforce, false); | ||
211 | } | ||
212 | public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); | ||
213 | |||
202 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 214 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
203 | 215 | ||
204 | public abstract float ForceBuoyancy { get; set; } | 216 | public abstract float ForceBuoyancy { get; set; } |
205 | 217 | ||
206 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 218 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
207 | 219 | ||
220 | public override bool PIDActive { set { MoveToTargetActive = value; } } | ||
221 | public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } | ||
222 | public override float PIDTau { set { MoveToTargetTau = value; } } | ||
223 | |||
224 | public bool MoveToTargetActive { get; set; } | ||
225 | public OMV.Vector3 MoveToTargetTarget { get; set; } | ||
226 | public float MoveToTargetTau { get; set; } | ||
227 | |||
228 | // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z | ||
229 | public override bool PIDHoverActive { set { HoverActive = value; } } | ||
230 | public override float PIDHoverHeight { set { HoverHeight = value; } } | ||
231 | public override PIDHoverType PIDHoverType { set { HoverType = value; } } | ||
232 | public override float PIDHoverTau { set { HoverTau = value; } } | ||
233 | |||
234 | public bool HoverActive { get; set; } | ||
235 | public float HoverHeight { get; set; } | ||
236 | public PIDHoverType HoverType { get; set; } | ||
237 | public float HoverTau { get; set; } | ||
238 | |||
239 | // For RotLookAt | ||
240 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
241 | public override bool APIDActive { set { return; } } | ||
242 | public override float APIDStrength { set { return; } } | ||
243 | public override float APIDDamping { set { return; } } | ||
244 | |||
208 | // The current velocity forward | 245 | // The current velocity forward |
209 | public virtual float ForwardSpeed | 246 | public virtual float ForwardSpeed |
210 | { | 247 | { |
@@ -226,10 +263,58 @@ public abstract class BSPhysObject : PhysicsActor | |||
226 | 263 | ||
227 | // The user can optionally set the center of mass. The user's setting will override any | 264 | // The user can optionally set the center of mass. The user's setting will override any |
228 | // computed center-of-mass (like in linksets). | 265 | // computed center-of-mass (like in linksets). |
229 | public OMV.Vector3? UserSetCenterOfMass { get; set; } | 266 | // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. |
267 | public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } | ||
268 | |||
269 | public OMV.Vector3 LockedLinearAxis { get; set; } // zero means locked. one means free. | ||
270 | public OMV.Vector3 LockedAngularAxis { get; set; } // zero means locked. one means free. | ||
271 | public const float FreeAxis = 1f; | ||
272 | public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free | ||
273 | |||
274 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
275 | // they need waking up when parameters are changed. | ||
276 | // Called in taint-time!! | ||
277 | public void ActivateIfPhysical(bool forceIt) | ||
278 | { | ||
279 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
280 | PhysScene.PE.Activate(PhysBody, forceIt); | ||
281 | } | ||
230 | 282 | ||
231 | public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free. | 283 | // '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 | 284 | // hovering to complex vehicle motion. |
285 | // May be called at non-taint time as this just adds the actor to the action list and the real | ||
286 | // work is done during the simulation step. | ||
287 | // Note that, if the actor is already in the list and we are disabling same, the actor is just left | ||
288 | // in the list disabled. | ||
289 | public delegate BSActor CreateActor(); | ||
290 | public void EnableActor(bool enableActor, string actorName, CreateActor creator) | ||
291 | { | ||
292 | lock (PhysicalActors) | ||
293 | { | ||
294 | BSActor theActor; | ||
295 | if (PhysicalActors.TryGetActor(actorName, out theActor)) | ||
296 | { | ||
297 | // The actor already exists so just turn it on or off | ||
298 | DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); | ||
299 | theActor.Enabled = enableActor; | ||
300 | } | ||
301 | else | ||
302 | { | ||
303 | // The actor does not exist. If it should, create it. | ||
304 | if (enableActor) | ||
305 | { | ||
306 | DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); | ||
307 | theActor = creator(); | ||
308 | PhysicalActors.Add(actorName, theActor); | ||
309 | theActor.Enabled = true; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | } | ||
233 | 318 | ||
234 | #region Collisions | 319 | #region Collisions |
235 | 320 | ||
@@ -247,45 +332,50 @@ public abstract class BSPhysObject : PhysicsActor | |||
247 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 332 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
248 | // On a collision, check the collider and remember if the last collider was moving | 333 | // 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) | 334 | // Used to modify the standing of avatars (avatars on stationary things stand still) |
250 | protected bool ColliderIsMoving; | 335 | public bool ColliderIsMoving; |
336 | // Used by BSCharacter to manage standing (and not slipping) | ||
337 | public bool IsStationary; | ||
251 | 338 | ||
252 | // Count of collisions for this object | 339 | // Count of collisions for this object |
253 | protected long CollisionAccumulation { get; set; } | 340 | protected long CollisionAccumulation { get; set; } |
254 | 341 | ||
255 | public override bool IsColliding { | 342 | public override bool IsColliding { |
256 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 343 | get { return (CollidingStep == PhysScene.SimulationStep); } |
257 | set { | 344 | set { |
258 | if (value) | 345 | if (value) |
259 | CollidingStep = PhysicsScene.SimulationStep; | 346 | CollidingStep = PhysScene.SimulationStep; |
260 | else | 347 | else |
261 | CollidingStep = 0; | 348 | CollidingStep = 0; |
262 | } | 349 | } |
263 | } | 350 | } |
264 | public override bool CollidingGround { | 351 | public override bool CollidingGround { |
265 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 352 | get { return (CollidingGroundStep == PhysScene.SimulationStep); } |
266 | set | 353 | set |
267 | { | 354 | { |
268 | if (value) | 355 | if (value) |
269 | CollidingGroundStep = PhysicsScene.SimulationStep; | 356 | CollidingGroundStep = PhysScene.SimulationStep; |
270 | else | 357 | else |
271 | CollidingGroundStep = 0; | 358 | CollidingGroundStep = 0; |
272 | } | 359 | } |
273 | } | 360 | } |
274 | public override bool CollidingObj { | 361 | public override bool CollidingObj { |
275 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | 362 | get { return (CollidingObjectStep == PhysScene.SimulationStep); } |
276 | set { | 363 | set { |
277 | if (value) | 364 | if (value) |
278 | CollidingObjectStep = PhysicsScene.SimulationStep; | 365 | CollidingObjectStep = PhysScene.SimulationStep; |
279 | else | 366 | else |
280 | CollidingObjectStep = 0; | 367 | CollidingObjectStep = 0; |
281 | } | 368 | } |
282 | } | 369 | } |
283 | 370 | ||
284 | // The collisions that have been collected this tick | 371 | // The collisions that have been collected for the next collision reporting (throttled by subscription) |
285 | protected CollisionEventUpdate CollisionCollection; | 372 | protected CollisionEventUpdate CollisionCollection; |
286 | // Remember collisions from last tick for fancy collision based actions | 373 | // This is the collision collection last reported to the Simulator. |
374 | public CollisionEventUpdate CollisionsLastReported; | ||
375 | // Remember the collisions recorded in the last tick for fancy collision checking | ||
287 | // (like a BSCharacter walking up stairs). | 376 | // (like a BSCharacter walking up stairs). |
288 | protected CollisionEventUpdate CollisionsLastTick; | 377 | public CollisionEventUpdate CollisionsLastTick; |
378 | private long CollisionsLastTickStep = -1; | ||
289 | 379 | ||
290 | // The simulation step is telling this object about a collision. | 380 | // The simulation step is telling this object about a collision. |
291 | // Return 'true' if a collision was processed and should be sent up. | 381 | // Return 'true' if a collision was processed and should be sent up. |
@@ -297,14 +387,14 @@ public abstract class BSPhysObject : PhysicsActor | |||
297 | bool ret = false; | 387 | bool ret = false; |
298 | 388 | ||
299 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work | 389 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
300 | CollidingStep = PhysicsScene.SimulationStep; | 390 | CollidingStep = PhysScene.SimulationStep; |
301 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 391 | if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) |
302 | { | 392 | { |
303 | CollidingGroundStep = PhysicsScene.SimulationStep; | 393 | CollidingGroundStep = PhysScene.SimulationStep; |
304 | } | 394 | } |
305 | else | 395 | else |
306 | { | 396 | { |
307 | CollidingObjectStep = PhysicsScene.SimulationStep; | 397 | CollidingObjectStep = PhysScene.SimulationStep; |
308 | } | 398 | } |
309 | 399 | ||
310 | CollisionAccumulation++; | 400 | CollisionAccumulation++; |
@@ -312,6 +402,15 @@ public abstract class BSPhysObject : PhysicsActor | |||
312 | // For movement tests, remember if we are colliding with an object that is moving. | 402 | // For movement tests, remember if we are colliding with an object that is moving. |
313 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | 403 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; |
314 | 404 | ||
405 | // Make a collection of the collisions that happened the last simulation tick. | ||
406 | // This is different than the collection created for sending up to the simulator as it is cleared every tick. | ||
407 | if (CollisionsLastTickStep != PhysScene.SimulationStep) | ||
408 | { | ||
409 | CollisionsLastTick = new CollisionEventUpdate(); | ||
410 | CollisionsLastTickStep = PhysScene.SimulationStep; | ||
411 | } | ||
412 | CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
413 | |||
315 | // If someone has subscribed for collision events log the collision so it will be reported up | 414 | // If someone has subscribed for collision events log the collision so it will be reported up |
316 | if (SubscribedEvents()) { | 415 | if (SubscribedEvents()) { |
317 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | 416 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); |
@@ -332,12 +431,12 @@ public abstract class BSPhysObject : PhysicsActor | |||
332 | bool ret = true; | 431 | bool ret = true; |
333 | 432 | ||
334 | // If the 'no collision' call, force it to happen right now so quick collision_end | 433 | // If the 'no collision' call, force it to happen right now so quick collision_end |
335 | bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0); | 434 | bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); |
336 | 435 | ||
337 | // throttle the collisions to the number of milliseconds specified in the subscription | 436 | // throttle the collisions to the number of milliseconds specified in the subscription |
338 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 437 | if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) |
339 | { | 438 | { |
340 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | 439 | NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; |
341 | 440 | ||
342 | // We are called if we previously had collisions. If there are no collisions | 441 | // 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. | 442 | // this time, send up one last empty event so OpenSim can sense collision end. |
@@ -351,11 +450,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
351 | base.SendCollisionUpdate(CollisionCollection); | 450 | base.SendCollisionUpdate(CollisionCollection); |
352 | 451 | ||
353 | // Remember the collisions from this tick for some collision specific processing. | 452 | // Remember the collisions from this tick for some collision specific processing. |
354 | CollisionsLastTick = CollisionCollection; | 453 | CollisionsLastReported = CollisionCollection; |
355 | 454 | ||
356 | // The CollisionCollection instance is passed around in the simulator. | 455 | // 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. | 456 | // 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, | 457 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, |
359 | // a race condition is created for the other users of this instance. | 458 | // a race condition is created for the other users of this instance. |
360 | CollisionCollection = new CollisionEventUpdate(); | 459 | CollisionCollection = new CollisionEventUpdate(); |
361 | } | 460 | } |
@@ -372,10 +471,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
372 | // make sure first collision happens | 471 | // make sure first collision happens |
373 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | 472 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); |
374 | 473 | ||
375 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 474 | PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
376 | { | 475 | { |
377 | if (PhysBody.HasPhysicalBody) | 476 | if (PhysBody.HasPhysicalBody) |
378 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 477 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
379 | }); | 478 | }); |
380 | } | 479 | } |
381 | else | 480 | else |
@@ -387,11 +486,11 @@ public abstract class BSPhysObject : PhysicsActor | |||
387 | public override void UnSubscribeEvents() { | 486 | public override void UnSubscribeEvents() { |
388 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | 487 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); |
389 | SubscribedEventsMs = 0; | 488 | SubscribedEventsMs = 0; |
390 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 489 | PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
391 | { | 490 | { |
392 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. | 491 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
393 | if (PhysBody.HasPhysicalBody) | 492 | if (PhysBody.HasPhysicalBody) |
394 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 493 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
395 | }); | 494 | }); |
396 | } | 495 | } |
397 | // Return 'true' if the simulator wants collision events | 496 | // Return 'true' if the simulator wants collision events |
@@ -405,7 +504,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
405 | { | 504 | { |
406 | // Scale the collision count by the time since the last collision. | 505 | // Scale the collision count by the time since the last collision. |
407 | // The "+1" prevents dividing by zero. | 506 | // The "+1" prevents dividing by zero. |
408 | long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1; | 507 | long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; |
409 | CollisionScore = CollisionAccumulation / timeAgo; | 508 | CollisionScore = CollisionAccumulation / timeAgo; |
410 | } | 509 | } |
411 | public override float CollisionScore { get; set; } | 510 | public override float CollisionScore { get; set; } |
@@ -413,103 +512,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
413 | #endregion // Collisions | 512 | #endregion // Collisions |
414 | 513 | ||
415 | #region Per Simulation Step actions | 514 | #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 | 515 | ||
426 | lock (RegisteredPrestepActions) | 516 | public BSActorCollection PhysicalActors; |
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 | |||
436 | // Unregister a pre step action. Safe to call if the action has not been registered. | ||
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 | 517 | ||
514 | // When an update to the physical properties happens, this event is fired to let | 518 | // 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 | 519 | // different actors to modify the update before it is passed around |
@@ -522,53 +526,13 @@ public abstract class BSPhysObject : PhysicsActor | |||
522 | actions(ref entprop); | 526 | actions(ref entprop); |
523 | } | 527 | } |
524 | 528 | ||
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 | 529 | #endregion // Per Simulation Step actions |
566 | 530 | ||
567 | // High performance detailed logging routine used by the physical objects. | 531 | // High performance detailed logging routine used by the physical objects. |
568 | protected void DetailLog(string msg, params Object[] args) | 532 | protected void DetailLog(string msg, params Object[] args) |
569 | { | 533 | { |
570 | if (PhysicsScene.PhysicsLogging.Enabled) | 534 | if (PhysScene.PhysicsLogging.Enabled) |
571 | PhysicsScene.DetailLog(msg, args); | 535 | PhysScene.DetailLog(msg, args); |
572 | } | 536 | } |
573 | 537 | ||
574 | } | 538 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 6a5461a..95bdc7b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject | |||
55 | private OMV.Vector3 _position; | 55 | private OMV.Vector3 _position; |
56 | 56 | ||
57 | private float _mass; // the mass of this object | 57 | 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; | 58 | private OMV.Vector3 _acceleration; |
62 | private OMV.Quaternion _orientation; | 59 | private OMV.Quaternion _orientation; |
63 | private int _physicsActorType; | 60 | private int _physicsActorType; |
@@ -72,16 +69,19 @@ public class BSPrim : BSPhysObject | |||
72 | 69 | ||
73 | private int CrossingFailures { get; set; } | 70 | private int CrossingFailures { get; set; } |
74 | 71 | ||
75 | public BSDynamics VehicleController { get; private set; } | 72 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. |
73 | public BSDynamics VehicleActor; | ||
74 | public const string VehicleActorName = "BasicVehicle"; | ||
76 | 75 | ||
77 | private BSVMotor _targetMotor; | 76 | // Parameters for the hover actor |
78 | private OMV.Vector3 _PIDTarget; | 77 | public const string HoverActorName = "HoverActor"; |
79 | private float _PIDTau; | 78 | // Parameters for the axis lock actor |
80 | 79 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; | |
81 | private BSFMotor _hoverMotor; | 80 | // Parameters for the move to target actor |
82 | private float _PIDHoverHeight; | 81 | public const string MoveToTargetActorName = "MoveToTargetActor"; |
83 | private PIDHoverType _PIDHoverType; | 82 | // Parameters for the setForce and setTorque actors |
84 | private float _PIDHoverTau; | 83 | public const string SetForceActorName = "SetForceActor"; |
84 | public const string SetTorqueActorName = "SetTorqueActor"; | ||
85 | 85 | ||
86 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | 86 | public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, |
87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -94,26 +94,28 @@ public class BSPrim : BSPhysObject | |||
94 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). | 94 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
95 | _orientation = rotation; | 95 | _orientation = rotation; |
96 | _buoyancy = 0f; | 96 | _buoyancy = 0f; |
97 | _velocity = OMV.Vector3.Zero; | 97 | RawVelocity = OMV.Vector3.Zero; |
98 | _rotationalVelocity = OMV.Vector3.Zero; | 98 | _rotationalVelocity = OMV.Vector3.Zero; |
99 | BaseShape = pbs; | 99 | BaseShape = pbs; |
100 | _isPhysical = pisPhysical; | 100 | _isPhysical = pisPhysical; |
101 | _isVolumeDetect = false; | 101 | _isVolumeDetect = false; |
102 | 102 | ||
103 | VehicleController = new BSDynamics(PhysicsScene, this); // add vehicleness | 103 | // We keep a handle to the vehicle actor so we can set vehicle parameters later. |
104 | VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName); | ||
105 | PhysicalActors.Add(VehicleActorName, VehicleActor); | ||
104 | 106 | ||
105 | _mass = CalculateMass(); | 107 | _mass = CalculateMass(); |
106 | 108 | ||
107 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 109 | // DetailLog("{0},BSPrim.constructor,call", LocalID); |
108 | // do the actual object creation at taint time | 110 | // do the actual object creation at taint time |
109 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 111 | PhysScene.TaintedObject("BSPrim.create", delegate() |
110 | { | 112 | { |
111 | // Make sure the object is being created with some sanity. | 113 | // Make sure the object is being created with some sanity. |
112 | ExtremeSanityCheck(true /* inTaintTime */); | 114 | ExtremeSanityCheck(true /* inTaintTime */); |
113 | 115 | ||
114 | CreateGeomAndObject(true); | 116 | CreateGeomAndObject(true); |
115 | 117 | ||
116 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); | 118 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); |
117 | }); | 119 | }); |
118 | } | 120 | } |
119 | 121 | ||
@@ -126,14 +128,14 @@ public class BSPrim : BSPhysObject | |||
126 | // Undo any vehicle properties | 128 | // Undo any vehicle properties |
127 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 129 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
128 | 130 | ||
129 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | 131 | PhysScene.TaintedObject("BSPrim.Destroy", delegate() |
130 | { | 132 | { |
131 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 133 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
132 | // If there are physical body and shape, release my use of same. | 134 | // If there are physical body and shape, release my use of same. |
133 | PhysicsScene.Shapes.DereferenceBody(PhysBody, null); | 135 | PhysScene.Shapes.DereferenceBody(PhysBody, null); |
134 | PhysBody.Clear(); | 136 | PhysBody.Clear(); |
135 | PhysicsScene.Shapes.DereferenceShape(PhysShape, null); | 137 | PhysShape.Dereference(PhysScene); |
136 | PhysShape.Clear(); | 138 | PhysShape = new BSShapeNull(); |
137 | }); | 139 | }); |
138 | } | 140 | } |
139 | 141 | ||
@@ -159,25 +161,13 @@ public class BSPrim : BSPhysObject | |||
159 | ForceBodyShapeRebuild(false); | 161 | ForceBodyShapeRebuild(false); |
160 | } | 162 | } |
161 | } | 163 | } |
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) | 164 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
167 | { | 165 | { |
168 | if (inTaintTime) | 166 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() |
169 | { | 167 | { |
170 | _mass = CalculateMass(); // changing the shape changes the mass | 168 | _mass = CalculateMass(); // changing the shape changes the mass |
171 | CreateGeomAndObject(true); | 169 | CreateGeomAndObject(true); |
172 | } | 170 | }); |
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; | 171 | return true; |
182 | } | 172 | } |
183 | public override bool Grabbed { | 173 | public override bool Grabbed { |
@@ -190,7 +180,7 @@ public class BSPrim : BSPhysObject | |||
190 | if (value != _isSelected) | 180 | if (value != _isSelected) |
191 | { | 181 | { |
192 | _isSelected = value; | 182 | _isSelected = value; |
193 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 183 | PhysScene.TaintedObject("BSPrim.setSelected", delegate() |
194 | { | 184 | { |
195 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 185 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
196 | SetObjectDynamic(false); | 186 | SetObjectDynamic(false); |
@@ -231,124 +221,56 @@ public class BSPrim : BSPhysObject | |||
231 | // Called at taint time! | 221 | // Called at taint time! |
232 | public override void ZeroMotion(bool inTaintTime) | 222 | public override void ZeroMotion(bool inTaintTime) |
233 | { | 223 | { |
234 | _velocity = OMV.Vector3.Zero; | 224 | RawVelocity = OMV.Vector3.Zero; |
235 | _acceleration = OMV.Vector3.Zero; | 225 | _acceleration = OMV.Vector3.Zero; |
236 | _rotationalVelocity = OMV.Vector3.Zero; | 226 | _rotationalVelocity = OMV.Vector3.Zero; |
237 | 227 | ||
238 | // Zero some other properties in the physics engine | 228 | // Zero some other properties in the physics engine |
239 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 229 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
240 | { | 230 | { |
241 | if (PhysBody.HasPhysicalBody) | 231 | if (PhysBody.HasPhysicalBody) |
242 | PhysicsScene.PE.ClearAllForces(PhysBody); | 232 | PhysScene.PE.ClearAllForces(PhysBody); |
243 | }); | 233 | }); |
244 | } | 234 | } |
245 | public override void ZeroAngularMotion(bool inTaintTime) | 235 | public override void ZeroAngularMotion(bool inTaintTime) |
246 | { | 236 | { |
247 | _rotationalVelocity = OMV.Vector3.Zero; | 237 | _rotationalVelocity = OMV.Vector3.Zero; |
248 | // Zero some other properties in the physics engine | 238 | // Zero some other properties in the physics engine |
249 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 239 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
250 | { | 240 | { |
251 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | 241 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
252 | if (PhysBody.HasPhysicalBody) | 242 | if (PhysBody.HasPhysicalBody) |
253 | { | 243 | { |
254 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 244 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
255 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 245 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
256 | } | 246 | } |
257 | }); | 247 | }); |
258 | } | 248 | } |
259 | 249 | ||
260 | bool TryExperimentalLockAxisCode = false; | ||
261 | BSConstraint LockAxisConstraint = null; | ||
262 | public override void LockAngularMotion(OMV.Vector3 axis) | 250 | public override void LockAngularMotion(OMV.Vector3 axis) |
263 | { | 251 | { |
264 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 252 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
265 | 253 | ||
266 | // "1" means free, "0" means locked | 254 | // "1" means free, "0" means locked |
267 | OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); | 255 | OMV.Vector3 locking = LockedAxisFree; |
268 | if (axis.X != 1) locking.X = 0f; | 256 | if (axis.X != 1) locking.X = 0f; |
269 | if (axis.Y != 1) locking.Y = 0f; | 257 | if (axis.Y != 1) locking.Y = 0f; |
270 | if (axis.Z != 1) locking.Z = 0f; | 258 | if (axis.Z != 1) locking.Z = 0f; |
271 | LockedAxis = locking; | 259 | LockedAngularAxis = locking; |
272 | 260 | ||
273 | if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) | 261 | EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() |
274 | { | 262 | { |
275 | // Lock that axis by creating a 6DOF constraint that has one end in the world and | 263 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); |
276 | // the other in the object. | 264 | }); |
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 | 265 | ||
324 | axisConstrainer.RecomputeConstraintVariables(RawMass); | 266 | // Update parameters so the new actor's Refresh() action is called at the right time. |
325 | }); | 267 | PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() |
326 | } | ||
327 | else | ||
328 | { | 268 | { |
329 | // Everything seems unlocked | 269 | UpdatePhysicalParameters(); |
330 | CleanUpLockAxisPhysicals(false /* inTaintTime */); | 270 | }); |
331 | } | ||
332 | 271 | ||
333 | return; | 272 | return; |
334 | } | 273 | } |
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 | 274 | ||
353 | public override OMV.Vector3 RawPosition | 275 | public override OMV.Vector3 RawPosition |
354 | { | 276 | { |
@@ -372,7 +294,7 @@ public class BSPrim : BSPhysObject | |||
372 | _position = value; | 294 | _position = value; |
373 | PositionSanityCheck(false); | 295 | PositionSanityCheck(false); |
374 | 296 | ||
375 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 297 | PhysScene.TaintedObject("BSPrim.setPosition", delegate() |
376 | { | 298 | { |
377 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 299 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
378 | ForcePosition = _position; | 300 | ForcePosition = _position; |
@@ -382,14 +304,14 @@ public class BSPrim : BSPhysObject | |||
382 | 304 | ||
383 | public override OMV.Vector3 ForcePosition { | 305 | public override OMV.Vector3 ForcePosition { |
384 | get { | 306 | get { |
385 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 307 | _position = PhysScene.PE.GetPosition(PhysBody); |
386 | return _position; | 308 | return _position; |
387 | } | 309 | } |
388 | set { | 310 | set { |
389 | _position = value; | 311 | _position = value; |
390 | if (PhysBody.HasPhysicalBody) | 312 | if (PhysBody.HasPhysicalBody) |
391 | { | 313 | { |
392 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 314 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
393 | ActivateIfPhysical(false); | 315 | ActivateIfPhysical(false); |
394 | } | 316 | } |
395 | } | 317 | } |
@@ -406,7 +328,7 @@ public class BSPrim : BSPhysObject | |||
406 | if (!IsPhysicallyActive) | 328 | if (!IsPhysicallyActive) |
407 | return ret; | 329 | return ret; |
408 | 330 | ||
409 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | 331 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
410 | { | 332 | { |
411 | // The physical object is out of the known/simulated area. | 333 | // The physical object is out of the known/simulated area. |
412 | // Upper levels of code will handle the transition to other areas so, for | 334 | // Upper levels of code will handle the transition to other areas so, for |
@@ -414,7 +336,7 @@ public class BSPrim : BSPhysObject | |||
414 | return ret; | 336 | return ret; |
415 | } | 337 | } |
416 | 338 | ||
417 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); | 339 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
418 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 340 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
419 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); | 341 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); |
420 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | 342 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) |
@@ -435,7 +357,7 @@ public class BSPrim : BSPhysObject | |||
435 | 357 | ||
436 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 358 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
437 | { | 359 | { |
438 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 360 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
439 | // TODO: a floating motor so object will bob in the water | 361 | // TODO: a floating motor so object will bob in the water |
440 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | 362 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
441 | { | 363 | { |
@@ -443,7 +365,7 @@ public class BSPrim : BSPhysObject | |||
443 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | 365 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
444 | 366 | ||
445 | // Apply upforce and overcome gravity. | 367 | // Apply upforce and overcome gravity. |
446 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | 368 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; |
447 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | 369 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); |
448 | AddForce(correctionForce, false, inTaintTime); | 370 | AddForce(correctionForce, false, inTaintTime); |
449 | ret = true; | 371 | ret = true; |
@@ -471,9 +393,9 @@ public class BSPrim : BSPhysObject | |||
471 | ZeroMotion(inTaintTime); | 393 | ZeroMotion(inTaintTime); |
472 | ret = true; | 394 | ret = true; |
473 | } | 395 | } |
474 | if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity) | 396 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) |
475 | { | 397 | { |
476 | _velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity); | 398 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
477 | ret = true; | 399 | ret = true; |
478 | } | 400 | } |
479 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | 401 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) |
@@ -498,7 +420,7 @@ public class BSPrim : BSPhysObject | |||
498 | get { return _mass; } | 420 | get { return _mass; } |
499 | } | 421 | } |
500 | // used when we only want this prim's mass and not the linkset thing | 422 | // used when we only want this prim's mass and not the linkset thing |
501 | public override float RawMass { | 423 | public override float RawMass { |
502 | get { return _mass; } | 424 | get { return _mass; } |
503 | } | 425 | } |
504 | // Set the physical mass to the passed mass. | 426 | // Set the physical mass to the passed mass. |
@@ -509,10 +431,10 @@ public class BSPrim : BSPhysObject | |||
509 | { | 431 | { |
510 | if (IsStatic) | 432 | if (IsStatic) |
511 | { | 433 | { |
512 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); | 434 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); |
513 | Inertia = OMV.Vector3.Zero; | 435 | Inertia = OMV.Vector3.Zero; |
514 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); | 436 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
515 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 437 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
516 | } | 438 | } |
517 | else | 439 | else |
518 | { | 440 | { |
@@ -521,16 +443,16 @@ public class BSPrim : BSPhysObject | |||
521 | // Changing interesting properties doesn't change proxy and collision cache | 443 | // Changing interesting properties doesn't change proxy and collision cache |
522 | // information. The Bullet solution is to re-add the object to the world | 444 | // information. The Bullet solution is to re-add the object to the world |
523 | // after parameters are changed. | 445 | // after parameters are changed. |
524 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 446 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
525 | } | 447 | } |
526 | 448 | ||
527 | // The computation of mass props requires gravity to be set on the object. | 449 | // The computation of mass props requires gravity to be set on the object. |
528 | Gravity = ComputeGravity(Buoyancy); | 450 | Gravity = ComputeGravity(Buoyancy); |
529 | PhysicsScene.PE.SetGravity(PhysBody, Gravity); | 451 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
530 | 452 | ||
531 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 453 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
532 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | 454 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); |
533 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 455 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
534 | 456 | ||
535 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", | 457 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", |
536 | LocalID, physMass, Inertia, Gravity, inWorld); | 458 | LocalID, physMass, Inertia, Gravity, inWorld); |
@@ -546,7 +468,7 @@ public class BSPrim : BSPhysObject | |||
546 | // Return what gravity should be set to this very moment | 468 | // Return what gravity should be set to this very moment |
547 | public OMV.Vector3 ComputeGravity(float buoyancy) | 469 | public OMV.Vector3 ComputeGravity(float buoyancy) |
548 | { | 470 | { |
549 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | 471 | OMV.Vector3 ret = PhysScene.DefaultGravity; |
550 | 472 | ||
551 | if (!IsStatic) | 473 | if (!IsStatic) |
552 | { | 474 | { |
@@ -570,95 +492,63 @@ public class BSPrim : BSPhysObject | |||
570 | } | 492 | } |
571 | 493 | ||
572 | public override OMV.Vector3 Force { | 494 | public override OMV.Vector3 Force { |
573 | get { return _force; } | 495 | get { return RawForce; } |
574 | set { | 496 | set { |
575 | _force = value; | 497 | RawForce = value; |
576 | if (_force != OMV.Vector3.Zero) | 498 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
577 | { | 499 | { |
578 | // If the force is non-zero, it must be reapplied each tick because | 500 | return new BSActorSetForce(PhysScene, this, SetForceActorName); |
579 | // Bullet clears the forces applied last frame. | 501 | }); |
580 | RegisterPreStepAction("BSPrim.setForce", LocalID, | ||
581 | delegate(float timeStep) | ||
582 | { | ||
583 | if (!IsPhysicallyActive || _force == OMV.Vector3.Zero) | ||
584 | { | ||
585 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
590 | if (PhysBody.HasPhysicalBody) | ||
591 | { | ||
592 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
593 | ActivateIfPhysical(false); | ||
594 | } | ||
595 | } | ||
596 | ); | ||
597 | } | ||
598 | else | ||
599 | { | ||
600 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
601 | } | ||
602 | } | 502 | } |
603 | } | 503 | } |
604 | 504 | ||
605 | public override int VehicleType { | 505 | public override int VehicleType { |
606 | get { | 506 | get { |
607 | return (int)VehicleController.Type; // if we are a vehicle, return that type | 507 | return (int)VehicleActor.Type; |
608 | } | 508 | } |
609 | set { | 509 | set { |
610 | Vehicle type = (Vehicle)value; | 510 | Vehicle type = (Vehicle)value; |
611 | 511 | ||
612 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 512 | PhysScene.TaintedObject("setVehicleType", delegate() |
613 | { | 513 | { |
614 | // Done at taint time so we're sure the physics engine is not using the variables | 514 | // Some vehicle scripts change vehicle type on the fly as an easy way to |
615 | // Vehicle code changes the parameters for this vehicle type. | 515 | // change all the parameters. Like a plane changing to CAR when on the |
616 | VehicleController.ProcessTypeChange(type); | 516 | // ground. In this case, don't want to zero motion. |
517 | // ZeroMotion(true /* inTaintTime */); | ||
518 | VehicleActor.ProcessTypeChange(type); | ||
617 | ActivateIfPhysical(false); | 519 | ActivateIfPhysical(false); |
618 | |||
619 | // If an active vehicle, register the vehicle code to be called before each step | ||
620 | if (VehicleController.Type == Vehicle.TYPE_NONE) | ||
621 | { | ||
622 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
623 | UnRegisterPostStepAction("BSPrim.Vehicle", LocalID); | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, VehicleController.Step); | ||
628 | RegisterPostStepAction("BSPrim.Vehicle", LocalID, VehicleController.PostStep); | ||
629 | } | ||
630 | }); | 520 | }); |
631 | } | 521 | } |
632 | } | 522 | } |
633 | public override void VehicleFloatParam(int param, float value) | 523 | public override void VehicleFloatParam(int param, float value) |
634 | { | 524 | { |
635 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 525 | PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
636 | { | 526 | { |
637 | VehicleController.ProcessFloatVehicleParam((Vehicle)param, value); | 527 | VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); |
638 | ActivateIfPhysical(false); | 528 | ActivateIfPhysical(false); |
639 | }); | 529 | }); |
640 | } | 530 | } |
641 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 531 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
642 | { | 532 | { |
643 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 533 | PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
644 | { | 534 | { |
645 | VehicleController.ProcessVectorVehicleParam((Vehicle)param, value); | 535 | VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); |
646 | ActivateIfPhysical(false); | 536 | ActivateIfPhysical(false); |
647 | }); | 537 | }); |
648 | } | 538 | } |
649 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 539 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
650 | { | 540 | { |
651 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 541 | PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
652 | { | 542 | { |
653 | VehicleController.ProcessRotationVehicleParam((Vehicle)param, rotation); | 543 | VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); |
654 | ActivateIfPhysical(false); | 544 | ActivateIfPhysical(false); |
655 | }); | 545 | }); |
656 | } | 546 | } |
657 | public override void VehicleFlags(int param, bool remove) | 547 | public override void VehicleFlags(int param, bool remove) |
658 | { | 548 | { |
659 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 549 | PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
660 | { | 550 | { |
661 | VehicleController.ProcessVehicleFlags(param, remove); | 551 | VehicleActor.ProcessVehicleFlags(param, remove); |
662 | }); | 552 | }); |
663 | } | 553 | } |
664 | 554 | ||
@@ -668,7 +558,7 @@ public class BSPrim : BSPhysObject | |||
668 | if (_isVolumeDetect != newValue) | 558 | if (_isVolumeDetect != newValue) |
669 | { | 559 | { |
670 | _isVolumeDetect = newValue; | 560 | _isVolumeDetect = newValue; |
671 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | 561 | PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
672 | { | 562 | { |
673 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | 563 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); |
674 | SetObjectDynamic(true); | 564 | SetObjectDynamic(true); |
@@ -679,7 +569,7 @@ public class BSPrim : BSPhysObject | |||
679 | public override void SetMaterial(int material) | 569 | public override void SetMaterial(int material) |
680 | { | 570 | { |
681 | base.SetMaterial(material); | 571 | base.SetMaterial(material); |
682 | PhysicsScene.TaintedObject("BSPrim.SetMaterial", delegate() | 572 | PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() |
683 | { | 573 | { |
684 | UpdatePhysicalParameters(); | 574 | UpdatePhysicalParameters(); |
685 | }); | 575 | }); |
@@ -692,7 +582,7 @@ public class BSPrim : BSPhysObject | |||
692 | if (base.Friction != value) | 582 | if (base.Friction != value) |
693 | { | 583 | { |
694 | base.Friction = value; | 584 | base.Friction = value; |
695 | PhysicsScene.TaintedObject("BSPrim.setFriction", delegate() | 585 | PhysScene.TaintedObject("BSPrim.setFriction", delegate() |
696 | { | 586 | { |
697 | UpdatePhysicalParameters(); | 587 | UpdatePhysicalParameters(); |
698 | }); | 588 | }); |
@@ -707,7 +597,7 @@ public class BSPrim : BSPhysObject | |||
707 | if (base.Restitution != value) | 597 | if (base.Restitution != value) |
708 | { | 598 | { |
709 | base.Restitution = value; | 599 | base.Restitution = value; |
710 | PhysicsScene.TaintedObject("BSPrim.setRestitution", delegate() | 600 | PhysScene.TaintedObject("BSPrim.setRestitution", delegate() |
711 | { | 601 | { |
712 | UpdatePhysicalParameters(); | 602 | UpdatePhysicalParameters(); |
713 | }); | 603 | }); |
@@ -724,7 +614,7 @@ public class BSPrim : BSPhysObject | |||
724 | if (base.Density != value) | 614 | if (base.Density != value) |
725 | { | 615 | { |
726 | base.Density = value; | 616 | base.Density = value; |
727 | PhysicsScene.TaintedObject("BSPrim.setDensity", delegate() | 617 | PhysScene.TaintedObject("BSPrim.setDensity", delegate() |
728 | { | 618 | { |
729 | UpdatePhysicalParameters(); | 619 | UpdatePhysicalParameters(); |
730 | }); | 620 | }); |
@@ -739,70 +629,47 @@ public class BSPrim : BSPhysObject | |||
739 | if (base.GravModifier != value) | 629 | if (base.GravModifier != value) |
740 | { | 630 | { |
741 | base.GravModifier = value; | 631 | base.GravModifier = value; |
742 | PhysicsScene.TaintedObject("BSPrim.setGravityModifier", delegate() | 632 | PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() |
743 | { | 633 | { |
744 | UpdatePhysicalParameters(); | 634 | UpdatePhysicalParameters(); |
745 | }); | 635 | }); |
746 | } | 636 | } |
747 | } | 637 | } |
748 | } | 638 | } |
749 | public override OMV.Vector3 RawVelocity | ||
750 | { | ||
751 | get { return _velocity; } | ||
752 | set { _velocity = value; } | ||
753 | } | ||
754 | public override OMV.Vector3 Velocity { | 639 | public override OMV.Vector3 Velocity { |
755 | get { return _velocity; } | 640 | get { return RawVelocity; } |
756 | set { | 641 | set { |
757 | _velocity = value; | 642 | RawVelocity = value; |
758 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 643 | PhysScene.TaintedObject("BSPrim.setVelocity", delegate() |
759 | { | 644 | { |
760 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 645 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
761 | ForceVelocity = _velocity; | 646 | ForceVelocity = RawVelocity; |
762 | }); | 647 | }); |
763 | } | 648 | } |
764 | } | 649 | } |
765 | public override OMV.Vector3 ForceVelocity { | 650 | public override OMV.Vector3 ForceVelocity { |
766 | get { return _velocity; } | 651 | get { return RawVelocity; } |
767 | set { | 652 | set { |
768 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | 653 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
769 | 654 | ||
770 | _velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); | 655 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
771 | if (PhysBody.HasPhysicalBody) | 656 | if (PhysBody.HasPhysicalBody) |
772 | { | 657 | { |
773 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); | 658 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
774 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 659 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
775 | ActivateIfPhysical(false); | 660 | ActivateIfPhysical(false); |
776 | } | 661 | } |
777 | } | 662 | } |
778 | } | 663 | } |
779 | public override OMV.Vector3 Torque { | 664 | public override OMV.Vector3 Torque { |
780 | get { return _torque; } | 665 | get { return RawTorque; } |
781 | set { | 666 | set { |
782 | _torque = value; | 667 | RawTorque = value; |
783 | if (_torque != OMV.Vector3.Zero) | 668 | 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 | { | 669 | { |
803 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | 670 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); |
804 | } | 671 | }); |
805 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 672 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
806 | } | 673 | } |
807 | } | 674 | } |
808 | public override OMV.Vector3 Acceleration { | 675 | public override OMV.Vector3 Acceleration { |
@@ -823,7 +690,7 @@ public class BSPrim : BSPhysObject | |||
823 | return; | 690 | return; |
824 | _orientation = value; | 691 | _orientation = value; |
825 | 692 | ||
826 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 693 | PhysScene.TaintedObject("BSPrim.setOrientation", delegate() |
827 | { | 694 | { |
828 | ForceOrientation = _orientation; | 695 | ForceOrientation = _orientation; |
829 | }); | 696 | }); |
@@ -834,14 +701,14 @@ public class BSPrim : BSPhysObject | |||
834 | { | 701 | { |
835 | get | 702 | get |
836 | { | 703 | { |
837 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 704 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
838 | return _orientation; | 705 | return _orientation; |
839 | } | 706 | } |
840 | set | 707 | set |
841 | { | 708 | { |
842 | _orientation = value; | 709 | _orientation = value; |
843 | if (PhysBody.HasPhysicalBody) | 710 | if (PhysBody.HasPhysicalBody) |
844 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 711 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
845 | } | 712 | } |
846 | } | 713 | } |
847 | public override int PhysicsActorType { | 714 | public override int PhysicsActorType { |
@@ -854,7 +721,7 @@ public class BSPrim : BSPhysObject | |||
854 | if (_isPhysical != value) | 721 | if (_isPhysical != value) |
855 | { | 722 | { |
856 | _isPhysical = value; | 723 | _isPhysical = value; |
857 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 724 | PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
858 | { | 725 | { |
859 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 726 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
860 | SetObjectDynamic(true); | 727 | SetObjectDynamic(true); |
@@ -903,19 +770,19 @@ public class BSPrim : BSPhysObject | |||
903 | if (!PhysBody.HasPhysicalBody) | 770 | if (!PhysBody.HasPhysicalBody) |
904 | { | 771 | { |
905 | // This would only happen if updates are called for during initialization when the body is not set up yet. | 772 | // 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); | 773 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); |
907 | return; | 774 | return; |
908 | } | 775 | } |
909 | 776 | ||
910 | // Mangling all the physical properties requires the object not be in the physical world. | 777 | // 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). | 778 | // 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); | 779 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
913 | 780 | ||
914 | // Set up the object physicalness (does gravity and collisions move this object) | 781 | // Set up the object physicalness (does gravity and collisions move this object) |
915 | MakeDynamic(IsStatic); | 782 | MakeDynamic(IsStatic); |
916 | 783 | ||
917 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 784 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
918 | VehicleController.Refresh(); | 785 | PhysicalActors.Refresh(); |
919 | 786 | ||
920 | // Arrange for collision events if the simulator wants them | 787 | // Arrange for collision events if the simulator wants them |
921 | EnableCollisions(SubscribedEvents()); | 788 | EnableCollisions(SubscribedEvents()); |
@@ -926,10 +793,11 @@ public class BSPrim : BSPhysObject | |||
926 | AddObjectToPhysicalWorld(); | 793 | AddObjectToPhysicalWorld(); |
927 | 794 | ||
928 | // Rebuild its shape | 795 | // Rebuild its shape |
929 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 796 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
930 | 797 | ||
931 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", | 798 | 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); | 799 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), |
800 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | ||
933 | } | 801 | } |
934 | 802 | ||
935 | // "Making dynamic" means changing to and from static. | 803 | // "Making dynamic" means changing to and from static. |
@@ -942,28 +810,28 @@ public class BSPrim : BSPhysObject | |||
942 | if (makeStatic) | 810 | if (makeStatic) |
943 | { | 811 | { |
944 | // Become a Bullet 'static' object type | 812 | // Become a Bullet 'static' object type |
945 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 813 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
946 | // Stop all movement | 814 | // Stop all movement |
947 | ZeroMotion(true); | 815 | ZeroMotion(true); |
948 | 816 | ||
949 | // Set various physical properties so other object interact properly | 817 | // Set various physical properties so other object interact properly |
950 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 818 | PhysScene.PE.SetFriction(PhysBody, Friction); |
951 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 819 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
952 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 820 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
953 | 821 | ||
954 | // Mass is zero which disables a bunch of physics stuff in Bullet | 822 | // Mass is zero which disables a bunch of physics stuff in Bullet |
955 | UpdatePhysicalMassProperties(0f, false); | 823 | UpdatePhysicalMassProperties(0f, false); |
956 | // Set collision detection parameters | 824 | // Set collision detection parameters |
957 | if (BSParam.CcdMotionThreshold > 0f) | 825 | if (BSParam.CcdMotionThreshold > 0f) |
958 | { | 826 | { |
959 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 827 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
960 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 828 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
961 | } | 829 | } |
962 | 830 | ||
963 | // The activation state is 'disabled' so Bullet will not try to act on it. | 831 | // The activation state is 'disabled' so Bullet will not try to act on it. |
964 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); | 832 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
965 | // Start it out sleeping and physical actions could wake it up. | 833 | // Start it out sleeping and physical actions could wake it up. |
966 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); | 834 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
967 | 835 | ||
968 | // This collides like a static object | 836 | // This collides like a static object |
969 | PhysBody.collisionType = CollisionType.Static; | 837 | PhysBody.collisionType = CollisionType.Static; |
@@ -971,11 +839,11 @@ public class BSPrim : BSPhysObject | |||
971 | else | 839 | else |
972 | { | 840 | { |
973 | // Not a Bullet static object | 841 | // Not a Bullet static object |
974 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 842 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
975 | 843 | ||
976 | // Set various physical properties so other object interact properly | 844 | // Set various physical properties so other object interact properly |
977 | PhysicsScene.PE.SetFriction(PhysBody, Friction); | 845 | PhysScene.PE.SetFriction(PhysBody, Friction); |
978 | PhysicsScene.PE.SetRestitution(PhysBody, Restitution); | 846 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
979 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); | 847 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); |
980 | 848 | ||
981 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 849 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
@@ -984,7 +852,7 @@ public class BSPrim : BSPhysObject | |||
984 | 852 | ||
985 | // For good measure, make sure the transform is set through to the motion state | 853 | // For good measure, make sure the transform is set through to the motion state |
986 | ForcePosition = _position; | 854 | ForcePosition = _position; |
987 | ForceVelocity = _velocity; | 855 | ForceVelocity = RawVelocity; |
988 | ForceRotationalVelocity = _rotationalVelocity; | 856 | ForceRotationalVelocity = _rotationalVelocity; |
989 | 857 | ||
990 | // A dynamic object has mass | 858 | // A dynamic object has mass |
@@ -993,22 +861,22 @@ public class BSPrim : BSPhysObject | |||
993 | // Set collision detection parameters | 861 | // Set collision detection parameters |
994 | if (BSParam.CcdMotionThreshold > 0f) | 862 | if (BSParam.CcdMotionThreshold > 0f) |
995 | { | 863 | { |
996 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 864 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
997 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 865 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
998 | } | 866 | } |
999 | 867 | ||
1000 | // Various values for simulation limits | 868 | // Various values for simulation limits |
1001 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); | 869 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
1002 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); | 870 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
1003 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | 871 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
1004 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 872 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
1005 | 873 | ||
1006 | // This collides like an object. | 874 | // This collides like an object. |
1007 | PhysBody.collisionType = CollisionType.Dynamic; | 875 | PhysBody.collisionType = CollisionType.Dynamic; |
1008 | 876 | ||
1009 | // Force activation of the object so Bullet will act on it. | 877 | // Force activation of the object so Bullet will act on it. |
1010 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 878 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
1011 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 879 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
1012 | } | 880 | } |
1013 | } | 881 | } |
1014 | 882 | ||
@@ -1018,7 +886,7 @@ public class BSPrim : BSPhysObject | |||
1018 | // the functions after this one set up the state of a possibly newly created collision body. | 886 | // the functions after this one set up the state of a possibly newly created collision body. |
1019 | private void MakeSolid(bool makeSolid) | 887 | private void MakeSolid(bool makeSolid) |
1020 | { | 888 | { |
1021 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); | 889 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); |
1022 | if (makeSolid) | 890 | if (makeSolid) |
1023 | { | 891 | { |
1024 | // Verify the previous code created the correct shape for this type of thing. | 892 | // Verify the previous code created the correct shape for this type of thing. |
@@ -1026,7 +894,7 @@ public class BSPrim : BSPhysObject | |||
1026 | { | 894 | { |
1027 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 895 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
1028 | } | 896 | } |
1029 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 897 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1030 | } | 898 | } |
1031 | else | 899 | else |
1032 | { | 900 | { |
@@ -1034,32 +902,23 @@ public class BSPrim : BSPhysObject | |||
1034 | { | 902 | { |
1035 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 903 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
1036 | } | 904 | } |
1037 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 905 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
1038 | 906 | ||
1039 | // Change collision info from a static object to a ghosty collision object | 907 | // Change collision info from a static object to a ghosty collision object |
1040 | PhysBody.collisionType = CollisionType.VolumeDetect; | 908 | PhysBody.collisionType = CollisionType.VolumeDetect; |
1041 | } | 909 | } |
1042 | } | 910 | } |
1043 | 911 | ||
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. | 912 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
1054 | private void EnableCollisions(bool wantsCollisionEvents) | 913 | private void EnableCollisions(bool wantsCollisionEvents) |
1055 | { | 914 | { |
1056 | if (wantsCollisionEvents) | 915 | if (wantsCollisionEvents) |
1057 | { | 916 | { |
1058 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 917 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1059 | } | 918 | } |
1060 | else | 919 | else |
1061 | { | 920 | { |
1062 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 921 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
1063 | } | 922 | } |
1064 | } | 923 | } |
1065 | 924 | ||
@@ -1070,7 +929,7 @@ public class BSPrim : BSPhysObject | |||
1070 | { | 929 | { |
1071 | if (PhysBody.HasPhysicalBody) | 930 | if (PhysBody.HasPhysicalBody) |
1072 | { | 931 | { |
1073 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 932 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
1074 | } | 933 | } |
1075 | else | 934 | else |
1076 | { | 935 | { |
@@ -1105,12 +964,12 @@ public class BSPrim : BSPhysObject | |||
1105 | public override bool FloatOnWater { | 964 | public override bool FloatOnWater { |
1106 | set { | 965 | set { |
1107 | _floatOnWater = value; | 966 | _floatOnWater = value; |
1108 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 967 | PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
1109 | { | 968 | { |
1110 | if (_floatOnWater) | 969 | if (_floatOnWater) |
1111 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 970 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1112 | else | 971 | else |
1113 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 972 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
1114 | }); | 973 | }); |
1115 | } | 974 | } |
1116 | } | 975 | } |
@@ -1122,7 +981,7 @@ public class BSPrim : BSPhysObject | |||
1122 | _rotationalVelocity = value; | 981 | _rotationalVelocity = value; |
1123 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | 982 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); |
1124 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 983 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
1125 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 984 | PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
1126 | { | 985 | { |
1127 | ForceRotationalVelocity = _rotationalVelocity; | 986 | ForceRotationalVelocity = _rotationalVelocity; |
1128 | }); | 987 | }); |
@@ -1137,7 +996,7 @@ public class BSPrim : BSPhysObject | |||
1137 | if (PhysBody.HasPhysicalBody) | 996 | if (PhysBody.HasPhysicalBody) |
1138 | { | 997 | { |
1139 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 998 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
1140 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 999 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
1141 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 1000 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
1142 | ActivateIfPhysical(false); | 1001 | ActivateIfPhysical(false); |
1143 | } | 1002 | } |
@@ -1153,7 +1012,7 @@ public class BSPrim : BSPhysObject | |||
1153 | get { return _buoyancy; } | 1012 | get { return _buoyancy; } |
1154 | set { | 1013 | set { |
1155 | _buoyancy = value; | 1014 | _buoyancy = value; |
1156 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 1015 | PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
1157 | { | 1016 | { |
1158 | ForceBuoyancy = _buoyancy; | 1017 | ForceBuoyancy = _buoyancy; |
1159 | }); | 1018 | }); |
@@ -1171,78 +1030,13 @@ public class BSPrim : BSPhysObject | |||
1171 | } | 1030 | } |
1172 | } | 1031 | } |
1173 | 1032 | ||
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 { | 1033 | public override bool PIDActive { |
1186 | set { | 1034 | set { |
1187 | if (value) | 1035 | base.MoveToTargetActive = value; |
1188 | { | 1036 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() |
1189 | // We're taking over after this. | ||
1190 | ZeroMotion(true); | ||
1191 | |||
1192 | _targetMotor = new BSVMotor("BSPrim.PIDTarget", | ||
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 | |||
1224 | // If we are very close to our target, turn off the movement motor. | ||
1225 | if (_targetMotor.ErrorIsZero()) | ||
1226 | { | ||
1227 | DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}", | ||
1228 | LocalID, movePosition, RawPosition, Mass); | ||
1229 | ForcePosition = _targetMotor.TargetValue; | ||
1230 | _targetMotor.Enabled = false; | ||
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 | { | 1037 | { |
1243 | // Stop any targetting | 1038 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); |
1244 | UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID); | 1039 | }); |
1245 | } | ||
1246 | } | 1040 | } |
1247 | } | 1041 | } |
1248 | 1042 | ||
@@ -1250,94 +1044,20 @@ public class BSPrim : BSPhysObject | |||
1250 | // Hover Height will override MoveTo target's Z | 1044 | // Hover Height will override MoveTo target's Z |
1251 | public override bool PIDHoverActive { | 1045 | public override bool PIDHoverActive { |
1252 | set { | 1046 | set { |
1253 | if (value) | 1047 | base.HoverActive = value; |
1254 | { | 1048 | EnableActor(HoverActive, HoverActorName, delegate() |
1255 | // Turning the target on | ||
1256 | _hoverMotor = new BSFMotor("BSPrim.Hover", | ||
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 | { | 1049 | { |
1288 | UnRegisterPreStepAction("BSPrim.Hover", LocalID); | 1050 | return new BSActorHover(PhysScene, this, HoverActorName); |
1289 | } | 1051 | }); |
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 | } | 1052 | } |
1325 | return ret; | ||
1326 | } | 1053 | } |
1327 | 1054 | ||
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) { | 1055 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
1336 | // Per documentation, max force is limited. | 1056 | // Per documentation, max force is limited. |
1337 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | 1057 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
1338 | 1058 | ||
1339 | // Since this force is being applied in only one step, make this a force per second. | 1059 | // Since this force is being applied in only one step, make this a force per second. |
1340 | addForce /= PhysicsScene.LastTimeStep; | 1060 | addForce /= PhysScene.LastTimeStep; |
1341 | AddForce(addForce, pushforce, false /* inTaintTime */); | 1061 | AddForce(addForce, pushforce, false /* inTaintTime */); |
1342 | } | 1062 | } |
1343 | 1063 | ||
@@ -1352,13 +1072,13 @@ public class BSPrim : BSPhysObject | |||
1352 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | 1072 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
1353 | 1073 | ||
1354 | OMV.Vector3 addForce = force; | 1074 | OMV.Vector3 addForce = force; |
1355 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | 1075 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
1356 | { | 1076 | { |
1357 | // Bullet adds this central force to the total force for this tick | 1077 | // Bullet adds this central force to the total force for this tick |
1358 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | 1078 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
1359 | if (PhysBody.HasPhysicalBody) | 1079 | if (PhysBody.HasPhysicalBody) |
1360 | { | 1080 | { |
1361 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 1081 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
1362 | ActivateIfPhysical(false); | 1082 | ActivateIfPhysical(false); |
1363 | } | 1083 | } |
1364 | }); | 1084 | }); |
@@ -1380,13 +1100,13 @@ public class BSPrim : BSPhysObject | |||
1380 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); | 1100 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); |
1381 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | 1101 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); |
1382 | 1102 | ||
1383 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() | 1103 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() |
1384 | { | 1104 | { |
1385 | // Bullet adds this impulse immediately to the velocity | 1105 | // Bullet adds this impulse immediately to the velocity |
1386 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | 1106 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); |
1387 | if (PhysBody.HasPhysicalBody) | 1107 | if (PhysBody.HasPhysicalBody) |
1388 | { | 1108 | { |
1389 | PhysicsScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | 1109 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); |
1390 | ActivateIfPhysical(false); | 1110 | ActivateIfPhysical(false); |
1391 | } | 1111 | } |
1392 | }); | 1112 | }); |
@@ -1399,20 +1119,18 @@ public class BSPrim : BSPhysObject | |||
1399 | } | 1119 | } |
1400 | } | 1120 | } |
1401 | 1121 | ||
1402 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1122 | // BSPhysObject.AddAngularForce() |
1403 | AddAngularForce(force, pushforce, false); | 1123 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
1404 | } | ||
1405 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1406 | { | 1124 | { |
1407 | if (force.IsFinite()) | 1125 | if (force.IsFinite()) |
1408 | { | 1126 | { |
1409 | OMV.Vector3 angForce = force; | 1127 | OMV.Vector3 angForce = force; |
1410 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | 1128 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
1411 | { | 1129 | { |
1412 | if (PhysBody.HasPhysicalBody) | 1130 | if (PhysBody.HasPhysicalBody) |
1413 | { | 1131 | { |
1414 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); | 1132 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); |
1415 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | 1133 | PhysScene.PE.ApplyTorque(PhysBody, angForce); |
1416 | ActivateIfPhysical(false); | 1134 | ActivateIfPhysical(false); |
1417 | } | 1135 | } |
1418 | }); | 1136 | }); |
@@ -1431,11 +1149,11 @@ public class BSPrim : BSPhysObject | |||
1431 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1149 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1432 | { | 1150 | { |
1433 | OMV.Vector3 applyImpulse = impulse; | 1151 | OMV.Vector3 applyImpulse = impulse; |
1434 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1152 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1435 | { | 1153 | { |
1436 | if (PhysBody.HasPhysicalBody) | 1154 | if (PhysBody.HasPhysicalBody) |
1437 | { | 1155 | { |
1438 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | 1156 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); |
1439 | ActivateIfPhysical(false); | 1157 | ActivateIfPhysical(false); |
1440 | } | 1158 | } |
1441 | }); | 1159 | }); |
@@ -1721,9 +1439,9 @@ public class BSPrim : BSPhysObject | |||
1721 | volume *= (profileEnd - profileBegin); | 1439 | volume *= (profileEnd - profileBegin); |
1722 | 1440 | ||
1723 | returnMass = Density * BSParam.DensityScaleFactor * volume; | 1441 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
1724 | DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1725 | 1442 | ||
1726 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | 1443 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
1444 | // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1727 | 1445 | ||
1728 | return returnMass; | 1446 | return returnMass; |
1729 | }// end CalculateMass | 1447 | }// end CalculateMass |
@@ -1736,13 +1454,14 @@ public class BSPrim : BSPhysObject | |||
1736 | { | 1454 | { |
1737 | // Create the correct physical representation for this type of object. | 1455 | // Create the correct physical representation for this type of object. |
1738 | // Updates base.PhysBody and base.PhysShape with the new information. | 1456 | // Updates base.PhysBody and base.PhysShape with the new information. |
1739 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1457 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
1740 | PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1458 | PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) |
1741 | { | 1459 | { |
1742 | // Called if the current prim body is about to be destroyed. | 1460 | // Called if the current prim body is about to be destroyed. |
1743 | // Remove all the physical dependencies on the old body. | 1461 | // 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, ...) | 1462 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1745 | RemoveBodyDependencies(); | 1463 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. |
1464 | RemoveDependencies(); | ||
1746 | }); | 1465 | }); |
1747 | 1466 | ||
1748 | // Make sure the properties are set on the new object | 1467 | // Make sure the properties are set on the new object |
@@ -1750,24 +1469,19 @@ public class BSPrim : BSPhysObject | |||
1750 | return; | 1469 | return; |
1751 | } | 1470 | } |
1752 | 1471 | ||
1753 | protected virtual void RemoveBodyDependencies() | 1472 | // Called at taint-time |
1473 | protected virtual void RemoveDependencies() | ||
1754 | { | 1474 | { |
1755 | VehicleController.RemoveBodyDependencies(this); | 1475 | PhysicalActors.RemoveDependencies(); |
1756 | } | 1476 | } |
1757 | 1477 | ||
1758 | // The physics engine says that properties have updated. Update same and inform | 1478 | // The physics engine says that properties have updated. Update same and inform |
1759 | // the world that things have changed. | 1479 | // the world that things have changed. |
1760 | public override void UpdateProperties(EntityProperties entprop) | 1480 | public override void UpdateProperties(EntityProperties entprop) |
1761 | { | 1481 | { |
1482 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. | ||
1762 | TriggerPreUpdatePropertyAction(ref entprop); | 1483 | TriggerPreUpdatePropertyAction(ref entprop); |
1763 | 1484 | ||
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 | 1485 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1772 | 1486 | ||
1773 | // Assign directly to the local variables so the normal set actions do not happen | 1487 | // Assign directly to the local variables so the normal set actions do not happen |
@@ -1775,8 +1489,8 @@ public class BSPrim : BSPhysObject | |||
1775 | _orientation = entprop.Rotation; | 1489 | _orientation = entprop.Rotation; |
1776 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be | 1490 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1777 | // very sensitive to velocity changes. | 1491 | // very sensitive to velocity changes. |
1778 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) | 1492 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
1779 | _velocity = entprop.Velocity; | 1493 | RawVelocity = entprop.Velocity; |
1780 | _acceleration = entprop.Acceleration; | 1494 | _acceleration = entprop.Acceleration; |
1781 | _rotationalVelocity = entprop.RotationalVelocity; | 1495 | _rotationalVelocity = entprop.RotationalVelocity; |
1782 | 1496 | ||
@@ -1786,7 +1500,7 @@ public class BSPrim : BSPhysObject | |||
1786 | if (PositionSanityCheck(true /* inTaintTime */ )) | 1500 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1787 | { | 1501 | { |
1788 | entprop.Position = _position; | 1502 | entprop.Position = _position; |
1789 | entprop.Velocity = _velocity; | 1503 | entprop.Velocity = RawVelocity; |
1790 | entprop.RotationalVelocity = _rotationalVelocity; | 1504 | entprop.RotationalVelocity = _rotationalVelocity; |
1791 | entprop.Acceleration = _acceleration; | 1505 | entprop.Acceleration = _acceleration; |
1792 | } | 1506 | } |
@@ -1798,16 +1512,9 @@ public class BSPrim : BSPhysObject | |||
1798 | LastEntityProperties = CurrentEntityProperties; | 1512 | LastEntityProperties = CurrentEntityProperties; |
1799 | CurrentEntityProperties = entprop; | 1513 | CurrentEntityProperties = entprop; |
1800 | 1514 | ||
1801 | base.RequestPhysicsterseUpdate(); | 1515 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. |
1802 | /* | 1516 | |
1803 | else | 1517 | PhysScene.PostUpdate(this); |
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 | } | 1518 | } |
1812 | } | 1519 | } |
1813 | } | 1520 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs index f1c3b5c..f5ee671 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs | |||
@@ -78,14 +78,16 @@ public class BSPrimDisplaced : BSPrim | |||
78 | // Set this sets and computes the displacement from the passed prim to the center-of-mass. | 78 | // 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. | 79 | // 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). | 80 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). |
81 | public virtual void SetEffectiveCenterOfMassW(Vector3 centerOfMassDisplacement) | 81 | public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) |
82 | { | 82 | { |
83 | Vector3 comDisp; | 83 | Vector3 comDisp; |
84 | if (UserSetCenterOfMass.HasValue) | 84 | if (UserSetCenterOfMassDisplacement.HasValue) |
85 | comDisp = (OMV.Vector3)UserSetCenterOfMass; | 85 | comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; |
86 | else | 86 | else |
87 | comDisp = centerOfMassDisplacement; | 87 | comDisp = centerOfMassDisplacement; |
88 | 88 | ||
89 | DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", | ||
90 | LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); | ||
89 | if (comDisp == Vector3.Zero) | 91 | if (comDisp == Vector3.Zero) |
90 | { | 92 | { |
91 | // If there is no diplacement. Things get reset. | 93 | // If there is no diplacement. Things get reset. |
@@ -107,9 +109,15 @@ public class BSPrimDisplaced : BSPrim | |||
107 | set | 109 | set |
108 | { | 110 | { |
109 | if (PositionDisplacement != OMV.Vector3.Zero) | 111 | if (PositionDisplacement != OMV.Vector3.Zero) |
110 | base.ForcePosition = value - (PositionDisplacement * RawOrientation); | 112 | { |
113 | OMV.Vector3 displacedPos = value - (PositionDisplacement * RawOrientation); | ||
114 | DetailLog("{0},BSPrimDisplaced.ForcePosition,val={1},disp={2},newPos={3}", LocalID, value, PositionDisplacement, displacedPos); | ||
115 | base.ForcePosition = displacedPos; | ||
116 | } | ||
111 | else | 117 | else |
118 | { | ||
112 | base.ForcePosition = value; | 119 | base.ForcePosition = value; |
120 | } | ||
113 | } | 121 | } |
114 | } | 122 | } |
115 | 123 | ||
@@ -118,6 +126,7 @@ public class BSPrimDisplaced : BSPrim | |||
118 | get { return base.ForceOrientation; } | 126 | get { return base.ForceOrientation; } |
119 | set | 127 | set |
120 | { | 128 | { |
129 | // TODO: | ||
121 | base.ForceOrientation = value; | 130 | base.ForceOrientation = value; |
122 | } | 131 | } |
123 | } | 132 | } |
@@ -143,7 +152,10 @@ public class BSPrimDisplaced : BSPrim | |||
143 | { | 152 | { |
144 | // Correct for any rotation around the center-of-mass | 153 | // Correct for any rotation around the center-of-mass |
145 | // TODO!!! | 154 | // TODO!!! |
146 | entprop.Position = entprop.Position + (PositionDisplacement * entprop.Rotation); | 155 | |
156 | OMV.Vector3 displacedPos = entprop.Position + (PositionDisplacement * entprop.Rotation); | ||
157 | DetailLog("{0},BSPrimDisplaced.ForcePosition,physPos={1},disp={2},newPos={3}", LocalID, entprop.Position, PositionDisplacement, displacedPos); | ||
158 | entprop.Position = displacedPos; | ||
147 | // entprop.Rotation = something; | 159 | // entprop.Rotation = something; |
148 | } | 160 | } |
149 | 161 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index d65d407..235da78 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -47,9 +47,9 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | 48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) |
49 | { | 49 | { |
50 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 50 | Linkset = BSLinkset.Factory(PhysScene, this); |
51 | 51 | ||
52 | PhysicsScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() | 52 | PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() |
53 | { | 53 | { |
54 | Linkset.Refresh(this); | 54 | Linkset.Refresh(this); |
55 | }); | 55 | }); |
@@ -61,9 +61,6 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
61 | base.Destroy(); | 61 | base.Destroy(); |
62 | } | 62 | } |
63 | 63 | ||
64 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
65 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
66 | |||
67 | public override void link(Manager.PhysicsActor obj) | 64 | public override void link(Manager.PhysicsActor obj) |
68 | { | 65 | { |
69 | BSPrimLinkable parent = obj as BSPrimLinkable; | 66 | BSPrimLinkable parent = obj as BSPrimLinkable; |
@@ -102,7 +99,7 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
102 | set | 99 | set |
103 | { | 100 | { |
104 | base.Position = value; | 101 | base.Position = value; |
105 | PhysicsScene.TaintedObject("BSPrimLinkset.setPosition", delegate() | 102 | PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate() |
106 | { | 103 | { |
107 | Linkset.UpdateProperties(UpdatedProperties.Position, this); | 104 | Linkset.UpdateProperties(UpdatedProperties.Position, this); |
108 | }); | 105 | }); |
@@ -116,7 +113,7 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
116 | set | 113 | set |
117 | { | 114 | { |
118 | base.Orientation = value; | 115 | base.Orientation = value; |
119 | PhysicsScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() | 116 | PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() |
120 | { | 117 | { |
121 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); | 118 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); |
122 | }); | 119 | }); |
@@ -149,10 +146,10 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
149 | } | 146 | } |
150 | 147 | ||
151 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. | 148 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. |
152 | protected override void RemoveBodyDependencies() | 149 | protected override void RemoveDependencies() |
153 | { | 150 | { |
154 | Linkset.RemoveBodyDependencies(this); | 151 | Linkset.RemoveDependencies(this); |
155 | base.RemoveBodyDependencies(); | 152 | base.RemoveDependencies(); |
156 | } | 153 | } |
157 | 154 | ||
158 | public override void UpdateProperties(EntityProperties entprop) | 155 | public override void UpdateProperties(EntityProperties entprop) |
@@ -163,6 +160,15 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
163 | // TODO: this will have to change when linksets are articulated. | 160 | // TODO: this will have to change when linksets are articulated. |
164 | base.UpdateProperties(entprop); | 161 | base.UpdateProperties(entprop); |
165 | } | 162 | } |
163 | /* | ||
164 | else | ||
165 | { | ||
166 | // For debugging, report the movement of children | ||
167 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
168 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
169 | entprop.Acceleration, entprop.RotationalVelocity); | ||
170 | } | ||
171 | */ | ||
166 | // The linkset might like to know about changing locations | 172 | // The linkset might like to know about changing locations |
167 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | 173 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
168 | } | 174 | } |
@@ -176,6 +182,10 @@ public class BSPrimLinkable : BSPrimDisplaced | |||
176 | { | 182 | { |
177 | return false; | 183 | return false; |
178 | } | 184 | } |
185 | |||
186 | // TODO: handle collisions of other objects with with children of linkset. | ||
187 | // This is a problem for LinksetCompound since the children are packed into the root. | ||
188 | |||
179 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | 189 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); |
180 | } | 190 | } |
181 | } | 191 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index e6aefd5..dec6b6f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -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,19 @@ 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 | |
101 | internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate() | ||
102 | |||
103 | internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to | ||
86 | 104 | ||
87 | // Physical objects can register for prestep or poststep events | 105 | // Physical objects can register for prestep or poststep events |
88 | public delegate void PreStepAction(float timeStep); | 106 | public delegate void PreStepAction(float timeStep); |
@@ -90,7 +108,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | public event PreStepAction BeforeStep; | 108 | public event PreStepAction BeforeStep; |
91 | public event PostStepAction AfterStep; | 109 | public event PostStepAction AfterStep; |
92 | 110 | ||
93 | // A value of the time now so all the collision and update routines do not have to get their own | 111 | // 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 | 112 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
95 | public int SimulationNowTime { get; private set; } | 113 | public int SimulationNowTime { get; private set; } |
96 | 114 | ||
@@ -188,6 +206,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
188 | PhysObjects = new Dictionary<uint, BSPhysObject>(); | 206 | PhysObjects = new Dictionary<uint, BSPhysObject>(); |
189 | Shapes = new BSShapeCollection(this); | 207 | Shapes = new BSShapeCollection(this); |
190 | 208 | ||
209 | m_simulatedTime = 0f; | ||
210 | LastTimeStep = 0.1f; | ||
211 | |||
191 | // Allocate pinned memory to pass parameters. | 212 | // Allocate pinned memory to pass parameters. |
192 | UnmanagedParams = new ConfigurationParameters[1]; | 213 | UnmanagedParams = new ConfigurationParameters[1]; |
193 | 214 | ||
@@ -227,10 +248,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
227 | TerrainManager = new BSTerrainManager(this); | 248 | TerrainManager = new BSTerrainManager(this); |
228 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); | 249 | TerrainManager.CreateInitialGroundPlaneAndTerrain(); |
229 | 250 | ||
230 | m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | 251 | // Put some informational messages into the log file. |
252 | m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation); | ||
231 | 253 | ||
232 | InTaintTime = false; | 254 | InTaintTime = false; |
233 | m_initialized = true; | 255 | m_initialized = true; |
256 | |||
257 | // If the physics engine runs on its own thread, start same. | ||
258 | if (BSParam.UseSeparatePhysicsThread) | ||
259 | { | ||
260 | // The physics simulation should happen independently of the heartbeat loop | ||
261 | m_physicsThread = new Thread(BulletSPluginPhysicsThread); | ||
262 | m_physicsThread.Name = BulletEngineName; | ||
263 | m_physicsThread.Start(); | ||
264 | } | ||
234 | } | 265 | } |
235 | 266 | ||
236 | // All default parameter values are set here. There should be no values set in the | 267 | // All default parameter values are set here. There should be no values set in the |
@@ -268,6 +299,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
268 | // Do any replacements in the parameters | 299 | // Do any replacements in the parameters |
269 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 300 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
270 | } | 301 | } |
302 | else | ||
303 | { | ||
304 | // Nothing in the configuration INI file so assume unmanaged and other defaults. | ||
305 | BulletEngineName = "BulletUnmanaged"; | ||
306 | m_physicsLoggingEnabled = false; | ||
307 | VehicleLoggingEnabled = false; | ||
308 | } | ||
271 | 309 | ||
272 | // The material characteristics. | 310 | // The material characteristics. |
273 | BSMaterials.InitializeFromDefaults(Params); | 311 | BSMaterials.InitializeFromDefaults(Params); |
@@ -311,11 +349,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
311 | 349 | ||
312 | switch (selectionName) | 350 | switch (selectionName) |
313 | { | 351 | { |
352 | case "bullet": | ||
314 | case "bulletunmanaged": | 353 | case "bulletunmanaged": |
315 | ret = new BSAPIUnman(engineName, this); | 354 | ret = new BSAPIUnman(engineName, this); |
316 | break; | 355 | break; |
317 | case "bulletxna": | 356 | case "bulletxna": |
318 | ret = new BSAPIXNA(engineName, this); | 357 | ret = new BSAPIXNA(engineName, this); |
358 | // Disable some features that are not implemented in BulletXNA | ||
359 | m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); | ||
360 | m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader); | ||
361 | BSParam.ShouldUseBulletHACD = false; | ||
362 | m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader); | ||
363 | BSParam.ShouldUseSingleConvexHullForPrims = false; | ||
364 | m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader); | ||
365 | BSParam.ShouldUseGImpactShapeForPrims = false; | ||
366 | m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader); | ||
367 | BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap; | ||
319 | break; | 368 | break; |
320 | } | 369 | } |
321 | 370 | ||
@@ -325,7 +374,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
325 | } | 374 | } |
326 | else | 375 | else |
327 | { | 376 | { |
328 | m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); | 377 | m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion); |
329 | } | 378 | } |
330 | 379 | ||
331 | return ret; | 380 | return ret; |
@@ -463,7 +512,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
463 | 512 | ||
464 | if (!m_initialized) return null; | 513 | if (!m_initialized) return null; |
465 | 514 | ||
466 | DetailLog("{0},BSScene.AddPrimShape,call", localID); | 515 | // DetailLog("{0},BSScene.AddPrimShape,call", localID); |
467 | 516 | ||
468 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); | 517 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); |
469 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 518 | lock (PhysObjects) PhysObjects.Add(localID, prim); |
@@ -478,25 +527,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
478 | #endregion // Prim and Avatar addition and removal | 527 | #endregion // Prim and Avatar addition and removal |
479 | 528 | ||
480 | #region Simulation | 529 | #region Simulation |
481 | // Simulate one timestep | 530 | |
531 | // Call from the simulator to send physics information to the simulator objects. | ||
532 | // This pushes all the collision and property update events into the objects in | ||
533 | // the simulator and, since it is on the heartbeat thread, there is an implicit | ||
534 | // locking of those data structures from other heartbeat events. | ||
535 | // If the physics engine is running on a separate thread, the update information | ||
536 | // will be in the ObjectsWithCollions and ObjectsWithUpdates structures. | ||
482 | public override float Simulate(float timeStep) | 537 | public override float Simulate(float timeStep) |
483 | { | 538 | { |
539 | if (!BSParam.UseSeparatePhysicsThread) | ||
540 | { | ||
541 | DoPhysicsStep(timeStep); | ||
542 | } | ||
543 | return SendUpdatesToSimulator(timeStep); | ||
544 | } | ||
545 | |||
546 | // Call the physics engine to do one 'timeStep' and collect collisions and updates | ||
547 | // into ObjectsWithCollisions and ObjectsWithUpdates data structures. | ||
548 | private void DoPhysicsStep(float timeStep) | ||
549 | { | ||
484 | // prevent simulation until we've been initialized | 550 | // prevent simulation until we've been initialized |
485 | if (!m_initialized) return 5.0f; | 551 | if (!m_initialized) return; |
486 | 552 | ||
487 | LastTimeStep = timeStep; | 553 | LastTimeStep = timeStep; |
488 | 554 | ||
489 | int updatedEntityCount = 0; | 555 | int updatedEntityCount = 0; |
490 | int collidersCount = 0; | 556 | int collidersCount = 0; |
491 | 557 | ||
492 | int beforeTime = 0; | 558 | int beforeTime = Util.EnvironmentTickCount(); |
493 | int simTime = 0; | 559 | int simTime = 0; |
494 | 560 | ||
495 | // update the prim states while we know the physics engine is not busy | ||
496 | int numTaints = _taintOperations.Count; | 561 | int numTaints = _taintOperations.Count; |
497 | |||
498 | InTaintTime = true; // Only used for debugging so locking is not necessary. | 562 | InTaintTime = true; // Only used for debugging so locking is not necessary. |
499 | 563 | ||
564 | // update the prim states while we know the physics engine is not busy | ||
500 | ProcessTaints(); | 565 | ProcessTaints(); |
501 | 566 | ||
502 | // Some of the physical objects requre individual, pre-step calls | 567 | // Some of the physical objects requre individual, pre-step calls |
@@ -519,18 +584,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
519 | int numSubSteps = 0; | 584 | int numSubSteps = 0; |
520 | try | 585 | try |
521 | { | 586 | { |
522 | if (PhysicsLogging.Enabled) | ||
523 | beforeTime = Util.EnvironmentTickCount(); | ||
524 | |||
525 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); | 587 | numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount); |
526 | 588 | ||
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 | } | 589 | } |
535 | catch (Exception e) | 590 | catch (Exception e) |
536 | { | 591 | { |
@@ -542,77 +597,62 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
542 | collidersCount = 0; | 597 | collidersCount = 0; |
543 | } | 598 | } |
544 | 599 | ||
600 | // Make the physics engine dump useful statistics periodically | ||
545 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) | 601 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
546 | PE.DumpPhysicsStatistics(World); | 602 | PE.DumpPhysicsStatistics(World); |
547 | 603 | ||
548 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 604 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
549 | SimulationNowTime = Util.EnvironmentTickCount(); | 605 | SimulationNowTime = Util.EnvironmentTickCount(); |
550 | 606 | ||
551 | // If there were collisions, process them by sending the event to the prim. | 607 | // Send collision information to the colliding objects. The objects decide if the collision |
552 | // Collisions must be processed before updates. | 608 | // is 'real' (like linksets don't collide with themselves) and the individual objects |
553 | if (collidersCount > 0) | 609 | // know if the simulator has subscribed to collisions. |
610 | lock (CollisionLock) | ||
554 | { | 611 | { |
555 | for (int ii = 0; ii < collidersCount; ii++) | 612 | if (collidersCount > 0) |
556 | { | 613 | { |
557 | uint cA = m_collisionArray[ii].aID; | 614 | 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 | { | 615 | { |
574 | // If the object is done colliding, see that it's removed from the colliding list | 616 | uint cA = m_collisionArray[ii].aID; |
575 | ObjectsWithNoMoreCollisions.Add(bsp); | 617 | uint cB = m_collisionArray[ii].bID; |
618 | Vector3 point = m_collisionArray[ii].point; | ||
619 | Vector3 normal = m_collisionArray[ii].normal; | ||
620 | float penetration = m_collisionArray[ii].penetration; | ||
621 | SendCollision(cA, cB, point, normal, penetration); | ||
622 | SendCollision(cB, cA, point, -normal, penetration); | ||
576 | } | 623 | } |
624 | } | ||
577 | } | 625 | } |
578 | 626 | ||
579 | // This is a kludge to get avatar movement updates. | 627 | // 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. | 628 | // and remember that there was a change so it will be passed to the simulator. |
581 | // The event updates avatar animations and stuff. | 629 | 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 | { | 630 | { |
603 | for (int ii = 0; ii < updatedEntityCount; ii++) | 631 | if (updatedEntityCount > 0) |
604 | { | 632 | { |
605 | EntityProperties entprop = m_updateArray[ii]; | 633 | for (int ii = 0; ii < updatedEntityCount; ii++) |
606 | BSPhysObject pobj; | ||
607 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
608 | { | 634 | { |
609 | pobj.UpdateProperties(entprop); | 635 | EntityProperties entprop = m_updateArray[ii]; |
636 | BSPhysObject pobj; | ||
637 | if (PhysObjects.TryGetValue(entprop.ID, out pobj)) | ||
638 | { | ||
639 | pobj.UpdateProperties(entprop); | ||
640 | } | ||
610 | } | 641 | } |
611 | } | 642 | } |
612 | } | 643 | } |
613 | 644 | ||
645 | // Some actors want to know when the simulation step is complete. | ||
614 | TriggerPostStepEvent(timeStep); | 646 | TriggerPostStepEvent(timeStep); |
615 | 647 | ||
648 | simTime = Util.EnvironmentTickCountSubtract(beforeTime); | ||
649 | if (PhysicsLogging.Enabled) | ||
650 | { | ||
651 | DetailLog("{0},DoPhysicsStep,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", | ||
652 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, | ||
653 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); | ||
654 | } | ||
655 | |||
616 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 656 | // 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. | 657 | // Only enable this in a limited test world with few objects. |
618 | if (m_physicsPhysicalDumpEnabled) | 658 | if (m_physicsPhysicalDumpEnabled) |
@@ -621,7 +661,84 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
621 | // The physics engine returns the number of milliseconds it simulated this call. | 661 | // 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. | 662 | // 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). | 663 | // 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; | 664 | m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate; |
665 | } | ||
666 | |||
667 | // Called by a BSPhysObject to note that it has changed properties and this information | ||
668 | // should be passed up to the simulator at the proper time. | ||
669 | // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so | ||
670 | // this is is under UpdateLock. | ||
671 | public void PostUpdate(BSPhysObject updatee) | ||
672 | { | ||
673 | ObjectsWithUpdates.Add(updatee); | ||
674 | } | ||
675 | |||
676 | // The simulator thinks it is physics time so return all the collisions and position | ||
677 | // updates that were collected in actual physics simulation. | ||
678 | private float SendUpdatesToSimulator(float timeStep) | ||
679 | { | ||
680 | if (!m_initialized) return 5.0f; | ||
681 | |||
682 | DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}", | ||
683 | BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime); | ||
684 | // Push the collisions into the simulator. | ||
685 | lock (CollisionLock) | ||
686 | { | ||
687 | if (ObjectsWithCollisions.Count > 0) | ||
688 | { | ||
689 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | ||
690 | if (!bsp.SendCollisions()) | ||
691 | { | ||
692 | // If the object is done colliding, see that it's removed from the colliding list | ||
693 | ObjectsWithNoMoreCollisions.Add(bsp); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | // This is a kludge to get avatar movement updates. | ||
698 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
699 | // The event updates avatar animations and stuff. | ||
700 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
701 | foreach (BSPhysObject bsp in m_avatars) | ||
702 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
703 | bsp.SendCollisions(); | ||
704 | |||
705 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | ||
706 | // Not done above because it is inside an iteration of ObjectWithCollisions. | ||
707 | // This complex collision processing is required to create an empty collision | ||
708 | // event call after all real collisions have happened on an object. This allows | ||
709 | // the simulator to generate the 'collision end' event. | ||
710 | if (ObjectsWithNoMoreCollisions.Count > 0) | ||
711 | { | ||
712 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | ||
713 | ObjectsWithCollisions.Remove(po); | ||
714 | ObjectsWithNoMoreCollisions.Clear(); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | // Call the simulator for each object that has physics property updates. | ||
719 | HashSet<BSPhysObject> updatedObjects = null; | ||
720 | lock (UpdateLock) | ||
721 | { | ||
722 | if (ObjectsWithUpdates.Count > 0) | ||
723 | { | ||
724 | updatedObjects = ObjectsWithUpdates; | ||
725 | ObjectsWithUpdates = new HashSet<BSPhysObject>(); | ||
726 | } | ||
727 | } | ||
728 | if (updatedObjects != null) | ||
729 | { | ||
730 | foreach (BSPhysObject obj in updatedObjects) | ||
731 | { | ||
732 | obj.RequestPhysicsterseUpdate(); | ||
733 | } | ||
734 | updatedObjects.Clear(); | ||
735 | } | ||
736 | |||
737 | // Return the framerate simulated to give the above returned results. | ||
738 | // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock). | ||
739 | float simTime = m_simulatedTime; | ||
740 | m_simulatedTime = 0f; | ||
741 | return simTime; | ||
625 | } | 742 | } |
626 | 743 | ||
627 | // Something has collided | 744 | // Something has collided |
@@ -640,7 +757,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
640 | return; | 757 | return; |
641 | } | 758 | } |
642 | 759 | ||
643 | // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called. | 760 | // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called. |
644 | BSPhysObject collidee = null; | 761 | BSPhysObject collidee = null; |
645 | PhysObjects.TryGetValue(collidingWith, out collidee); | 762 | PhysObjects.TryGetValue(collidingWith, out collidee); |
646 | 763 | ||
@@ -648,13 +765,39 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
648 | 765 | ||
649 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 766 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
650 | { | 767 | { |
651 | // If a collision was posted, remember to send it to the simulator | 768 | // If a collision was 'good', remember to send it to the simulator |
652 | ObjectsWithCollisions.Add(collider); | 769 | ObjectsWithCollisions.Add(collider); |
653 | } | 770 | } |
654 | 771 | ||
655 | return; | 772 | return; |
656 | } | 773 | } |
657 | 774 | ||
775 | public void BulletSPluginPhysicsThread() | ||
776 | { | ||
777 | while (m_initialized) | ||
778 | { | ||
779 | int beginSimulationRealtimeMS = Util.EnvironmentTickCount(); | ||
780 | DoPhysicsStep(BSParam.PhysicsTimeStep); | ||
781 | int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS); | ||
782 | int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS; | ||
783 | |||
784 | if (simulationTimeVsRealtimeDifferenceMS > 0) | ||
785 | { | ||
786 | // The simulation of the time interval took less than realtime. | ||
787 | // Do a sleep for the rest of realtime. | ||
788 | DetailLog("{0},BulletSPluginPhysicsThread,sleeping={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
789 | Thread.Sleep(simulationTimeVsRealtimeDifferenceMS); | ||
790 | } | ||
791 | else | ||
792 | { | ||
793 | // The simulation took longer than realtime. | ||
794 | // Do some scaling of simulation time. | ||
795 | // TODO. | ||
796 | DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS); | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
658 | #endregion // Simulation | 801 | #endregion // Simulation |
659 | 802 | ||
660 | public override void GetResults() { } | 803 | public override void GetResults() { } |
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..4357ef1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -1,41 +1,38 @@ | |||
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 | Computation of mesh mass. How done? How should it be done? | ||
7 | Script changing rotation of child prim while vehicle moving (eg turning wheel) causes | ||
8 | the wheel to appear to jump back. Looks like sending position from previous update. | ||
5 | Enable vehicle border crossings (at least as poorly as ODE) | 9 | Enable vehicle border crossings (at least as poorly as ODE) |
6 | Terrain skirts | 10 | Terrain skirts |
7 | Avatar created in previous region and not new region when crossing border | 11 | 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) | 12 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) |
9 | Lock axis | ||
10 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. | 13 | 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. | 14 | Not sure if it is because standing on it. Done with large prim linksets. |
12 | Linkset child rotations. | 15 | Linkset child rotations. |
13 | Nebadon spiral tube has middle sections which are rotated wrong. | 16 | Nebadon spiral tube has middle sections which are rotated wrong. |
14 | Select linked spiral tube. Delink and note where the middle section ends up. | 17 | Select linked spiral tube. Delink and note where the middle section ends up. |
18 | Refarb compound linkset creation to create a pseudo-root for center-of-mass | ||
19 | Let children change their shape to physical indendently and just add shapes to compound | ||
15 | Vehicle angular vertical attraction | 20 | Vehicle angular vertical attraction |
16 | vehicle angular banking | 21 | vehicle angular banking |
17 | Center-of-gravity | 22 | Center-of-gravity |
18 | Vehicle angular deflection | 23 | Vehicle angular deflection |
19 | Preferred orientation angular correction fix | 24 | 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 | 25 | Teravus llMoveToTarget script debug |
23 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force | 26 | 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) | 27 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) |
25 | limitMotorUp calibration (more down?) | 28 | limitMotorUp calibration (more down?) |
26 | llRotLookAt | 29 | llRotLookAt |
27 | llLookAt | 30 | llLookAt |
28 | Avatars walking up stairs (HALF DONE) | 31 | 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 | 32 | Vehicle script tuning/debugging |
34 | Avanti speed script | 33 | Avanti speed script |
35 | Weapon shooter script | 34 | Weapon shooter script |
36 | Move material definitions (friction, ...) into simulator. | 35 | Move material definitions (friction, ...) into simulator. |
37 | Add material densities to the material types. | ||
38 | Terrain detail: double terrain mesh detail | ||
39 | One sided meshes? Should terrain be built into a closed shape? | 36 | 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. | 37 | 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. | 38 | It is possible that Bullet processes collisions whether entering or leaving a mesh. |
@@ -43,12 +40,13 @@ One sided meshes? Should terrain be built into a closed shape? | |||
43 | 40 | ||
44 | VEHICLES TODO LIST: | 41 | VEHICLES TODO LIST: |
45 | ================================================= | 42 | ================================================= |
46 | Border crossing with linked vehicle causes crash | 43 | LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. |
47 | 20121129.1411: editting/moving phys object across region boundries causes crash | 44 | What are the limits in SL? |
48 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | 45 | Same for other velocity settings. |
46 | UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: | ||
47 | https://github.com/UbitUmarov/Ubit-opensim | ||
49 | Vehicles (Move smoothly) | 48 | Vehicles (Move smoothly) |
50 | Some vehicles should not be able to turn if no speed or off ground. | 49 | 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. | 50 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. |
53 | Neb car jiggling left and right | 51 | Neb car jiggling left and right |
54 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | 52 | Happens on terrain and any other mesh object. Flat cubes are much smoother. |
@@ -58,8 +56,6 @@ 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. |
@@ -168,6 +163,7 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint) | |||
168 | 163 | ||
169 | MORE | 164 | MORE |
170 | ====================================================== | 165 | ====================================================== |
166 | Compute avatar size and scale correctly. Now it is a bit off from the capsule size. | ||
171 | Create tests for different interface components | 167 | Create tests for different interface components |
172 | Have test objects/scripts measure themselves and turn color if correct/bad | 168 | Have test objects/scripts measure themselves and turn color if correct/bad |
173 | Test functions in SL and calibrate correctness there | 169 | Test functions in SL and calibrate correctness there |
@@ -344,3 +340,29 @@ 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. | 340 | Verify that angular motion specified around Z moves in the vehicle coordinates. |
345 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | 341 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. |
346 | Nebadon vehicles turning funny in arena (DONE) | 342 | Nebadon vehicles turning funny in arena (DONE) |
343 | Lock axis (DONE 20130401) | ||
344 | Terrain detail: double terrain mesh detail (DONE) | ||
345 | Use the HACD convex hull routine in Bullet rather than the C# version. | ||
346 | Speed up hullifying large meshes. (DONE) | ||
347 | Vehicle ride, get up, ride again. Second time vehicle does not act correctly. | ||
348 | Have to rez new vehicle and delete the old to fix situation. | ||
349 | (DONE 20130520: normalize rotations) | ||
350 | Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd | ||
351 | position state where it will not settle onto ground properly, etc | ||
352 | (DONE 20130520: normalize rotations) | ||
353 | Two of Nebadon vehicles in a sim max the CPU. This is new. | ||
354 | (DONE 20130520: two problems: if asset failed to mesh, constantly refetched | ||
355 | asset; vehicle was sending too many messages to all linkset members) | ||
356 | Add material densities to the material types. (WILL NOT BE DONE: not how it is done) | ||
357 | Avatars walking up stairs (DONE) | ||
358 | Avatar movement | ||
359 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
360 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) | ||
361 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
362 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
363 | Need to force a position update for the root prim after compound shape destruction | ||
364 | (DONE) | ||
365 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
366 | Regular triangle meshes don't do physical collisions. | ||
367 | (DONE: discovered GImpact is VERY CPU intensive) | ||
368 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs index 33232bd..b040e21 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Tests/BasicVehicles.cs | |||
@@ -114,9 +114,9 @@ public class BasicVehicles : OpenSimTestCase | |||
114 | // Instead the appropriate values are set and calls are made just the parts of the | 114 | // 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 | 115 | // controller we want to exercise. Stepping the physics engine then applies |
116 | // the actions of that one feature. | 116 | // the actions of that one feature. |
117 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); | 117 | TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency); |
118 | TestVehicle.VehicleController.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); | 118 | TestVehicle.VehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale); |
119 | TestVehicle.VehicleController.enableAngularVerticalAttraction = true; | 119 | TestVehicle.VehicleActor.enableAngularVerticalAttraction = true; |
120 | 120 | ||
121 | TestVehicle.IsPhysical = true; | 121 | TestVehicle.IsPhysical = true; |
122 | PhysicsScene.ProcessTaints(); | 122 | PhysicsScene.ProcessTaints(); |
@@ -124,9 +124,9 @@ public class BasicVehicles : OpenSimTestCase | |||
124 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up | 124 | // Step the simulator a bunch of times and vertical attraction should orient the vehicle up |
125 | for (int ii = 0; ii < simSteps; ii++) | 125 | for (int ii = 0; ii < simSteps; ii++) |
126 | { | 126 | { |
127 | TestVehicle.VehicleController.ForgetKnownVehicleProperties(); | 127 | TestVehicle.VehicleActor.ForgetKnownVehicleProperties(); |
128 | TestVehicle.VehicleController.ComputeAngularVerticalAttraction(); | 128 | TestVehicle.VehicleActor.ComputeAngularVerticalAttraction(); |
129 | TestVehicle.VehicleController.PushKnownChanged(); | 129 | TestVehicle.VehicleActor.PushKnownChanged(); |
130 | 130 | ||
131 | PhysicsScene.Simulate(simulationTimeStep); | 131 | PhysicsScene.Simulate(simulationTimeStep); |
132 | } | 132 | } |