diff options
Diffstat (limited to '')
41 files changed, 7213 insertions, 3303 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs index 8c6e7d6..231f0f8 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 | { |
@@ -166,7 +166,7 @@ public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet | |||
166 | 166 | ||
167 | // If Debug logging level, enable logging from the unmanaged code | 167 | // If Debug logging level, enable logging from the unmanaged code |
168 | m_DebugLogCallbackHandle = null; | 168 | m_DebugLogCallbackHandle = null; |
169 | if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled) | 169 | if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) |
170 | { | 170 | { |
171 | BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); | 171 | BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); |
172 | if (PhysicsScene.PhysicsLogging.Enabled) | 172 | if (PhysicsScene.PhysicsLogging.Enabled) |
@@ -202,7 +202,7 @@ private void BulletLoggerPhysLog(string msg) | |||
202 | } | 202 | } |
203 | 203 | ||
204 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | 204 | public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, |
205 | out int updatedEntityCount, out int collidersCount) | 205 | out int updatedEntityCount, out int collidersCount) |
206 | { | 206 | { |
207 | BulletWorldUnman worldu = world as BulletWorldUnman; | 207 | BulletWorldUnman worldu = world as BulletWorldUnman; |
208 | return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); | 208 | return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); |
@@ -212,6 +212,19 @@ public override void Shutdown(BulletWorld world) | |||
212 | { | 212 | { |
213 | BulletWorldUnman worldu = world as BulletWorldUnman; | 213 | BulletWorldUnman worldu = world as BulletWorldUnman; |
214 | BSAPICPP.Shutdown2(worldu.ptr); | 214 | BSAPICPP.Shutdown2(worldu.ptr); |
215 | |||
216 | if (m_paramsHandle.IsAllocated) | ||
217 | { | ||
218 | m_paramsHandle.Free(); | ||
219 | } | ||
220 | if (m_collisionArrayPinnedHandle.IsAllocated) | ||
221 | { | ||
222 | m_collisionArrayPinnedHandle.Free(); | ||
223 | } | ||
224 | if (m_updateArrayPinnedHandle.IsAllocated) | ||
225 | { | ||
226 | m_updateArrayPinnedHandle.Free(); | ||
227 | } | ||
215 | } | 228 | } |
216 | 229 | ||
217 | public override bool PushUpdate(BulletBody obj) | 230 | public override bool PushUpdate(BulletBody obj) |
@@ -242,19 +255,38 @@ public override BulletShape CreateHullShape(BulletWorld world, int hullCount, fl | |||
242 | { | 255 | { |
243 | BulletWorldUnman worldu = world as BulletWorldUnman; | 256 | BulletWorldUnman worldu = world as BulletWorldUnman; |
244 | return new BulletShapeUnman( | 257 | return new BulletShapeUnman( |
245 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), | 258 | BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), |
246 | BSPhysicsShapeType.SHAPE_HULL); | 259 | BSPhysicsShapeType.SHAPE_HULL); |
247 | } | 260 | } |
248 | 261 | ||
249 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | 262 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) |
250 | { | 263 | { |
251 | BulletWorldUnman worldu = world as BulletWorldUnman; | 264 | BulletWorldUnman worldu = world as BulletWorldUnman; |
252 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | 265 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; |
253 | return new BulletShapeUnman( | 266 | return new BulletShapeUnman( |
254 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | 267 | BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), |
255 | BSPhysicsShapeType.SHAPE_HULL); | 268 | BSPhysicsShapeType.SHAPE_HULL); |
256 | } | 269 | } |
257 | 270 | ||
271 | public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) | ||
272 | { | ||
273 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
274 | BulletShapeUnman shapeu = meshShape as BulletShapeUnman; | ||
275 | return new BulletShapeUnman( | ||
276 | BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), | ||
277 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
278 | } | ||
279 | |||
280 | public override BulletShape CreateConvexHullShape(BulletWorld world, | ||
281 | int indicesCount, int[] indices, | ||
282 | int verticesCount, float[] vertices) | ||
283 | { | ||
284 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
285 | return new BulletShapeUnman( | ||
286 | BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), | ||
287 | BSPhysicsShapeType.SHAPE_CONVEXHULL); | ||
288 | } | ||
289 | |||
258 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) | 290 | public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) |
259 | { | 291 | { |
260 | BulletWorldUnman worldu = world as BulletWorldUnman; | 292 | BulletWorldUnman worldu = world as BulletWorldUnman; |
@@ -273,7 +305,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin) | |||
273 | { | 305 | { |
274 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | 306 | BulletShapeUnman shapeu = shape as BulletShapeUnman; |
275 | if (shapeu != null && shapeu.HasPhysicalShape) | 307 | if (shapeu != null && shapeu.HasPhysicalShape) |
276 | BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); | 308 | BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); |
277 | } | 309 | } |
278 | 310 | ||
279 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) | 311 | public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) |
@@ -327,6 +359,12 @@ public override void RemoveChildShapeFromCompoundShape(BulletShape shape, Bullet | |||
327 | BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); | 359 | BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); |
328 | } | 360 | } |
329 | 361 | ||
362 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) | ||
363 | { | ||
364 | BulletShapeUnman shapeu = pShape as BulletShapeUnman; | ||
365 | BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); | ||
366 | } | ||
367 | |||
330 | public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) | 368 | public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) |
331 | { | 369 | { |
332 | BulletShapeUnman shapeu = shape as BulletShapeUnman; | 370 | BulletShapeUnman shapeu = shape as BulletShapeUnman; |
@@ -337,7 +375,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha | |||
337 | { | 375 | { |
338 | BulletWorldUnman worldu = world as BulletWorldUnman; | 376 | BulletWorldUnman worldu = world as BulletWorldUnman; |
339 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; | 377 | BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; |
340 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); | 378 | return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); |
341 | } | 379 | } |
342 | 380 | ||
343 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) | 381 | public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) |
@@ -419,6 +457,28 @@ public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, | |||
419 | joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 457 | joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); |
420 | } | 458 | } |
421 | 459 | ||
460 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
461 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
462 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) | ||
463 | { | ||
464 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
465 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
466 | return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, | ||
467 | frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); | ||
468 | } | ||
469 | |||
470 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
471 | Vector3 frame1loc, Quaternion frame1rot, | ||
472 | Vector3 frame2loc, Quaternion frame2rot, | ||
473 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
474 | { | ||
475 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
476 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
477 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
478 | return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
479 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
480 | } | ||
481 | |||
422 | public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | 482 | public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, |
423 | Vector3 pivotinA, Vector3 pivotinB, | 483 | Vector3 pivotinA, Vector3 pivotinB, |
424 | Vector3 axisInA, Vector3 axisInB, | 484 | Vector3 axisInA, Vector3 axisInB, |
@@ -431,6 +491,52 @@ public override BulletConstraint CreateHingeConstraint(BulletWorld world, Bullet | |||
431 | pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 491 | pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); |
432 | } | 492 | } |
433 | 493 | ||
494 | public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
495 | Vector3 frame1loc, Quaternion frame1rot, | ||
496 | Vector3 frame2loc, Quaternion frame2rot, | ||
497 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | ||
498 | { | ||
499 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
500 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
501 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
502 | return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
503 | frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | ||
504 | } | ||
505 | |||
506 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
507 | Vector3 frame1loc, Quaternion frame1rot, | ||
508 | Vector3 frame2loc, Quaternion frame2rot, | ||
509 | bool disableCollisionsBetweenLinkedBodies) | ||
510 | { | ||
511 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
512 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
513 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
514 | return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, | ||
515 | frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); | ||
516 | } | ||
517 | |||
518 | public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
519 | Vector3 axisInA, Vector3 axisInB, | ||
520 | float ratio, bool disableCollisionsBetweenLinkedBodies) | ||
521 | { | ||
522 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
523 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
524 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
525 | return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, | ||
526 | ratio, disableCollisionsBetweenLinkedBodies)); | ||
527 | } | ||
528 | |||
529 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
530 | Vector3 pivotInA, Vector3 pivotInB, | ||
531 | bool disableCollisionsBetweenLinkedBodies) | ||
532 | { | ||
533 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
534 | BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; | ||
535 | BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; | ||
536 | return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, | ||
537 | disableCollisionsBetweenLinkedBodies)); | ||
538 | } | ||
539 | |||
434 | public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) | 540 | public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) |
435 | { | 541 | { |
436 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; | 542 | BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; |
@@ -530,12 +636,12 @@ public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) | |||
530 | // btDynamicsWorld entries | 636 | // btDynamicsWorld entries |
531 | public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) | 637 | public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) |
532 | { | 638 | { |
533 | // Bullet resets several variables when an object is added to the world. | ||
534 | // Gravity is reset to world default depending on the static/dynamic | ||
535 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
536 | BulletWorldUnman worldu = world as BulletWorldUnman; | 639 | BulletWorldUnman worldu = world as BulletWorldUnman; |
537 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 640 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
538 | 641 | ||
642 | // Bullet resets several variables when an object is added to the world. | ||
643 | // Gravity is reset to world default depending on the static/dynamic | ||
644 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | ||
539 | Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); | 645 | Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); |
540 | 646 | ||
541 | bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); | 647 | bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); |
@@ -921,6 +1027,7 @@ public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quater | |||
921 | } | 1027 | } |
922 | 1028 | ||
923 | // Add a force to the object as if its mass is one. | 1029 | // Add a force to the object as if its mass is one. |
1030 | // Deep down in Bullet: m_totalForce += force*m_linearFactor; | ||
924 | public override void ApplyCentralForce(BulletBody obj, Vector3 force) | 1031 | public override void ApplyCentralForce(BulletBody obj, Vector3 force) |
925 | { | 1032 | { |
926 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1033 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -964,6 +1071,7 @@ public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, | |||
964 | BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); | 1071 | BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); |
965 | } | 1072 | } |
966 | 1073 | ||
1074 | // Deep down in Bullet: m_totalTorque += torque*m_angularFactor; | ||
967 | public override void ApplyTorque(BulletBody obj, Vector3 torque) | 1075 | public override void ApplyTorque(BulletBody obj, Vector3 torque) |
968 | { | 1076 | { |
969 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1077 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -971,6 +1079,8 @@ public override void ApplyTorque(BulletBody obj, Vector3 torque) | |||
971 | } | 1079 | } |
972 | 1080 | ||
973 | // Apply force at the given point. Will add torque to the object. | 1081 | // Apply force at the given point. Will add torque to the object. |
1082 | // Deep down in Bullet: applyCentralForce(force); | ||
1083 | // applyTorque(rel_pos.cross(force*m_linearFactor)); | ||
974 | public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) | 1084 | public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) |
975 | { | 1085 | { |
976 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1086 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -978,6 +1088,7 @@ public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) | |||
978 | } | 1088 | } |
979 | 1089 | ||
980 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. | 1090 | // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. |
1091 | // Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; | ||
981 | public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) | 1092 | public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) |
982 | { | 1093 | { |
983 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1094 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -985,6 +1096,7 @@ public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) | |||
985 | } | 1096 | } |
986 | 1097 | ||
987 | // Apply impulse to the object's torque. Force is scaled by object's mass. | 1098 | // Apply impulse to the object's torque. Force is scaled by object's mass. |
1099 | // Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; | ||
988 | public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) | 1100 | public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) |
989 | { | 1101 | { |
990 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1102 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -992,6 +1104,8 @@ public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) | |||
992 | } | 1104 | } |
993 | 1105 | ||
994 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. | 1106 | // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. |
1107 | // Deep down in Bullet: applyCentralImpulse(impulse); | ||
1108 | // applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); | ||
995 | public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) | 1109 | public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) |
996 | { | 1110 | { |
997 | BulletBodyUnman bodyu = obj as BulletBodyUnman; | 1111 | BulletBodyUnman bodyu = obj as BulletBodyUnman; |
@@ -1259,6 +1373,16 @@ public override void DumpPhysicsStatistics(BulletWorld world) | |||
1259 | BulletWorldUnman worldu = world as BulletWorldUnman; | 1373 | BulletWorldUnman worldu = world as BulletWorldUnman; |
1260 | BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); | 1374 | BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); |
1261 | } | 1375 | } |
1376 | public override void ResetBroadphasePool(BulletWorld world) | ||
1377 | { | ||
1378 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1379 | BSAPICPP.ResetBroadphasePool(worldu.ptr); | ||
1380 | } | ||
1381 | public override void ResetConstraintSolver(BulletWorld world) | ||
1382 | { | ||
1383 | BulletWorldUnman worldu = world as BulletWorldUnman; | ||
1384 | BSAPICPP.ResetConstraintSolver(worldu.ptr); | ||
1385 | } | ||
1262 | 1386 | ||
1263 | // ===================================================================================== | 1387 | // ===================================================================================== |
1264 | // ===================================================================================== | 1388 | // ===================================================================================== |
@@ -1306,7 +1430,15 @@ public static extern IntPtr CreateHullShape2(IntPtr world, | |||
1306 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); | 1430 | int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); |
1307 | 1431 | ||
1308 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1432 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1309 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | 1433 | public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); |
1434 | |||
1435 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1436 | public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); | ||
1437 | |||
1438 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1439 | public static extern IntPtr CreateConvexHullShape2(IntPtr world, | ||
1440 | int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, | ||
1441 | int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); | ||
1310 | 1442 | ||
1311 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1443 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1312 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); | 1444 | public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); |
@@ -1315,7 +1447,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
1315 | public static extern bool IsNativeShape2(IntPtr shape); | 1447 | public static extern bool IsNativeShape2(IntPtr shape); |
1316 | 1448 | ||
1317 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1449 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1318 | public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); | 1450 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); |
1319 | 1451 | ||
1320 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1452 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1321 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 1453 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); |
@@ -1339,6 +1471,9 @@ public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShap | |||
1339 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | 1471 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); |
1340 | 1472 | ||
1341 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1473 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1474 | public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
1475 | |||
1476 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1342 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); | 1477 | public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); |
1343 | 1478 | ||
1344 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1479 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -1368,7 +1503,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj); | |||
1368 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); | 1503 | public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); |
1369 | 1504 | ||
1370 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1505 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1371 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, | 1506 | public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, |
1372 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, | 1507 | [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, |
1373 | float scaleFactor, float collisionMargin); | 1508 | float scaleFactor, float collisionMargin); |
1374 | 1509 | ||
@@ -1386,12 +1521,46 @@ public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr ob | |||
1386 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 1521 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
1387 | 1522 | ||
1388 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1523 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1524 | public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, | ||
1525 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1526 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
1527 | |||
1528 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1529 | public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1530 | Vector3 frame1loc, Quaternion frame1rot, | ||
1531 | Vector3 frame2loc, Quaternion frame2rot, | ||
1532 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1533 | |||
1534 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1389 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | 1535 | public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, |
1390 | Vector3 pivotinA, Vector3 pivotinB, | 1536 | Vector3 pivotinA, Vector3 pivotinB, |
1391 | Vector3 axisInA, Vector3 axisInB, | 1537 | Vector3 axisInA, Vector3 axisInB, |
1392 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 1538 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
1393 | 1539 | ||
1394 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1540 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1541 | public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1542 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1543 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1544 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
1545 | |||
1546 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1547 | public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1548 | Vector3 frameInAloc, Quaternion frameInArot, | ||
1549 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
1550 | bool disableCollisionsBetweenLinkedBodies); | ||
1551 | |||
1552 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1553 | public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1554 | Vector3 axisInA, Vector3 axisInB, | ||
1555 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
1556 | |||
1557 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1558 | public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, | ||
1559 | Vector3 pivotInA, Vector3 pivotInB, | ||
1560 | bool disableCollisionsBetweenLinkedBodies); | ||
1561 | |||
1562 | |||
1563 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1395 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); | 1564 | public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); |
1396 | 1565 | ||
1397 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1566 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -1832,6 +2001,12 @@ public static extern void DumpAllInfo2(IntPtr sim); | |||
1832 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 2001 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1833 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 2002 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
1834 | 2003 | ||
2004 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2005 | public static extern void ResetBroadphasePool(IntPtr sim); | ||
2006 | |||
2007 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
2008 | public static extern void ResetConstraintSolver(IntPtr sim); | ||
2009 | |||
1835 | } | 2010 | } |
1836 | 2011 | ||
1837 | } | 2012 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs index 30a7bee..59780ae 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.IO; | 29 | using System.IO; |
30 | using System.Runtime.InteropServices; | ||
30 | using System.Text; | 31 | using System.Text; |
31 | 32 | ||
32 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
@@ -80,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody | |||
80 | private sealed class BulletShapeXNA : BulletShape | 81 | private sealed class BulletShapeXNA : BulletShape |
81 | { | 82 | { |
82 | public CollisionShape shape; | 83 | public CollisionShape shape; |
83 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) | 84 | public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) |
84 | : base() | 85 | : base() |
85 | { | 86 | { |
86 | shape = xx; | 87 | shape = xx; |
87 | type = typ; | 88 | shapeType = typ; |
88 | } | 89 | } |
89 | public override bool HasPhysicalShape | 90 | public override bool HasPhysicalShape |
90 | { | 91 | { |
@@ -96,7 +97,7 @@ private sealed class BulletShapeXNA : BulletShape | |||
96 | } | 97 | } |
97 | public override BulletShape Clone() | 98 | public override BulletShape Clone() |
98 | { | 99 | { |
99 | return new BulletShapeXNA(shape, type); | 100 | return new BulletShapeXNA(shape, shapeType); |
100 | } | 101 | } |
101 | public override bool ReferenceSame(BulletShape other) | 102 | public override bool ReferenceSame(BulletShape other) |
102 | { | 103 | { |
@@ -129,6 +130,14 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
129 | get { return "XNAConstraint"; } | 130 | get { return "XNAConstraint"; } |
130 | } | 131 | } |
131 | } | 132 | } |
133 | internal int m_maxCollisions; | ||
134 | internal CollisionDesc[] UpdatedCollisions; | ||
135 | internal int LastCollisionDesc = 0; | ||
136 | internal int m_maxUpdatesPerFrame; | ||
137 | internal int LastEntityProperty = 0; | ||
138 | |||
139 | internal EntityProperties[] UpdatedObjects; | ||
140 | internal Dictionary<uint, GhostObject> specialCollisionObjects; | ||
132 | 141 | ||
133 | private static int m_collisionsThisFrame; | 142 | private static int m_collisionsThisFrame; |
134 | private BSScene PhysicsScene { get; set; } | 143 | private BSScene PhysicsScene { get; set; } |
@@ -142,111 +151,127 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
142 | } | 151 | } |
143 | 152 | ||
144 | /// <summary> | 153 | /// <summary> |
145 | /// | 154 | /// |
146 | /// </summary> | 155 | /// </summary> |
147 | /// <param name="p"></param> | 156 | /// <param name="p"></param> |
148 | /// <param name="p_2"></param> | 157 | /// <param name="p_2"></param> |
149 | public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) | 158 | public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) |
150 | { | 159 | { |
151 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 160 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
152 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 161 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; |
153 | world.RemoveRigidBody(body); | 162 | CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; |
163 | if (body != null) | ||
164 | world.RemoveRigidBody(body); | ||
165 | else if (collisionObject != null) | ||
166 | world.RemoveCollisionObject(collisionObject); | ||
167 | else | ||
168 | return false; | ||
154 | return true; | 169 | return true; |
155 | } | 170 | } |
156 | 171 | ||
157 | public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) | 172 | public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) |
158 | { | 173 | { |
159 | /* TODO */ | 174 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
160 | return false; | 175 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; |
176 | world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); | ||
177 | |||
178 | return true; | ||
179 | |||
161 | } | 180 | } |
162 | 181 | ||
163 | public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) | 182 | public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) |
164 | { | 183 | { |
165 | /* TODO */ | 184 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
166 | return false; | 185 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; |
186 | world.RemoveConstraint(constraint); | ||
187 | return true; | ||
167 | } | 188 | } |
168 | 189 | ||
169 | public override void SetRestitution(BulletBody pBody, float pRestitution) | 190 | public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) |
170 | { | 191 | { |
171 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 192 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
172 | body.SetRestitution(pRestitution); | 193 | collisionObject.SetRestitution(pRestitution); |
173 | } | 194 | } |
174 | 195 | ||
175 | public override int GetShapeType(BulletShape pShape) | 196 | public override int GetShapeType(BulletShape pShape) |
176 | { | 197 | { |
177 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 198 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
178 | return (int)shape.GetShapeType(); | 199 | return (int)shape.GetShapeType(); |
179 | } | 200 | } |
180 | public override void SetMargin(BulletShape pShape, float pMargin) | 201 | public override void SetMargin(BulletShape pShape, float pMargin) |
181 | { | 202 | { |
182 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 203 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
183 | shape.SetMargin(pMargin); | 204 | shape.SetMargin(pMargin); |
184 | } | 205 | } |
185 | 206 | ||
186 | public override float GetMargin(BulletShape pShape) | 207 | public override float GetMargin(BulletShape pShape) |
187 | { | 208 | { |
188 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 209 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
189 | return shape.GetMargin(); | 210 | return shape.GetMargin(); |
190 | } | 211 | } |
191 | 212 | ||
192 | public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) | 213 | public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) |
193 | { | 214 | { |
194 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 215 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
195 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | 216 | IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); |
196 | shape.SetLocalScaling(ref vec); | 217 | shape.SetLocalScaling(ref vec); |
197 | 218 | ||
198 | } | 219 | } |
199 | 220 | ||
200 | public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold) | 221 | public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) |
201 | { | 222 | { |
202 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 223 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
203 | body.SetContactProcessingThreshold(contactprocessingthreshold); | 224 | collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); |
204 | } | 225 | } |
205 | 226 | ||
206 | public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold) | 227 | public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) |
207 | { | 228 | { |
208 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 229 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
209 | body.SetCcdMotionThreshold(pccdMotionThreashold); | 230 | collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); |
210 | } | 231 | } |
211 | 232 | ||
212 | public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius) | 233 | public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) |
213 | { | 234 | { |
214 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 235 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
215 | body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); | 236 | collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); |
216 | } | 237 | } |
217 | 238 | ||
218 | public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) | 239 | public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) |
219 | { | 240 | { |
220 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 241 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
221 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); | 242 | body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); |
222 | } | 243 | } |
223 | 244 | ||
224 | public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) | 245 | public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) |
225 | { | 246 | { |
226 | CollisionObject body = ((BulletBodyXNA)pBody).body; | 247 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
227 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | 248 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); |
228 | existingcollisionFlags |= pcollisionFlags; | 249 | existingcollisionFlags |= pcollisionFlags; |
229 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | 250 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); |
230 | return (CollisionFlags) (uint) existingcollisionFlags; | 251 | return (CollisionFlags) (uint) existingcollisionFlags; |
231 | } | 252 | } |
232 | 253 | ||
233 | public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) | 254 | public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) |
234 | { | 255 | { |
256 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
257 | CollisionObject cbody = (pBody as BulletBodyXNA).body; | ||
258 | RigidBody rbody = cbody as RigidBody; | ||
259 | |||
235 | // Bullet resets several variables when an object is added to the world. In particular, | 260 | // Bullet resets several variables when an object is added to the world. In particular, |
236 | // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic | 261 | // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic |
237 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. | 262 | // type. Of course, the collision flags in the broadphase proxy are initialized to default. |
238 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 263 | IndexedMatrix origPos = cbody.GetWorldTransform(); |
239 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 264 | if (rbody != null) |
240 | 265 | { | |
241 | IndexedMatrix origPos = body.GetWorldTransform(); | 266 | IndexedVector3 origGrav = rbody.GetGravity(); |
242 | IndexedVector3 origGrav = body.GetGravity(); | 267 | world.AddRigidBody(rbody); |
243 | 268 | rbody.SetGravity(origGrav); | |
244 | //if (!(body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE && body.GetCollisionShape().GetShapeType() == BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE)) | 269 | } |
245 | 270 | else | |
246 | world.AddRigidBody(body); | 271 | { |
247 | 272 | world.AddCollisionObject(cbody); | |
248 | body.SetWorldTransform(origPos); | 273 | } |
249 | body.SetGravity(origGrav); | 274 | cbody.SetWorldTransform(origPos); |
250 | 275 | ||
251 | pBody.ApplyCollisionMask(pWorld.physicsScene); | 276 | pBody.ApplyCollisionMask(pWorld.physicsScene); |
252 | 277 | ||
@@ -255,99 +280,110 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
255 | return true; | 280 | return true; |
256 | } | 281 | } |
257 | 282 | ||
258 | public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState) | 283 | public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) |
259 | { | 284 | { |
260 | CollisionObject body = ((BulletBodyXNA)pBody).body; | 285 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
261 | body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); | 286 | collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); |
262 | } | 287 | } |
263 | 288 | ||
264 | public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody) | 289 | public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) |
265 | { | 290 | { |
266 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 291 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
267 | CollisionObject body = ((BulletBodyXNA)pBody).body; | 292 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
268 | world.UpdateSingleAabb(body); | 293 | world.UpdateSingleAabb(collisionObject); |
269 | } | 294 | } |
270 | 295 | ||
271 | public override void UpdateAabbs(BulletWorld world) { /* TODO */ } | 296 | public override void UpdateAabbs(BulletWorld pWorld) { |
272 | public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; } | 297 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
273 | public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ } | 298 | world.UpdateAabbs(); |
299 | } | ||
300 | public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { | ||
301 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
302 | return world.GetForceUpdateAllAabbs(); | ||
274 | 303 | ||
275 | public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask) | 304 | } |
305 | public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) | ||
276 | { | 306 | { |
277 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 307 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
278 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | 308 | world.SetForceUpdateAllAabbs(pForce); |
279 | body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | 309 | } |
280 | if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0) | 310 | |
311 | public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) | ||
312 | { | ||
313 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; | ||
314 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
315 | collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; | ||
316 | if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) | ||
281 | return false; | 317 | return false; |
282 | return true; | 318 | return true; |
283 | } | 319 | } |
284 | 320 | ||
285 | public override void ClearAllForces(BulletBody pBody) | 321 | public override void ClearAllForces(BulletBody pCollisionObject) |
286 | { | 322 | { |
287 | CollisionObject body = ((BulletBodyXNA)pBody).body; | 323 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
288 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); | 324 | IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); |
289 | body.SetInterpolationLinearVelocity(ref zeroVector); | 325 | collisionObject.SetInterpolationLinearVelocity(ref zeroVector); |
290 | body.SetInterpolationAngularVelocity(ref zeroVector); | 326 | collisionObject.SetInterpolationAngularVelocity(ref zeroVector); |
291 | IndexedMatrix bodytransform = body.GetWorldTransform(); | 327 | IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); |
292 | 328 | ||
293 | body.SetInterpolationWorldTransform(ref bodytransform); | 329 | collisionObject.SetInterpolationWorldTransform(ref bodytransform); |
294 | 330 | ||
295 | if (body is RigidBody) | 331 | if (collisionObject is RigidBody) |
296 | { | 332 | { |
297 | RigidBody rigidbody = body as RigidBody; | 333 | RigidBody rigidbody = collisionObject as RigidBody; |
298 | rigidbody.SetLinearVelocity(zeroVector); | 334 | rigidbody.SetLinearVelocity(zeroVector); |
299 | rigidbody.SetAngularVelocity(zeroVector); | 335 | rigidbody.SetAngularVelocity(zeroVector); |
300 | rigidbody.ClearForces(); | 336 | rigidbody.ClearForces(); |
301 | } | 337 | } |
302 | } | 338 | } |
303 | 339 | ||
304 | public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3) | 340 | public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) |
305 | { | 341 | { |
306 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 342 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
307 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | 343 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); |
308 | body.SetInterpolationAngularVelocity(ref vec); | 344 | collisionObject.SetInterpolationAngularVelocity(ref vec); |
309 | } | 345 | } |
310 | 346 | ||
311 | public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) | 347 | public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) |
312 | { | 348 | { |
313 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 349 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
314 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); | 350 | IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); |
315 | body.SetAngularVelocity(ref vec); | 351 | body.SetAngularVelocity(ref vec); |
316 | } | 352 | } |
317 | public override Vector3 GetTotalForce(BulletBody pBody) | 353 | public override Vector3 GetTotalForce(BulletBody pBody) |
318 | { | 354 | { |
319 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 355 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
320 | IndexedVector3 iv3 = body.GetTotalForce(); | 356 | IndexedVector3 iv3 = body.GetTotalForce(); |
321 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 357 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
322 | } | 358 | } |
323 | public override Vector3 GetTotalTorque(BulletBody pBody) | 359 | public override Vector3 GetTotalTorque(BulletBody pBody) |
324 | { | 360 | { |
325 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 361 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
326 | IndexedVector3 iv3 = body.GetTotalTorque(); | 362 | IndexedVector3 iv3 = body.GetTotalTorque(); |
327 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 363 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
328 | } | 364 | } |
329 | public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) | 365 | public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) |
330 | { | 366 | { |
331 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 367 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
332 | IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); | 368 | IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); |
333 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 369 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
334 | } | 370 | } |
335 | public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) | 371 | public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) |
336 | { | 372 | { |
337 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 373 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
338 | IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); | 374 | IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); |
339 | body.SetInvInertiaDiagLocal(ref iv3); | 375 | body.SetInvInertiaDiagLocal(ref iv3); |
340 | } | 376 | } |
341 | public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) | 377 | public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) |
342 | { | 378 | { |
343 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 379 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
344 | IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); | 380 | IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); |
345 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | 381 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); |
346 | body.ApplyForce(ref forceiv3, ref posiv3); | 382 | body.ApplyForce(ref forceiv3, ref posiv3); |
347 | } | 383 | } |
348 | public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) | 384 | public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) |
349 | { | 385 | { |
350 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 386 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
351 | IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); | 387 | IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); |
352 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | 388 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); |
353 | body.ApplyImpulse(ref impiv3, ref posiv3); | 389 | body.ApplyImpulse(ref impiv3, ref posiv3); |
@@ -355,32 +391,32 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
355 | 391 | ||
356 | public override void ClearForces(BulletBody pBody) | 392 | public override void ClearForces(BulletBody pBody) |
357 | { | 393 | { |
358 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 394 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
359 | body.ClearForces(); | 395 | body.ClearForces(); |
360 | } | 396 | } |
361 | 397 | ||
362 | public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation) | 398 | public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) |
363 | { | 399 | { |
364 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 400 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
365 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); | 401 | IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); |
366 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, | 402 | IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, |
367 | _orientation.W); | 403 | _orientation.W); |
368 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); | 404 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); |
369 | mat._origin = vposition; | 405 | mat._origin = vposition; |
370 | body.SetWorldTransform(mat); | 406 | collisionObject.SetWorldTransform(mat); |
371 | 407 | ||
372 | } | 408 | } |
373 | 409 | ||
374 | public override Vector3 GetPosition(BulletBody pBody) | 410 | public override Vector3 GetPosition(BulletBody pCollisionObject) |
375 | { | 411 | { |
376 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 412 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
377 | IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin; | 413 | IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; |
378 | return new Vector3(pos.X, pos.Y, pos.Z); | 414 | return new Vector3(pos.X, pos.Y, pos.Z); |
379 | } | 415 | } |
380 | 416 | ||
381 | public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) | 417 | public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) |
382 | { | 418 | { |
383 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 419 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
384 | IndexedVector3 inertia = IndexedVector3.Zero; | 420 | IndexedVector3 inertia = IndexedVector3.Zero; |
385 | shape.CalculateLocalInertia(pphysMass, out inertia); | 421 | shape.CalculateLocalInertia(pphysMass, out inertia); |
386 | return new Vector3(inertia.X, inertia.Y, inertia.Z); | 422 | return new Vector3(inertia.X, inertia.Y, inertia.Z); |
@@ -388,81 +424,104 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
388 | 424 | ||
389 | public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) | 425 | public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) |
390 | { | 426 | { |
391 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 427 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
392 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | 428 | if (body != null) // Can't set mass props on collision object. |
393 | body.SetMassProps(pphysMass, inertia); | 429 | { |
430 | IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); | ||
431 | body.SetMassProps(pphysMass, inertia); | ||
432 | } | ||
394 | } | 433 | } |
395 | 434 | ||
396 | 435 | ||
397 | public override void SetObjectForce(BulletBody pBody, Vector3 _force) | 436 | public override void SetObjectForce(BulletBody pBody, Vector3 _force) |
398 | { | 437 | { |
399 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 438 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
400 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); | 439 | IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); |
401 | body.SetTotalForce(ref force); | 440 | body.SetTotalForce(ref force); |
402 | } | 441 | } |
403 | 442 | ||
404 | public override void SetFriction(BulletBody pBody, float _currentFriction) | 443 | public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) |
405 | { | 444 | { |
406 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 445 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
407 | body.SetFriction(_currentFriction); | 446 | collisionObject.SetFriction(_currentFriction); |
408 | } | 447 | } |
409 | 448 | ||
410 | public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) | 449 | public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) |
411 | { | 450 | { |
412 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 451 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
413 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); | 452 | IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); |
414 | body.SetLinearVelocity(velocity); | 453 | body.SetLinearVelocity(velocity); |
415 | } | 454 | } |
416 | 455 | ||
417 | public override void Activate(BulletBody pBody, bool pforceactivation) | 456 | public override void Activate(BulletBody pCollisionObject, bool pforceactivation) |
418 | { | 457 | { |
419 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 458 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
420 | body.Activate(pforceactivation); | 459 | collisionObject.Activate(pforceactivation); |
421 | 460 | ||
422 | } | 461 | } |
423 | 462 | ||
424 | public override Quaternion GetOrientation(BulletBody pBody) | 463 | public override Quaternion GetOrientation(BulletBody pCollisionObject) |
425 | { | 464 | { |
426 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 465 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
427 | IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation(); | 466 | IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); |
428 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); | 467 | return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); |
429 | } | 468 | } |
430 | 469 | ||
431 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags) | 470 | public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) |
432 | { | 471 | { |
433 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 472 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
434 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags(); | 473 | CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); |
435 | existingcollisionFlags &= ~pcollisionFlags; | 474 | existingcollisionFlags &= ~pcollisionFlags; |
436 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); | 475 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); |
437 | return (CollisionFlags)(uint)existingcollisionFlags; | 476 | return (CollisionFlags)(uint)existingcollisionFlags; |
438 | } | 477 | } |
439 | 478 | ||
440 | public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; } | 479 | public override float GetCcdMotionThreshold(BulletBody pCollisionObject) |
480 | { | ||
481 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
482 | return collisionObject.GetCcdSquareMotionThreshold(); | ||
483 | } | ||
441 | 484 | ||
442 | public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; } | 485 | public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) |
486 | { | ||
487 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
488 | return collisionObject.GetCcdSweptSphereRadius(); | ||
489 | |||
490 | } | ||
443 | 491 | ||
444 | public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; } | 492 | public override IntPtr GetUserPointer(BulletBody pCollisionObject) |
493 | { | ||
494 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
495 | return (IntPtr)shape.GetUserPointer(); | ||
496 | } | ||
445 | 497 | ||
446 | public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ } | 498 | public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) |
499 | { | ||
500 | CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; | ||
501 | shape.SetUserPointer(val); | ||
502 | } | ||
447 | 503 | ||
448 | public override void SetGravity(BulletBody pBody, Vector3 pGravity) | 504 | public override void SetGravity(BulletBody pBody, Vector3 pGravity) |
449 | { | 505 | { |
450 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 506 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
451 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | 507 | if (body != null) // Can't set collisionobject.set gravity |
452 | body.SetGravity(gravity); | 508 | { |
509 | IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); | ||
510 | body.SetGravity(gravity); | ||
511 | } | ||
453 | } | 512 | } |
454 | 513 | ||
455 | public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) | 514 | public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) |
456 | { | 515 | { |
457 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 516 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
458 | TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain; | 517 | TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; |
459 | world.RemoveConstraint(constraint); | 518 | world.RemoveConstraint(constraint); |
460 | return true; | 519 | return true; |
461 | } | 520 | } |
462 | 521 | ||
463 | public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | 522 | public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) |
464 | { | 523 | { |
465 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 524 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
466 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | 525 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); |
467 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | 526 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); |
468 | constraint.SetLinearLowerLimit(lowlimit); | 527 | constraint.SetLinearLowerLimit(lowlimit); |
@@ -472,7 +531,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
472 | 531 | ||
473 | public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) | 532 | public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) |
474 | { | 533 | { |
475 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 534 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
476 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); | 535 | IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); |
477 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); | 536 | IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); |
478 | constraint.SetAngularLowerLimit(lowlimit); | 537 | constraint.SetAngularLowerLimit(lowlimit); |
@@ -482,31 +541,32 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
482 | 541 | ||
483 | public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) | 542 | public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) |
484 | { | 543 | { |
485 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 544 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
486 | constraint.SetOverrideNumSolverIterations((int)cnt); | 545 | constraint.SetOverrideNumSolverIterations((int)cnt); |
487 | } | 546 | } |
488 | 547 | ||
489 | public override bool CalculateTransforms(BulletConstraint pConstraint) | 548 | public override bool CalculateTransforms(BulletConstraint pConstraint) |
490 | { | 549 | { |
491 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 550 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
492 | constraint.CalculateTransforms(); | 551 | constraint.CalculateTransforms(); |
493 | return true; | 552 | return true; |
494 | } | 553 | } |
495 | 554 | ||
496 | public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) | 555 | public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) |
497 | { | 556 | { |
498 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 557 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
499 | constraint.SetEnabled((p_2 == 0) ? false : true); | 558 | constraint.SetEnabled((p_2 == 0) ? false : true); |
500 | } | 559 | } |
501 | 560 | ||
502 | 561 | ||
503 | //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); | 562 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
504 | public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 563 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, |
564 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
505 | 565 | ||
506 | { | 566 | { |
507 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 567 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
508 | RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; | 568 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; |
509 | RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; | 569 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; |
510 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | 570 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); |
511 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | 571 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); |
512 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | 572 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); |
@@ -525,9 +585,26 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
525 | return new BulletConstraintXNA(consttr); | 585 | return new BulletConstraintXNA(consttr); |
526 | } | 586 | } |
527 | 587 | ||
528 | 588 | public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, | |
589 | Vector3 pframe1, Quaternion pframe1rot, | ||
590 | bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) | ||
591 | { | ||
592 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
593 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
594 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
595 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
596 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
597 | frame1._origin = frame1v; | ||
598 | |||
599 | Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); | ||
600 | consttr.CalculateTransforms(); | ||
601 | world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); | ||
602 | |||
603 | return new BulletConstraintXNA(consttr); | ||
604 | } | ||
605 | |||
529 | /// <summary> | 606 | /// <summary> |
530 | /// | 607 | /// |
531 | /// </summary> | 608 | /// </summary> |
532 | /// <param name="pWorld"></param> | 609 | /// <param name="pWorld"></param> |
533 | /// <param name="pBody1"></param> | 610 | /// <param name="pBody1"></param> |
@@ -538,9 +615,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
538 | /// <returns></returns> | 615 | /// <returns></returns> |
539 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 616 | public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) |
540 | { | 617 | { |
541 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 618 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
542 | RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody; | 619 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; |
543 | RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody; | 620 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; |
544 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | 621 | IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); |
545 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); | 622 | IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); |
546 | 623 | ||
@@ -559,7 +636,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
559 | //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); | 636 | //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); |
560 | public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) | 637 | public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) |
561 | { | 638 | { |
562 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 639 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
563 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | 640 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); |
564 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | 641 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); |
565 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | 642 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); |
@@ -575,109 +652,110 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
575 | 652 | ||
576 | public override Vector3 GetLinearVelocity(BulletBody pBody) | 653 | public override Vector3 GetLinearVelocity(BulletBody pBody) |
577 | { | 654 | { |
578 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 655 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
579 | IndexedVector3 iv3 = body.GetLinearVelocity(); | 656 | IndexedVector3 iv3 = body.GetLinearVelocity(); |
580 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 657 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
581 | } | 658 | } |
582 | public override Vector3 GetAngularVelocity(BulletBody pBody) | 659 | public override Vector3 GetAngularVelocity(BulletBody pBody) |
583 | { | 660 | { |
584 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 661 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
585 | IndexedVector3 iv3 = body.GetAngularVelocity(); | 662 | IndexedVector3 iv3 = body.GetAngularVelocity(); |
586 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 663 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
587 | } | 664 | } |
588 | public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) | 665 | public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) |
589 | { | 666 | { |
590 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 667 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
591 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); | 668 | IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); |
592 | IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); | 669 | IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); |
593 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 670 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
594 | } | 671 | } |
595 | public override void Translate(BulletBody pBody, Vector3 trans) | 672 | public override void Translate(BulletBody pCollisionObject, Vector3 trans) |
596 | { | 673 | { |
597 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 674 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
675 | collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); | ||
598 | } | 676 | } |
599 | public override void UpdateDeactivation(BulletBody pBody, float timeStep) | 677 | public override void UpdateDeactivation(BulletBody pBody, float timeStep) |
600 | { | 678 | { |
601 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 679 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
602 | body.UpdateDeactivation(timeStep); | 680 | body.UpdateDeactivation(timeStep); |
603 | } | 681 | } |
604 | 682 | ||
605 | public override bool WantsSleeping(BulletBody pBody) | 683 | public override bool WantsSleeping(BulletBody pBody) |
606 | { | 684 | { |
607 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 685 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
608 | return body.WantsSleeping(); | 686 | return body.WantsSleeping(); |
609 | } | 687 | } |
610 | 688 | ||
611 | public override void SetAngularFactor(BulletBody pBody, float factor) | 689 | public override void SetAngularFactor(BulletBody pBody, float factor) |
612 | { | 690 | { |
613 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 691 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
614 | body.SetAngularFactor(factor); | 692 | body.SetAngularFactor(factor); |
615 | } | 693 | } |
616 | 694 | ||
617 | public override Vector3 GetAngularFactor(BulletBody pBody) | 695 | public override Vector3 GetAngularFactor(BulletBody pBody) |
618 | { | 696 | { |
619 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 697 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
620 | IndexedVector3 iv3 = body.GetAngularFactor(); | 698 | IndexedVector3 iv3 = body.GetAngularFactor(); |
621 | return new Vector3(iv3.X, iv3.Y, iv3.Z); | 699 | return new Vector3(iv3.X, iv3.Y, iv3.Z); |
622 | } | 700 | } |
623 | 701 | ||
624 | public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody) | 702 | public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) |
625 | { | 703 | { |
626 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 704 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
627 | CollisionObject body = ((BulletBodyXNA)pBody).body; | 705 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
628 | return world.IsInWorld(body); | 706 | return world.IsInWorld(collisionObject); |
629 | } | 707 | } |
630 | 708 | ||
631 | public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain) | 709 | public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) |
632 | { | 710 | { |
633 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 711 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
634 | TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; | 712 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; |
635 | body.AddConstraintRef(constrain); | 713 | body.AddConstraintRef(constrain); |
636 | } | 714 | } |
637 | 715 | ||
638 | public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain) | 716 | public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) |
639 | { | 717 | { |
640 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 718 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
641 | TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain; | 719 | TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; |
642 | body.RemoveConstraintRef(constrain); | 720 | body.RemoveConstraintRef(constrain); |
643 | } | 721 | } |
644 | 722 | ||
645 | public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) | 723 | public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) |
646 | { | 724 | { |
647 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 725 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
648 | return new BulletConstraintXNA(body.GetConstraintRef(index)); | 726 | return new BulletConstraintXNA(body.GetConstraintRef(index)); |
649 | } | 727 | } |
650 | 728 | ||
651 | public override int GetNumConstraintRefs(BulletBody pBody) | 729 | public override int GetNumConstraintRefs(BulletBody pBody) |
652 | { | 730 | { |
653 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 731 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
654 | return body.GetNumConstraintRefs(); | 732 | return body.GetNumConstraintRefs(); |
655 | } | 733 | } |
656 | 734 | ||
657 | public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity) | 735 | public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) |
658 | { | 736 | { |
659 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 737 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
660 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); | 738 | IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); |
661 | body.SetInterpolationLinearVelocity(ref velocity); | 739 | collisionObject.SetInterpolationLinearVelocity(ref velocity); |
662 | } | 740 | } |
663 | 741 | ||
664 | public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) | 742 | public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) |
665 | { | 743 | { |
666 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 744 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
667 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); | 745 | constraint.SetUseFrameOffset((onOff == 0) ? false : true); |
668 | return true; | 746 | return true; |
669 | } | 747 | } |
670 | //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); | 748 | //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); |
671 | public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) | 749 | public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) |
672 | { | 750 | { |
673 | Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 751 | Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
674 | constraint.SetBreakingImpulseThreshold(threshold); | 752 | constraint.SetBreakingImpulseThreshold(threshold); |
675 | return true; | 753 | return true; |
676 | } | 754 | } |
677 | //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); | 755 | //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); |
678 | public override void SetAngularDamping(BulletBody pBody, float angularDamping) | 756 | public override void SetAngularDamping(BulletBody pBody, float angularDamping) |
679 | { | 757 | { |
680 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 758 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
681 | float lineardamping = body.GetLinearDamping(); | 759 | float lineardamping = body.GetLinearDamping(); |
682 | body.SetDamping(lineardamping, angularDamping); | 760 | body.SetDamping(lineardamping, angularDamping); |
683 | 761 | ||
@@ -685,163 +763,241 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
685 | 763 | ||
686 | public override void UpdateInertiaTensor(BulletBody pBody) | 764 | public override void UpdateInertiaTensor(BulletBody pBody) |
687 | { | 765 | { |
688 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 766 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
689 | body.UpdateInertiaTensor(); | 767 | if (body != null) // can't update inertia tensor on CollisionObject |
768 | body.UpdateInertiaTensor(); | ||
690 | } | 769 | } |
691 | 770 | ||
692 | public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) | 771 | public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) |
693 | { | 772 | { |
694 | CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; | 773 | CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; |
695 | shape.RecalculateLocalAabb(); | 774 | shape.RecalculateLocalAabb(); |
696 | } | 775 | } |
697 | 776 | ||
698 | //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) | 777 | //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) |
699 | public override CollisionFlags GetCollisionFlags(BulletBody pBody) | 778 | public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) |
700 | { | 779 | { |
701 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 780 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
702 | uint flags = (uint)body.GetCollisionFlags(); | 781 | uint flags = (uint)collisionObject.GetCollisionFlags(); |
703 | return (CollisionFlags) flags; | 782 | return (CollisionFlags) flags; |
704 | } | 783 | } |
705 | 784 | ||
706 | public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) | 785 | public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) |
707 | { | 786 | { |
708 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 787 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
709 | body.SetDamping(pLinear, pAngular); | 788 | body.SetDamping(pLinear, pAngular); |
710 | } | 789 | } |
711 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); | 790 | //PhysBody.ptr, PhysicsScene.Params.deactivationTime); |
712 | public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime) | 791 | public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) |
713 | { | 792 | { |
714 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 793 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
715 | body.SetDeactivationTime(pDeactivationTime); | 794 | collisionObject.SetDeactivationTime(pDeactivationTime); |
716 | } | 795 | } |
717 | //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 796 | //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |
718 | public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) | 797 | public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) |
719 | { | 798 | { |
720 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 799 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
721 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); | 800 | body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); |
722 | } | 801 | } |
723 | 802 | ||
724 | public override CollisionObjectTypes GetBodyType(BulletBody pBody) | 803 | public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) |
725 | { | 804 | { |
726 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 805 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
727 | return (CollisionObjectTypes)(int) body.GetInternalType(); | 806 | return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); |
728 | } | 807 | } |
729 | 808 | ||
730 | public override void ApplyGravity(BulletBody obj) { /* TODO */ } | 809 | public override void ApplyGravity(BulletBody pBody) |
810 | { | ||
811 | |||
812 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
813 | body.ApplyGravity(); | ||
814 | } | ||
731 | 815 | ||
732 | public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; } | 816 | public override Vector3 GetGravity(BulletBody pBody) |
817 | { | ||
818 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
819 | IndexedVector3 gravity = body.GetGravity(); | ||
820 | return new Vector3(gravity.X, gravity.Y, gravity.Z); | ||
821 | } | ||
733 | 822 | ||
734 | public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ } | 823 | public override void SetLinearDamping(BulletBody pBody, float lin_damping) |
824 | { | ||
825 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
826 | float angularDamping = body.GetAngularDamping(); | ||
827 | body.SetDamping(lin_damping, angularDamping); | ||
828 | } | ||
735 | 829 | ||
736 | public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; } | 830 | public override float GetLinearDamping(BulletBody pBody) |
831 | { | ||
832 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
833 | return body.GetLinearDamping(); | ||
834 | } | ||
737 | 835 | ||
738 | public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; } | 836 | public override float GetAngularDamping(BulletBody pBody) |
837 | { | ||
838 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
839 | return body.GetAngularDamping(); | ||
840 | } | ||
739 | 841 | ||
740 | public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; } | 842 | public override float GetLinearSleepingThreshold(BulletBody pBody) |
843 | { | ||
844 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
845 | return body.GetLinearSleepingThreshold(); | ||
846 | } | ||
741 | 847 | ||
742 | public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ } | 848 | public override void ApplyDamping(BulletBody pBody, float timeStep) |
849 | { | ||
850 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
851 | body.ApplyDamping(timeStep); | ||
852 | } | ||
743 | 853 | ||
744 | public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; } | 854 | public override Vector3 GetLinearFactor(BulletBody pBody) |
855 | { | ||
856 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
857 | IndexedVector3 linearFactor = body.GetLinearFactor(); | ||
858 | return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); | ||
859 | } | ||
745 | 860 | ||
746 | public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ } | 861 | public override void SetLinearFactor(BulletBody pBody, Vector3 factor) |
862 | { | ||
863 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
864 | body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); | ||
865 | } | ||
747 | 866 | ||
748 | public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ } | 867 | public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) |
868 | { | ||
869 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; | ||
870 | IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); | ||
871 | IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); | ||
872 | mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); | ||
873 | body.SetCenterOfMassTransform( ref mat); | ||
874 | /* TODO: double check this */ | ||
875 | } | ||
749 | 876 | ||
750 | //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); | 877 | //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); |
751 | public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) | 878 | public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) |
752 | { | 879 | { |
753 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 880 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
754 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | 881 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); |
755 | body.ApplyCentralForce(ref fSum); | 882 | body.ApplyCentralForce(ref fSum); |
756 | } | 883 | } |
757 | public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) | 884 | public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) |
758 | { | 885 | { |
759 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 886 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
760 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | 887 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); |
761 | body.ApplyCentralImpulse(ref fSum); | 888 | body.ApplyCentralImpulse(ref fSum); |
762 | } | 889 | } |
763 | public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) | 890 | public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) |
764 | { | 891 | { |
765 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 892 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
766 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | 893 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); |
767 | body.ApplyTorque(ref fSum); | 894 | body.ApplyTorque(ref fSum); |
768 | } | 895 | } |
769 | public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) | 896 | public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) |
770 | { | 897 | { |
771 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 898 | RigidBody body = (pBody as BulletBodyXNA).rigidBody; |
772 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); | 899 | IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); |
773 | body.ApplyTorqueImpulse(ref fSum); | 900 | body.ApplyTorqueImpulse(ref fSum); |
774 | } | 901 | } |
775 | 902 | ||
776 | public override void DumpRigidBody(BulletWorld p, BulletBody p_2) | 903 | public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) |
777 | { | ||
778 | //TODO: | ||
779 | } | ||
780 | |||
781 | public override void DumpCollisionShape(BulletWorld p, BulletShape p_2) | ||
782 | { | 904 | { |
783 | //TODO: | 905 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
784 | } | 906 | CollisionObject co = (pBody as BulletBodyXNA).rigidBody; |
785 | public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) | 907 | RigidBody bo = co as RigidBody; |
786 | { | 908 | if (bo == null) |
787 | //TODO: | 909 | { |
788 | } | ||
789 | |||
790 | public override void DumpActivationInfo(BulletWorld world) | ||
791 | { | ||
792 | //TODO: | ||
793 | } | ||
794 | 910 | ||
795 | public override void DumpAllInfo(BulletWorld world) | 911 | if (world.IsInWorld(co)) |
796 | { | 912 | { |
797 | //TODO: | 913 | world.RemoveCollisionObject(co); |
798 | } | 914 | } |
915 | } | ||
916 | else | ||
917 | { | ||
799 | 918 | ||
800 | public override void DumpPhysicsStatistics(BulletWorld world) | 919 | if (world.IsInWorld(bo)) |
801 | { | 920 | { |
802 | //TODO: | 921 | world.RemoveRigidBody(bo); |
803 | } | 922 | } |
923 | } | ||
924 | if (co != null) | ||
925 | { | ||
926 | if (co.GetUserPointer() != null) | ||
927 | { | ||
928 | uint localId = (uint) co.GetUserPointer(); | ||
929 | if (specialCollisionObjects.ContainsKey(localId)) | ||
930 | { | ||
931 | specialCollisionObjects.Remove(localId); | ||
932 | } | ||
933 | } | ||
934 | } | ||
804 | 935 | ||
805 | public override void DestroyObject(BulletWorld p, BulletBody p_2) | ||
806 | { | ||
807 | //TODO: | ||
808 | } | 936 | } |
809 | 937 | ||
810 | public override void Shutdown(BulletWorld pWorld) | 938 | public override void Shutdown(BulletWorld pWorld) |
811 | { | 939 | { |
812 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 940 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
813 | world.Cleanup(); | 941 | world.Cleanup(); |
814 | } | 942 | } |
815 | 943 | ||
816 | public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id) | 944 | public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) |
817 | { | 945 | { |
818 | return null; | 946 | CollisionShape shape1 = (pShape as BulletShapeXNA).shape; |
947 | |||
948 | // TODO: Turn this from a reference copy to a Value Copy. | ||
949 | BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); | ||
950 | |||
951 | return shape2; | ||
819 | } | 952 | } |
820 | 953 | ||
821 | public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2) | 954 | public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) |
822 | { | 955 | { |
823 | //TODO: | 956 | //TODO: |
824 | return false; | 957 | return false; |
825 | } | 958 | } |
826 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 959 | //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
827 | 960 | ||
828 | 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) |
829 | { | 962 | { |
830 | CollisionWorld world = ((BulletWorldXNA)pWorld).world; | 963 | CollisionWorld world = (pWorld as BulletWorldXNA).world; |
831 | IndexedMatrix mat = | 964 | IndexedMatrix mat = |
832 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, | 965 | IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, |
833 | pRawOrientation.Z, pRawOrientation.W)); | 966 | pRawOrientation.Z, pRawOrientation.W)); |
834 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | 967 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); |
835 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 968 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
836 | //UpdateSingleAabb(world, shape); | 969 | //UpdateSingleAabb(world, shape); |
837 | // TODO: Feed Update array into null | 970 | // TODO: Feed Update array into null |
838 | RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero); | 971 | SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); |
839 | 972 | RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); | |
973 | RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) | ||
974 | { | ||
975 | m_mass = 0 | ||
976 | }; | ||
977 | /* | ||
978 | m_mass = mass; | ||
979 | m_motionState =motionState; | ||
980 | m_collisionShape = collisionShape; | ||
981 | m_localInertia = localInertia; | ||
982 | m_linearDamping = 0f; | ||
983 | m_angularDamping = 0f; | ||
984 | m_friction = 0.5f; | ||
985 | m_restitution = 0f; | ||
986 | m_linearSleepingThreshold = 0.8f; | ||
987 | m_angularSleepingThreshold = 1f; | ||
988 | m_additionalDamping = false; | ||
989 | m_additionalDampingFactor = 0.005f; | ||
990 | m_additionalLinearDampingThresholdSqr = 0.01f; | ||
991 | m_additionalAngularDampingThresholdSqr = 0.01f; | ||
992 | m_additionalAngularDampingFactor = 0.01f; | ||
993 | m_startWorldTransform = IndexedMatrix.Identity; | ||
994 | */ | ||
840 | body.SetUserPointer(pLocalID); | 995 | body.SetUserPointer(pLocalID); |
996 | |||
841 | return new BulletBodyXNA(pLocalID, body); | 997 | return new BulletBodyXNA(pLocalID, body); |
842 | } | 998 | } |
843 | 999 | ||
844 | 1000 | ||
845 | 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) |
846 | { | 1002 | { |
847 | 1003 | ||
@@ -850,7 +1006,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
850 | pRawOrientation.Z, pRawOrientation.W)); | 1006 | pRawOrientation.Z, pRawOrientation.W)); |
851 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | 1007 | mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); |
852 | 1008 | ||
853 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1009 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
854 | 1010 | ||
855 | // TODO: Feed Update array into null | 1011 | // TODO: Feed Update array into null |
856 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); | 1012 | RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); |
@@ -859,21 +1015,43 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
859 | return new BulletBodyXNA(pLocalID, body); | 1015 | return new BulletBodyXNA(pLocalID, body); |
860 | } | 1016 | } |
861 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 1017 | //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
862 | public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags) | 1018 | public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) |
863 | { | 1019 | { |
864 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 1020 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
865 | body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); | 1021 | collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); |
866 | return (CollisionFlags)body.GetCollisionFlags(); | 1022 | return (CollisionFlags)collisionObject.GetCollisionFlags(); |
867 | } | 1023 | } |
868 | 1024 | ||
869 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; } | 1025 | public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) |
1026 | { | ||
1027 | |||
1028 | /* TODO */ | ||
1029 | return Vector3.Zero; | ||
1030 | } | ||
870 | 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; } |
871 | public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } | 1032 | public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } |
872 | public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } | 1033 | public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } |
873 | public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; } | 1034 | public override bool IsStaticObject(BulletBody pCollisionObject) |
874 | public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; } | 1035 | { |
875 | public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; } | 1036 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
876 | public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; } | 1037 | return collisionObject.IsStaticObject(); |
1038 | |||
1039 | } | ||
1040 | public override bool IsKinematicObject(BulletBody pCollisionObject) | ||
1041 | { | ||
1042 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1043 | return collisionObject.IsKinematicObject(); | ||
1044 | } | ||
1045 | public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) | ||
1046 | { | ||
1047 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1048 | return collisionObject.IsStaticOrKinematicObject(); | ||
1049 | } | ||
1050 | public override bool HasContactResponse(BulletBody pCollisionObject) | ||
1051 | { | ||
1052 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1053 | return collisionObject.HasContactResponse(); | ||
1054 | } | ||
877 | public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } | 1055 | public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } |
878 | public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } | 1056 | public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } |
879 | public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } | 1057 | public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } |
@@ -884,15 +1062,15 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
884 | public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } | 1062 | public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } |
885 | 1063 | ||
886 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); | 1064 | //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); |
887 | public override void SetHitFraction(BulletBody pBody, float pHitFraction) | 1065 | public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) |
888 | { | 1066 | { |
889 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 1067 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
890 | body.SetHitFraction(pHitFraction); | 1068 | collisionObject.SetHitFraction(pHitFraction); |
891 | } | 1069 | } |
892 | //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); | 1070 | //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); |
893 | public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) | 1071 | public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) |
894 | { | 1072 | { |
895 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1073 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
896 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); | 1074 | IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); |
897 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); | 1075 | CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); |
898 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); | 1076 | capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); |
@@ -906,19 +1084,29 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
906 | int maxUpdates, ref EntityProperties[] updateArray | 1084 | int maxUpdates, ref EntityProperties[] updateArray |
907 | ) | 1085 | ) |
908 | { | 1086 | { |
1087 | |||
1088 | UpdatedObjects = updateArray; | ||
1089 | UpdatedCollisions = collisionArray; | ||
909 | /* TODO */ | 1090 | /* TODO */ |
910 | return new BulletWorldXNA(1, null, null); | 1091 | ConfigurationParameters[] configparms = new ConfigurationParameters[1]; |
1092 | configparms[0] = parms; | ||
1093 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | ||
1094 | m_maxCollisions = maxCollisions; | ||
1095 | m_maxUpdatesPerFrame = maxUpdates; | ||
1096 | specialCollisionObjects = new Dictionary<uint, GhostObject>(); | ||
1097 | |||
1098 | return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); | ||
911 | } | 1099 | } |
912 | 1100 | ||
913 | private static object Initialize2(Vector3 worldExtent, | 1101 | private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, |
914 | ConfigurationParameters[] o, | 1102 | ConfigurationParameters[] o, |
915 | int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray, | 1103 | int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, |
916 | int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray, | 1104 | int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, |
917 | object mDebugLogCallbackHandle) | 1105 | object mDebugLogCallbackHandle) |
918 | { | 1106 | { |
919 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); | 1107 | CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); |
920 | 1108 | ||
921 | p.angularDamping = o[0].XangularDamping; | 1109 | p.angularDamping = BSParam.AngularDamping; |
922 | p.defaultFriction = o[0].defaultFriction; | 1110 | p.defaultFriction = o[0].defaultFriction; |
923 | p.defaultFriction = o[0].defaultFriction; | 1111 | p.defaultFriction = o[0].defaultFriction; |
924 | p.defaultDensity = o[0].defaultDensity; | 1112 | p.defaultDensity = o[0].defaultDensity; |
@@ -926,33 +1114,33 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
926 | p.collisionMargin = o[0].collisionMargin; | 1114 | p.collisionMargin = o[0].collisionMargin; |
927 | p.gravity = o[0].gravity; | 1115 | p.gravity = o[0].gravity; |
928 | 1116 | ||
929 | p.linearDamping = o[0].XlinearDamping; | 1117 | p.linearDamping = BSParam.LinearDamping; |
930 | p.angularDamping = o[0].XangularDamping; | 1118 | p.angularDamping = BSParam.AngularDamping; |
931 | p.deactivationTime = o[0].XdeactivationTime; | 1119 | p.deactivationTime = BSParam.DeactivationTime; |
932 | p.linearSleepingThreshold = o[0].XlinearSleepingThreshold; | 1120 | p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; |
933 | p.angularSleepingThreshold = o[0].XangularSleepingThreshold; | 1121 | p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; |
934 | p.ccdMotionThreshold = o[0].XccdMotionThreshold; | 1122 | p.ccdMotionThreshold = BSParam.CcdMotionThreshold; |
935 | p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius; | 1123 | p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; |
936 | p.contactProcessingThreshold = o[0].XcontactProcessingThreshold; | 1124 | p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; |
937 | 1125 | ||
938 | p.terrainImplementation = o[0].XterrainImplementation; | 1126 | p.terrainImplementation = BSParam.TerrainImplementation; |
939 | p.terrainFriction = o[0].XterrainFriction; | 1127 | p.terrainFriction = BSParam.TerrainFriction; |
940 | 1128 | ||
941 | p.terrainHitFraction = o[0].XterrainHitFraction; | 1129 | p.terrainHitFraction = BSParam.TerrainHitFraction; |
942 | p.terrainRestitution = o[0].XterrainRestitution; | 1130 | p.terrainRestitution = BSParam.TerrainRestitution; |
943 | p.terrainCollisionMargin = o[0].XterrainCollisionMargin; | 1131 | p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; |
944 | 1132 | ||
945 | p.avatarFriction = o[0].XavatarFriction; | 1133 | p.avatarFriction = BSParam.AvatarFriction; |
946 | p.avatarStandingFriction = o[0].XavatarStandingFriction; | 1134 | p.avatarStandingFriction = BSParam.AvatarStandingFriction; |
947 | p.avatarDensity = o[0].XavatarDensity; | 1135 | p.avatarDensity = BSParam.AvatarDensity; |
948 | p.avatarRestitution = o[0].XavatarRestitution; | 1136 | p.avatarRestitution = BSParam.AvatarRestitution; |
949 | p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth; | 1137 | p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; |
950 | p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth; | 1138 | p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; |
951 | p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight; | 1139 | p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; |
952 | p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold; | 1140 | p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; |
953 | 1141 | ||
954 | p.vehicleAngularDamping = o[0].XvehicleAngularDamping; | 1142 | p.vehicleAngularDamping = BSParam.VehicleAngularDamping; |
955 | 1143 | ||
956 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; | 1144 | p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; |
957 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; | 1145 | p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; |
958 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; | 1146 | p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; |
@@ -962,17 +1150,17 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
962 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; | 1150 | p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; |
963 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; | 1151 | p.numberOfSolverIterations = o[0].numberOfSolverIterations; |
964 | 1152 | ||
965 | p.linksetImplementation = o[0].XlinksetImplementation; | 1153 | p.linksetImplementation = BSParam.LinksetImplementation; |
966 | p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset; | 1154 | p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); |
967 | p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor; | 1155 | p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); |
968 | p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel; | 1156 | p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; |
969 | p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce; | 1157 | p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; |
970 | p.linkConstraintERP = o[0].XlinkConstraintERP; | 1158 | p.linkConstraintERP = BSParam.LinkConstraintERP; |
971 | p.linkConstraintCFM = o[0].XlinkConstraintCFM; | 1159 | p.linkConstraintCFM = BSParam.LinkConstraintCFM; |
972 | p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations; | 1160 | p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; |
973 | p.physicsLoggingFrames = o[0].XphysicsLoggingFrames; | 1161 | p.physicsLoggingFrames = o[0].physicsLoggingFrames; |
974 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); | 1162 | DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); |
975 | 1163 | ||
976 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); | 1164 | DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); |
977 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); | 1165 | CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); |
978 | 1166 | ||
@@ -993,8 +1181,10 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
993 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); | 1181 | SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); |
994 | 1182 | ||
995 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); | 1183 | DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); |
996 | world.UpdatedObjects = updateArray; | 1184 | |
997 | world.UpdatedCollisions = collisionArray; | 1185 | world.LastCollisionDesc = 0; |
1186 | world.LastEntityProperty = 0; | ||
1187 | |||
998 | world.WorldSettings.Params = p; | 1188 | world.WorldSettings.Params = p; |
999 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); | 1189 | world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); |
1000 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; | 1190 | world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; |
@@ -1028,7 +1218,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1028 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; | 1218 | world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; |
1029 | world.SetForceUpdateAllAabbs(true); | 1219 | world.SetForceUpdateAllAabbs(true); |
1030 | 1220 | ||
1031 | 1221 | //BSParam.TerrainImplementation = 0; | |
1032 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); | 1222 | world.SetGravity(new IndexedVector3(0,0,p.gravity)); |
1033 | 1223 | ||
1034 | return world; | 1224 | return world; |
@@ -1036,7 +1226,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1036 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL | 1226 | //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL |
1037 | public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) | 1227 | public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) |
1038 | { | 1228 | { |
1039 | Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint; | 1229 | Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; |
1040 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) | 1230 | if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) |
1041 | { | 1231 | { |
1042 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); | 1232 | constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); |
@@ -1059,7 +1249,8 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1059 | public override bool PushUpdate(BulletBody pCollisionObject) | 1249 | public override bool PushUpdate(BulletBody pCollisionObject) |
1060 | { | 1250 | { |
1061 | bool ret = false; | 1251 | bool ret = false; |
1062 | RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody; | 1252 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
1253 | RigidBody rb = collisionObject as RigidBody; | ||
1063 | if (rb != null) | 1254 | if (rb != null) |
1064 | { | 1255 | { |
1065 | SimMotionState sms = rb.GetMotionState() as SimMotionState; | 1256 | SimMotionState sms = rb.GetMotionState() as SimMotionState; |
@@ -1072,62 +1263,62 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1072 | } | 1263 | } |
1073 | } | 1264 | } |
1074 | return ret; | 1265 | return ret; |
1075 | 1266 | ||
1076 | } | 1267 | } |
1077 | 1268 | ||
1078 | public override float GetAngularMotionDisc(BulletShape pShape) | 1269 | public override float GetAngularMotionDisc(BulletShape pShape) |
1079 | { | 1270 | { |
1080 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1271 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1081 | return shape.GetAngularMotionDisc(); | 1272 | return shape.GetAngularMotionDisc(); |
1082 | } | 1273 | } |
1083 | public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) | 1274 | public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) |
1084 | { | 1275 | { |
1085 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1276 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1086 | return shape.GetContactBreakingThreshold(defaultFactor); | 1277 | return shape.GetContactBreakingThreshold(defaultFactor); |
1087 | } | 1278 | } |
1088 | public override bool IsCompound(BulletShape pShape) | 1279 | public override bool IsCompound(BulletShape pShape) |
1089 | { | 1280 | { |
1090 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1281 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1091 | return shape.IsCompound(); | 1282 | return shape.IsCompound(); |
1092 | } | 1283 | } |
1093 | public override bool IsSoftBody(BulletShape pShape) | 1284 | public override bool IsSoftBody(BulletShape pShape) |
1094 | { | 1285 | { |
1095 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1286 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1096 | return shape.IsSoftBody(); | 1287 | return shape.IsSoftBody(); |
1097 | } | 1288 | } |
1098 | public override bool IsPolyhedral(BulletShape pShape) | 1289 | public override bool IsPolyhedral(BulletShape pShape) |
1099 | { | 1290 | { |
1100 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1291 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1101 | return shape.IsPolyhedral(); | 1292 | return shape.IsPolyhedral(); |
1102 | } | 1293 | } |
1103 | public override bool IsConvex2d(BulletShape pShape) | 1294 | public override bool IsConvex2d(BulletShape pShape) |
1104 | { | 1295 | { |
1105 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1296 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1106 | return shape.IsConvex2d(); | 1297 | return shape.IsConvex2d(); |
1107 | } | 1298 | } |
1108 | public override bool IsConvex(BulletShape pShape) | 1299 | public override bool IsConvex(BulletShape pShape) |
1109 | { | 1300 | { |
1110 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1301 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1111 | return shape.IsConvex(); | 1302 | return shape.IsConvex(); |
1112 | } | 1303 | } |
1113 | public override bool IsNonMoving(BulletShape pShape) | 1304 | public override bool IsNonMoving(BulletShape pShape) |
1114 | { | 1305 | { |
1115 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1306 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1116 | return shape.IsNonMoving(); | 1307 | return shape.IsNonMoving(); |
1117 | } | 1308 | } |
1118 | public override bool IsConcave(BulletShape pShape) | 1309 | public override bool IsConcave(BulletShape pShape) |
1119 | { | 1310 | { |
1120 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1311 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1121 | return shape.IsConcave(); | 1312 | return shape.IsConcave(); |
1122 | } | 1313 | } |
1123 | public override bool IsInfinite(BulletShape pShape) | 1314 | public override bool IsInfinite(BulletShape pShape) |
1124 | { | 1315 | { |
1125 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1316 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1126 | return shape.IsInfinite(); | 1317 | return shape.IsInfinite(); |
1127 | } | 1318 | } |
1128 | public override bool IsNativeShape(BulletShape pShape) | 1319 | public override bool IsNativeShape(BulletShape pShape) |
1129 | { | 1320 | { |
1130 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1321 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1131 | bool ret; | 1322 | bool ret; |
1132 | switch (shape.GetShapeType()) | 1323 | switch (shape.GetShapeType()) |
1133 | { | 1324 | { |
@@ -1144,38 +1335,59 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1144 | return ret; | 1335 | return ret; |
1145 | } | 1336 | } |
1146 | 1337 | ||
1147 | public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ } | 1338 | public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) |
1339 | { | ||
1340 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1341 | shape.SetMargin(pMargin); | ||
1342 | } | ||
1148 | 1343 | ||
1149 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation | 1344 | //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation |
1150 | public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) | 1345 | public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) |
1151 | { | 1346 | { |
1152 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1347 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1153 | IndexedMatrix bodyTransform = new IndexedMatrix(); | 1348 | IndexedMatrix bodyTransform = new IndexedMatrix(); |
1154 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); | 1349 | bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); |
1155 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); | 1350 | bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); |
1156 | GhostObject gObj = new PairCachingGhostObject(); | 1351 | GhostObject gObj = new PairCachingGhostObject(); |
1157 | gObj.SetWorldTransform(bodyTransform); | 1352 | gObj.SetWorldTransform(bodyTransform); |
1158 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1353 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1159 | gObj.SetCollisionShape(shape); | 1354 | gObj.SetCollisionShape(shape); |
1160 | gObj.SetUserPointer(pLocalID); | 1355 | gObj.SetUserPointer(pLocalID); |
1356 | |||
1357 | if (specialCollisionObjects.ContainsKey(pLocalID)) | ||
1358 | specialCollisionObjects[pLocalID] = gObj; | ||
1359 | else | ||
1360 | specialCollisionObjects.Add(pLocalID, gObj); | ||
1361 | |||
1161 | // TODO: Add to Special CollisionObjects! | 1362 | // TODO: Add to Special CollisionObjects! |
1162 | return new BulletBodyXNA(pLocalID, gObj); | 1363 | return new BulletBodyXNA(pLocalID, gObj); |
1163 | } | 1364 | } |
1164 | 1365 | ||
1165 | public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape) | 1366 | public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) |
1166 | { | 1367 | { |
1167 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1368 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1168 | CollisionObject obj = ((BulletBodyXNA)pObj).body; | 1369 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; |
1169 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 1370 | if (pShape == null) |
1170 | obj.SetCollisionShape(shape); | 1371 | { |
1171 | 1372 | collisionObject.SetCollisionShape(new EmptyShape()); | |
1373 | } | ||
1374 | else | ||
1375 | { | ||
1376 | CollisionShape shape = (pShape as BulletShapeXNA).shape; | ||
1377 | collisionObject.SetCollisionShape(shape); | ||
1378 | } | ||
1379 | } | ||
1380 | public override BulletShape GetCollisionShape(BulletBody pCollisionObject) | ||
1381 | { | ||
1382 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; | ||
1383 | CollisionShape shape = collisionObject.GetCollisionShape(); | ||
1384 | return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1172 | } | 1385 | } |
1173 | public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; } | ||
1174 | 1386 | ||
1175 | //(PhysicsScene.World.ptr, nativeShapeData) | 1387 | //(PhysicsScene.World.ptr, nativeShapeData) |
1176 | public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) | 1388 | public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) |
1177 | { | 1389 | { |
1178 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1390 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1179 | CollisionShape shape = null; | 1391 | CollisionShape shape = null; |
1180 | switch (pShapeData.Type) | 1392 | switch (pShapeData.Type) |
1181 | { | 1393 | { |
@@ -1210,15 +1422,15 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1210 | 1422 | ||
1211 | public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) | 1423 | public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) |
1212 | { | 1424 | { |
1213 | CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape; | 1425 | CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; |
1214 | return compoundshape.GetNumChildShapes(); | 1426 | return compoundshape.GetNumChildShapes(); |
1215 | } | 1427 | } |
1216 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot | 1428 | //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot |
1217 | public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) | 1429 | public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) |
1218 | { | 1430 | { |
1219 | IndexedMatrix relativeTransform = new IndexedMatrix(); | 1431 | IndexedMatrix relativeTransform = new IndexedMatrix(); |
1220 | CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; | 1432 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; |
1221 | CollisionShape addshape = ((BulletShapeXNA)paddShape).shape; | 1433 | CollisionShape addshape = (paddShape as BulletShapeXNA).shape; |
1222 | 1434 | ||
1223 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); | 1435 | relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); |
1224 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); | 1436 | relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); |
@@ -1228,15 +1440,155 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1228 | 1440 | ||
1229 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) | 1441 | public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) |
1230 | { | 1442 | { |
1231 | CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape; | 1443 | CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; |
1232 | CollisionShape ret = null; | 1444 | CollisionShape ret = null; |
1233 | ret = compoundshape.GetChildShape(pii); | 1445 | ret = compoundshape.GetChildShape(pii); |
1234 | compoundshape.RemoveChildShapeByIndex(pii); | 1446 | compoundshape.RemoveChildShapeByIndex(pii); |
1235 | return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN); | 1447 | return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); |
1448 | } | ||
1449 | |||
1450 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { | ||
1451 | |||
1452 | if (cShape == null) | ||
1453 | return null; | ||
1454 | CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; | ||
1455 | CollisionShape shape = compoundShape.GetChildShape(indx); | ||
1456 | BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); | ||
1457 | |||
1458 | |||
1459 | return retShape; | ||
1460 | } | ||
1461 | |||
1462 | public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) | ||
1463 | { | ||
1464 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1465 | switch (pin) | ||
1466 | { | ||
1467 | case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: | ||
1468 | ret = BSPhysicsShapeType.SHAPE_BOX; | ||
1469 | break; | ||
1470 | case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: | ||
1471 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1472 | break; | ||
1473 | |||
1474 | case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: | ||
1475 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1476 | break; | ||
1477 | case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: | ||
1478 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1479 | break; | ||
1480 | case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: | ||
1481 | ret = BSPhysicsShapeType.SHAPE_HULL; | ||
1482 | break; | ||
1483 | case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: | ||
1484 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1485 | break; | ||
1486 | case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: | ||
1487 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1488 | break; | ||
1489 | //implicit convex shapes | ||
1490 | case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: | ||
1491 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1492 | break; | ||
1493 | case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: | ||
1494 | ret = BSPhysicsShapeType.SHAPE_SPHERE; | ||
1495 | break; | ||
1496 | case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: | ||
1497 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1498 | break; | ||
1499 | case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: | ||
1500 | ret = BSPhysicsShapeType.SHAPE_CAPSULE; | ||
1501 | break; | ||
1502 | case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: | ||
1503 | ret = BSPhysicsShapeType.SHAPE_CONE; | ||
1504 | break; | ||
1505 | case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: | ||
1506 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1507 | break; | ||
1508 | case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: | ||
1509 | ret = BSPhysicsShapeType.SHAPE_CYLINDER; | ||
1510 | break; | ||
1511 | case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: | ||
1512 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1513 | break; | ||
1514 | case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: | ||
1515 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1516 | break; | ||
1517 | case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: | ||
1518 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1519 | break; | ||
1520 | case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: | ||
1521 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1522 | break; | ||
1523 | case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: | ||
1524 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1525 | break; | ||
1526 | case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: | ||
1527 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1528 | break; | ||
1529 | //concave shape | ||
1530 | case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: | ||
1531 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1532 | break; | ||
1533 | //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! | ||
1534 | case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1535 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1536 | break; | ||
1537 | case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: | ||
1538 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1539 | break; | ||
1540 | ///used for demo integration FAST/Swift collision library and Bullet | ||
1541 | case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: | ||
1542 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1543 | break; | ||
1544 | //terrain | ||
1545 | case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: | ||
1546 | ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; | ||
1547 | break; | ||
1548 | ///Used for GIMPACT Trimesh integration | ||
1549 | case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: | ||
1550 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1551 | break; | ||
1552 | ///Multimaterial mesh | ||
1553 | case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: | ||
1554 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1555 | break; | ||
1556 | |||
1557 | case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: | ||
1558 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1559 | break; | ||
1560 | case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: | ||
1561 | ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; | ||
1562 | break; | ||
1563 | case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: | ||
1564 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1565 | break; | ||
1566 | case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: | ||
1567 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1568 | break; | ||
1569 | |||
1570 | case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: | ||
1571 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
1572 | break; | ||
1573 | |||
1574 | case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: | ||
1575 | ret = BSPhysicsShapeType.SHAPE_MESH; | ||
1576 | break; | ||
1577 | case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: | ||
1578 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1579 | break; | ||
1580 | case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: | ||
1581 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1582 | break; | ||
1583 | case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: | ||
1584 | ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
1585 | break; | ||
1586 | } | ||
1587 | return ret; | ||
1236 | } | 1588 | } |
1237 | 1589 | ||
1238 | public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; } | ||
1239 | public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } | 1590 | public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } |
1591 | public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } | ||
1240 | 1592 | ||
1241 | public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) | 1593 | public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) |
1242 | { | 1594 | { |
@@ -1246,18 +1598,144 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1246 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 1598 | return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
1247 | } | 1599 | } |
1248 | 1600 | ||
1249 | public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | 1601 | public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, |
1602 | Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, | ||
1603 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1604 | |||
1605 | { | ||
1606 | Generic6DofSpringConstraint constrain = null; | ||
1607 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1608 | RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1609 | RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1610 | if (body1 != null && body2 != null) | ||
1611 | { | ||
1612 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1613 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1614 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1615 | frame1._origin = frame1v; | ||
1616 | |||
1617 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1618 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1619 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1620 | frame2._origin = frame1v; | ||
1621 | |||
1622 | constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1623 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1624 | |||
1625 | constrain.CalculateTransforms(); | ||
1626 | } | ||
1627 | |||
1628 | return new BulletConstraintXNA(constrain); | ||
1629 | } | ||
1630 | |||
1631 | public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1632 | Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, | ||
1633 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1250 | { | 1634 | { |
1251 | HingeConstraint constrain = null; | 1635 | HingeConstraint constrain = null; |
1252 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1636 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1253 | RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody; | 1637 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; |
1254 | RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody; | 1638 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; |
1255 | if (rb1 != null && rb2 != null) | 1639 | if (rb1 != null && rb2 != null) |
1256 | { | 1640 | { |
1257 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | 1641 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); |
1258 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | 1642 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); |
1259 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | 1643 | IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); |
1260 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | 1644 | IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); |
1645 | constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); | ||
1646 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1647 | } | ||
1648 | return new BulletConstraintXNA(constrain); | ||
1649 | } | ||
1650 | |||
1651 | public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1652 | Vector3 pframe1, Quaternion pframe1rot, | ||
1653 | Vector3 pframe2, Quaternion pframe2rot, | ||
1654 | bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) | ||
1655 | { | ||
1656 | SliderConstraint constrain = null; | ||
1657 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1658 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1659 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1660 | if (rb1 != null && rb2 != null) | ||
1661 | { | ||
1662 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1663 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1664 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1665 | frame1._origin = frame1v; | ||
1666 | |||
1667 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1668 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1669 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1670 | frame2._origin = frame1v; | ||
1671 | |||
1672 | constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); | ||
1673 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1674 | } | ||
1675 | return new BulletConstraintXNA(constrain); | ||
1676 | } | ||
1677 | |||
1678 | public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1679 | Vector3 pframe1, Quaternion pframe1rot, | ||
1680 | Vector3 pframe2, Quaternion pframe2rot, | ||
1681 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1682 | { | ||
1683 | ConeTwistConstraint constrain = null; | ||
1684 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1685 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1686 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1687 | if (rb1 != null && rb2 != null) | ||
1688 | { | ||
1689 | IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); | ||
1690 | IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); | ||
1691 | IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); | ||
1692 | frame1._origin = frame1v; | ||
1693 | |||
1694 | IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); | ||
1695 | IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); | ||
1696 | IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); | ||
1697 | frame2._origin = frame1v; | ||
1698 | |||
1699 | constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); | ||
1700 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1701 | } | ||
1702 | return new BulletConstraintXNA(constrain); | ||
1703 | } | ||
1704 | |||
1705 | public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1706 | Vector3 paxisInA, Vector3 paxisInB, | ||
1707 | float pratio, bool pdisableCollisionsBetweenLinkedBodies) | ||
1708 | { | ||
1709 | Generic6DofConstraint constrain = null; | ||
1710 | /* BulletXNA does not have a gear constraint | ||
1711 | GearConstraint constrain = null; | ||
1712 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1713 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1714 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1715 | if (rb1 != null && rb2 != null) | ||
1716 | { | ||
1717 | IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); | ||
1718 | IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); | ||
1719 | constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); | ||
1720 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | ||
1721 | } | ||
1722 | */ | ||
1723 | return new BulletConstraintXNA(constrain); | ||
1724 | } | ||
1725 | |||
1726 | public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, | ||
1727 | Vector3 ppivotInA, Vector3 ppivotInB, | ||
1728 | bool pdisableCollisionsBetweenLinkedBodies) | ||
1729 | { | ||
1730 | Point2PointConstraint constrain = null; | ||
1731 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; | ||
1732 | RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; | ||
1733 | RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; | ||
1734 | if (rb1 != null && rb2 != null) | ||
1735 | { | ||
1736 | IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); | ||
1737 | IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); | ||
1738 | constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); | ||
1261 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); | 1739 | world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); |
1262 | } | 1740 | } |
1263 | return new BulletConstraintXNA(constrain); | 1741 | return new BulletConstraintXNA(constrain); |
@@ -1265,9 +1743,9 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1265 | 1743 | ||
1266 | public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) | 1744 | public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) |
1267 | { | 1745 | { |
1268 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1746 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1269 | CompoundShape compoundshape = new CompoundShape(false); | 1747 | CompoundShape compoundshape = new CompoundShape(false); |
1270 | 1748 | ||
1271 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); | 1749 | compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); |
1272 | int ii = 1; | 1750 | int ii = 1; |
1273 | 1751 | ||
@@ -1283,7 +1761,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1283 | int ender = ((ii + 4) + (vertexCount*3)); | 1761 | int ender = ((ii + 4) + (vertexCount*3)); |
1284 | for (int iii = ii + 4; iii < ender; iii+=3) | 1762 | for (int iii = ii + 4; iii < ender; iii+=3) |
1285 | { | 1763 | { |
1286 | 1764 | ||
1287 | 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])); |
1288 | } | 1766 | } |
1289 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); | 1767 | ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); |
@@ -1291,26 +1769,39 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1291 | compoundshape.AddChildShape(ref childTrans, convexShape); | 1769 | compoundshape.AddChildShape(ref childTrans, convexShape); |
1292 | ii += (vertexCount*3 + 4); | 1770 | ii += (vertexCount*3 + 4); |
1293 | } | 1771 | } |
1294 | 1772 | ||
1295 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); | 1773 | return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); |
1296 | } | 1774 | } |
1297 | 1775 | ||
1298 | public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; } | 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) | ||
1782 | { | ||
1783 | /* TODO */ return null; | ||
1784 | } | ||
1785 | |||
1786 | public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) | ||
1787 | { | ||
1788 | /* TODO */ return null; | ||
1789 | } | ||
1299 | 1790 | ||
1300 | 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) |
1301 | { | 1792 | { |
1302 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); | 1793 | //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); |
1303 | 1794 | ||
1304 | for (int iter = 0; iter < pVerticesCount; iter++) | 1795 | for (int iter = 0; iter < pVerticesCount; iter++) |
1305 | { | 1796 | { |
1306 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; | 1797 | if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; |
1307 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; | 1798 | if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; |
1308 | } | 1799 | } |
1309 | 1800 | ||
1310 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); | 1801 | ObjectArray<int> indicesarr = new ObjectArray<int>(indices); |
1311 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); | 1802 | ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats); |
1312 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); | 1803 | DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); |
1313 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1804 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1314 | IndexedMesh mesh = new IndexedMesh(); | 1805 | IndexedMesh mesh = new IndexedMesh(); |
1315 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; | 1806 | mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; |
1316 | mesh.m_numTriangles = pIndicesCount/3; | 1807 | mesh.m_numTriangles = pIndicesCount/3; |
@@ -1320,7 +1811,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1320 | mesh.m_vertexStride = 3; | 1811 | mesh.m_vertexStride = 3; |
1321 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1812 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1322 | mesh.m_triangleIndexStride = 3; | 1813 | mesh.m_triangleIndexStride = 3; |
1323 | 1814 | ||
1324 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1815 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1325 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1816 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1326 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); | 1817 | BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); |
@@ -1331,7 +1822,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1331 | } | 1822 | } |
1332 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) | 1823 | public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount ) |
1333 | { | 1824 | { |
1334 | 1825 | ||
1335 | String fileName = "objTest3.raw"; | 1826 | String fileName = "objTest3.raw"; |
1336 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); | 1827 | String completePath = System.IO.Path.Combine(Util.configDir(), fileName); |
1337 | StreamWriter sw = new StreamWriter(completePath); | 1828 | StreamWriter sw = new StreamWriter(completePath); |
@@ -1357,7 +1848,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1357 | string s = vertices[indices[i * 3]].ToString("0.0000"); | 1848 | string s = vertices[indices[i * 3]].ToString("0.0000"); |
1358 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); | 1849 | s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); |
1359 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); | 1850 | s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); |
1360 | 1851 | ||
1361 | sw.Write(s + "\n"); | 1852 | sw.Write(s + "\n"); |
1362 | } | 1853 | } |
1363 | 1854 | ||
@@ -1379,7 +1870,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1379 | mesh.m_vertexStride = 3; | 1870 | mesh.m_vertexStride = 3; |
1380 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; | 1871 | mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; |
1381 | mesh.m_triangleIndexStride = 3; | 1872 | mesh.m_triangleIndexStride = 3; |
1382 | 1873 | ||
1383 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); | 1874 | TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); |
1384 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); | 1875 | tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); |
1385 | 1876 | ||
@@ -1410,7 +1901,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1410 | sw.Close(); | 1901 | sw.Close(); |
1411 | } | 1902 | } |
1412 | 1903 | ||
1413 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 1904 | public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
1414 | float scaleFactor, float collisionMargin) | 1905 | float scaleFactor, float collisionMargin) |
1415 | { | 1906 | { |
1416 | const int upAxis = 2; | 1907 | const int upAxis = 2; |
@@ -1426,7 +1917,7 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1426 | 1917 | ||
1427 | public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) | 1918 | public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) |
1428 | { | 1919 | { |
1429 | TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain; | 1920 | TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; |
1430 | bool onOff = ponOff != 0; | 1921 | bool onOff = ponOff != 0; |
1431 | bool ret = false; | 1922 | bool ret = false; |
1432 | 1923 | ||
@@ -1452,64 +1943,73 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1452 | /* TODO */ | 1943 | /* TODO */ |
1453 | updatedEntityCount = 0; | 1944 | updatedEntityCount = 0; |
1454 | collidersCount = 0; | 1945 | collidersCount = 0; |
1455 | return 1; | 1946 | |
1947 | |||
1948 | int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); | ||
1949 | |||
1950 | return ret; | ||
1456 | } | 1951 | } |
1457 | 1952 | ||
1458 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, | 1953 | private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, |
1459 | out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, | 1954 | out int updatedEntityCount, out EntityProperties[] updatedEntities, |
1460 | out int collidersCount, out List<BulletXNA.CollisionDesc>colliders) | 1955 | out int collidersCount, out CollisionDesc[] colliders) |
1461 | { | 1956 | { |
1462 | int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, | 1957 | int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, |
1463 | out collidersCount, out colliders); | 1958 | out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); |
1464 | return epic; | 1959 | return epic; |
1465 | } | 1960 | } |
1466 | 1961 | ||
1467 | private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders) | 1962 | private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, |
1963 | out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) | ||
1468 | { | 1964 | { |
1469 | int numSimSteps = 0; | 1965 | int numSimSteps = 0; |
1470 | 1966 | Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); | |
1967 | Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); | ||
1968 | LastEntityProperty=0; | ||
1969 | |||
1970 | |||
1471 | 1971 | ||
1472 | //if (updatedEntities is null) | ||
1473 | // updatedEntities = new List<BulletXNA.EntityProperties>(); | ||
1474 | 1972 | ||
1475 | //if (colliders is null) | 1973 | |
1476 | // colliders = new List<BulletXNA.CollisionDesc>(); | 1974 | |
1477 | 1975 | LastCollisionDesc=0; | |
1976 | |||
1977 | updatedEntityCount = 0; | ||
1978 | collidersCount = 0; | ||
1979 | |||
1478 | 1980 | ||
1479 | if (pWorld is BulletWorldXNA) | 1981 | if (pWorld is BulletWorldXNA) |
1480 | { | 1982 | { |
1481 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 1983 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1482 | 1984 | ||
1985 | world.LastCollisionDesc = 0; | ||
1986 | world.LastEntityProperty = 0; | ||
1483 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); | 1987 | numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); |
1484 | int updates = 0; | 1988 | int updates = 0; |
1485 | 1989 | ||
1486 | updatedEntityCount = world.UpdatedObjects.Count; | 1990 | PersistentManifold contactManifold; |
1487 | updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects); | 1991 | CollisionObject objA; |
1488 | updatedEntityCount = updatedEntities.Count; | 1992 | CollisionObject objB; |
1489 | world.UpdatedObjects.Clear(); | 1993 | ManifoldPoint manifoldPoint; |
1490 | 1994 | PairCachingGhostObject pairCachingGhostObject; | |
1491 | 1995 | ||
1492 | collidersCount = world.UpdatedCollisions.Count; | ||
1493 | colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions); | ||
1494 | |||
1495 | world.UpdatedCollisions.Clear(); | ||
1496 | m_collisionsThisFrame = 0; | 1996 | m_collisionsThisFrame = 0; |
1497 | int numManifolds = world.GetDispatcher().GetNumManifolds(); | 1997 | int numManifolds = world.GetDispatcher().GetNumManifolds(); |
1498 | for (int j = 0; j < numManifolds; j++) | 1998 | for (int j = 0; j < numManifolds; j++) |
1499 | { | 1999 | { |
1500 | PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); | 2000 | contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); |
1501 | int numContacts = contactManifold.GetNumContacts(); | 2001 | int numContacts = contactManifold.GetNumContacts(); |
1502 | if (numContacts == 0) | 2002 | if (numContacts == 0) |
1503 | continue; | 2003 | continue; |
1504 | 2004 | ||
1505 | CollisionObject objA = contactManifold.GetBody0() as CollisionObject; | 2005 | objA = contactManifold.GetBody0() as CollisionObject; |
1506 | CollisionObject objB = contactManifold.GetBody1() as CollisionObject; | 2006 | objB = contactManifold.GetBody1() as CollisionObject; |
1507 | 2007 | ||
1508 | ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0); | 2008 | manifoldPoint = contactManifold.GetContactPoint(0); |
1509 | IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); | 2009 | //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); |
1510 | IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A | 2010 | // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A |
1511 | 2011 | ||
1512 | RecordCollision(world, objA, objB, contactPoint, contactNormal); | 2012 | RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); |
1513 | m_collisionsThisFrame ++; | 2013 | m_collisionsThisFrame ++; |
1514 | if (m_collisionsThisFrame >= 9999999) | 2014 | if (m_collisionsThisFrame >= 9999999) |
1515 | break; | 2015 | break; |
@@ -1517,23 +2017,91 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1517 | 2017 | ||
1518 | } | 2018 | } |
1519 | 2019 | ||
2020 | foreach (GhostObject ghostObject in specialCollisionObjects.Values) | ||
2021 | { | ||
2022 | pairCachingGhostObject = ghostObject as PairCachingGhostObject; | ||
2023 | if (pairCachingGhostObject != null) | ||
2024 | { | ||
2025 | RecordGhostCollisions(pairCachingGhostObject); | ||
2026 | } | ||
2027 | |||
2028 | } | ||
2029 | |||
2030 | |||
2031 | updatedEntityCount = LastEntityProperty; | ||
2032 | updatedEntities = UpdatedObjects; | ||
2033 | |||
2034 | collidersCount = LastCollisionDesc; | ||
2035 | colliders = UpdatedCollisions; | ||
2036 | |||
1520 | 2037 | ||
1521 | } | 2038 | } |
1522 | else | 2039 | else |
1523 | { | 2040 | { |
1524 | //if (updatedEntities is null) | 2041 | //if (updatedEntities is null) |
1525 | updatedEntities = new List<BulletXNA.EntityProperties>(); | 2042 | //updatedEntities = new List<BulletXNA.EntityProperties>(); |
1526 | updatedEntityCount = 0; | 2043 | //updatedEntityCount = 0; |
1527 | //if (colliders is null) | 2044 | |
1528 | colliders = new List<BulletXNA.CollisionDesc>(); | 2045 | |
1529 | collidersCount = 0; | 2046 | //collidersCount = 0; |
2047 | |||
2048 | updatedEntities = new EntityProperties[0]; | ||
2049 | |||
2050 | |||
2051 | colliders = new CollisionDesc[0]; | ||
2052 | |||
1530 | } | 2053 | } |
1531 | return numSimSteps; | 2054 | return numSimSteps; |
1532 | } | 2055 | } |
2056 | public void RecordGhostCollisions(PairCachingGhostObject obj) | ||
2057 | { | ||
2058 | IOverlappingPairCache cache = obj.GetOverlappingPairCache(); | ||
2059 | ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray(); | ||
2060 | |||
2061 | DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; | ||
2062 | PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); | ||
2063 | BroadphasePair collisionPair; | ||
2064 | PersistentManifold contactManifold; | ||
2065 | |||
2066 | CollisionObject objA; | ||
2067 | CollisionObject objB; | ||
2068 | |||
2069 | ManifoldPoint pt; | ||
1533 | 2070 | ||
1534 | private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm) | 2071 | int numPairs = pairs.Count; |
2072 | |||
2073 | for (int i = 0; i < numPairs; i++) | ||
2074 | { | ||
2075 | manifoldArray.Clear(); | ||
2076 | if (LastCollisionDesc < UpdatedCollisions.Length) | ||
2077 | break; | ||
2078 | collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); | ||
2079 | if (collisionPair == null) | ||
2080 | continue; | ||
2081 | |||
2082 | collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); | ||
2083 | for (int j = 0; j < manifoldArray.Count; j++) | ||
2084 | { | ||
2085 | contactManifold = manifoldArray[j]; | ||
2086 | int numContacts = contactManifold.GetNumContacts(); | ||
2087 | objA = contactManifold.GetBody0() as CollisionObject; | ||
2088 | objB = contactManifold.GetBody1() as CollisionObject; | ||
2089 | for (int p = 0; p < numContacts; p++) | ||
2090 | { | ||
2091 | pt = contactManifold.GetContactPoint(p); | ||
2092 | if (pt.GetDistance() < 0.0f) | ||
2093 | { | ||
2094 | RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); | ||
2095 | break; | ||
2096 | } | ||
2097 | } | ||
2098 | } | ||
2099 | } | ||
2100 | |||
2101 | } | ||
2102 | private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) | ||
1535 | { | 2103 | { |
1536 | 2104 | ||
1537 | IndexedVector3 contactNormal = norm; | 2105 | IndexedVector3 contactNormal = norm; |
1538 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && | 2106 | if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && |
1539 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) | 2107 | (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) |
@@ -1550,31 +2118,34 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1550 | contactNormal = -contactNormal; | 2118 | contactNormal = -contactNormal; |
1551 | } | 2119 | } |
1552 | 2120 | ||
1553 | ulong collisionID = ((ulong) idA << 32) | idB; | 2121 | //ulong collisionID = ((ulong) idA << 32) | idB; |
1554 | 2122 | ||
1555 | BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc() | 2123 | CollisionDesc cDesc = new CollisionDesc() |
1556 | { | 2124 | { |
1557 | aID = idA, | 2125 | aID = idA, |
1558 | bID = idB, | 2126 | bID = idB, |
1559 | point = contact, | 2127 | point = new Vector3(contact.X,contact.Y,contact.Z), |
1560 | normal = contactNormal | 2128 | normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), |
2129 | penetration = penetration | ||
2130 | |||
1561 | }; | 2131 | }; |
1562 | world.UpdatedCollisions.Add(cDesc); | 2132 | if (world.LastCollisionDesc < world.UpdatedCollisions.Length) |
2133 | world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); | ||
1563 | m_collisionsThisFrame++; | 2134 | m_collisionsThisFrame++; |
1564 | 2135 | ||
1565 | 2136 | ||
1566 | } | 2137 | } |
1567 | private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody) | 2138 | private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) |
1568 | { | 2139 | { |
1569 | EntityProperties ent = new EntityProperties(); | 2140 | EntityProperties ent = new EntityProperties(); |
1570 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 2141 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1571 | RigidBody body = ((BulletBodyXNA)pBody).rigidBody; | 2142 | CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; |
1572 | IndexedMatrix transform = body.GetWorldTransform(); | 2143 | IndexedMatrix transform = collisionObject.GetWorldTransform(); |
1573 | IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity(); | 2144 | IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); |
1574 | IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity(); | 2145 | IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); |
1575 | IndexedQuaternion rotation = transform.GetRotation(); | 2146 | IndexedQuaternion rotation = transform.GetRotation(); |
1576 | ent.Acceleration = Vector3.Zero; | 2147 | ent.Acceleration = Vector3.Zero; |
1577 | ent.ID = (uint)body.GetUserPointer(); | 2148 | ent.ID = (uint)collisionObject.GetUserPointer(); |
1578 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); | 2149 | ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); |
1579 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); | 2150 | ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); |
1580 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); | 2151 | ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); |
@@ -1582,28 +2153,29 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1582 | return ent; | 2153 | return ent; |
1583 | } | 2154 | } |
1584 | 2155 | ||
1585 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; } | 2156 | public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ |
2157 | return false; } | ||
1586 | 2158 | ||
1587 | public override Vector3 GetLocalScaling(BulletShape pShape) | 2159 | public override Vector3 GetLocalScaling(BulletShape pShape) |
1588 | { | 2160 | { |
1589 | CollisionShape shape = ((BulletShapeXNA)pShape).shape; | 2161 | CollisionShape shape = (pShape as BulletShapeXNA).shape; |
1590 | IndexedVector3 scale = shape.GetLocalScaling(); | 2162 | IndexedVector3 scale = shape.GetLocalScaling(); |
1591 | return new Vector3(scale.X,scale.Y,scale.Z); | 2163 | return new Vector3(scale.X,scale.Y,scale.Z); |
1592 | } | 2164 | } |
1593 | 2165 | ||
1594 | public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) | 2166 | public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) |
1595 | { | 2167 | { |
1596 | DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world; | 2168 | DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; |
1597 | if (world != null) | 2169 | if (world != null) |
1598 | { | 2170 | { |
1599 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) | 2171 | if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) |
1600 | { | 2172 | { |
1601 | CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body; | 2173 | CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; |
1602 | 2174 | ||
1603 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); | 2175 | IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); |
1604 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); | 2176 | IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); |
1605 | using ( | 2177 | using ( |
1606 | ClosestNotMeRayResultCallback rayCallback = | 2178 | ClosestNotMeRayResultCallback rayCallback = |
1607 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) | 2179 | new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) |
1608 | ) | 2180 | ) |
1609 | { | 2181 | { |
@@ -1619,4 +2191,130 @@ private sealed class BulletConstraintXNA : BulletConstraint | |||
1619 | return false; | 2191 | return false; |
1620 | } | 2192 | } |
1621 | } | 2193 | } |
2194 | |||
2195 | |||
2196 | |||
2197 | |||
2198 | public class SimMotionState : DefaultMotionState | ||
2199 | { | ||
2200 | public RigidBody Rigidbody; | ||
2201 | public Vector3 ZeroVect; | ||
2202 | |||
2203 | private IndexedMatrix m_xform; | ||
2204 | |||
2205 | private EntityProperties m_properties; | ||
2206 | private EntityProperties m_lastProperties; | ||
2207 | private BSAPIXNA m_world; | ||
2208 | |||
2209 | const float POSITION_TOLERANCE = 0.05f; | ||
2210 | const float VELOCITY_TOLERANCE = 0.001f; | ||
2211 | const float ROTATION_TOLERANCE = 0.01f; | ||
2212 | const float ANGULARVELOCITY_TOLERANCE = 0.01f; | ||
2213 | |||
2214 | public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates) | ||
2215 | { | ||
2216 | IndexedQuaternion OrientationQuaterion = starTransform.GetRotation(); | ||
2217 | m_properties = new EntityProperties() | ||
2218 | { | ||
2219 | ID = id, | ||
2220 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z), | ||
2221 | Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W) | ||
2222 | }; | ||
2223 | m_lastProperties = new EntityProperties() | ||
2224 | { | ||
2225 | ID = id, | ||
2226 | Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z), | ||
2227 | Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W) | ||
2228 | }; | ||
2229 | m_world = pWorld; | ||
2230 | m_xform = starTransform; | ||
2231 | } | ||
2232 | |||
2233 | public override void GetWorldTransform(out IndexedMatrix worldTrans) | ||
2234 | { | ||
2235 | worldTrans = m_xform; | ||
2236 | } | ||
2237 | |||
2238 | public override void SetWorldTransform(IndexedMatrix worldTrans) | ||
2239 | { | ||
2240 | SetWorldTransform(ref worldTrans); | ||
2241 | } | ||
2242 | |||
2243 | public override void SetWorldTransform(ref IndexedMatrix worldTrans) | ||
2244 | { | ||
2245 | SetWorldTransform(ref worldTrans, false); | ||
2246 | } | ||
2247 | public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force) | ||
2248 | { | ||
2249 | m_xform = worldTrans; | ||
2250 | // Put the new transform into m_properties | ||
2251 | IndexedQuaternion OrientationQuaternion = m_xform.GetRotation(); | ||
2252 | IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity(); | ||
2253 | IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity(); | ||
2254 | m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z); | ||
2255 | m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y, | ||
2256 | OrientationQuaternion.Z, OrientationQuaternion.W); | ||
2257 | // A problem with stock Bullet is that we don't get an event when an object is deactivated. | ||
2258 | // This means that the last non-zero values for linear and angular velocity | ||
2259 | // are left in the viewer who does dead reconning and the objects look like | ||
2260 | // they float off. | ||
2261 | // BulletSim ships with a patch to Bullet which creates such an event. | ||
2262 | m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z); | ||
2263 | m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z); | ||
2264 | |||
2265 | if (force | ||
2266 | |||
2267 | || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE) | ||
2268 | || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE) | ||
2269 | // If the Velocity and AngularVelocity are zero, most likely the object has | ||
2270 | // been deactivated. If they both are zero and they have become zero recently, | ||
2271 | // make sure a property update is sent so the zeros make it to the viewer. | ||
2272 | || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect) | ||
2273 | && | ||
2274 | (m_properties.Velocity != m_lastProperties.Velocity || | ||
2275 | m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity)) | ||
2276 | // If Velocity and AngularVelocity are non-zero but have changed, send an update. | ||
2277 | || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE) | ||
2278 | || | ||
2279 | !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity, | ||
2280 | ANGULARVELOCITY_TOLERANCE) | ||
2281 | ) | ||
2282 | |||
2283 | |||
2284 | { | ||
2285 | // Add this update to the list of updates for this frame. | ||
2286 | m_lastProperties = m_properties; | ||
2287 | if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length) | ||
2288 | m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties); | ||
2289 | |||
2290 | //(*m_updatesThisFrame)[m_properties.ID] = &m_properties; | ||
2291 | } | ||
2292 | |||
2293 | |||
2294 | |||
2295 | |||
2296 | } | ||
2297 | public override void SetRigidBody(RigidBody body) | ||
2298 | { | ||
2299 | Rigidbody = body; | ||
2300 | } | ||
2301 | internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon) | ||
2302 | { | ||
2303 | return | ||
2304 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2305 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2306 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))); | ||
2307 | } | ||
2308 | |||
2309 | internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon) | ||
2310 | { | ||
2311 | return | ||
2312 | (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) && | ||
2313 | (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) && | ||
2314 | (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && | ||
2315 | (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); | ||
2316 | } | ||
2317 | |||
2318 | } | ||
1622 | } | 2319 | } |
2320 | |||
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 8ad78ca..3378c93 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs | |||
@@ -6,7 +6,7 @@ | |||
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyrightD | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
@@ -70,6 +70,7 @@ 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, | ||
73 | }; | 74 | }; |
74 | 75 | ||
75 | // The native shapes have predefined shape hash keys | 76 | // The native shapes have predefined shape hash keys |
@@ -87,7 +88,7 @@ public enum FixedShapeKey : ulong | |||
87 | [StructLayout(LayoutKind.Sequential)] | 88 | [StructLayout(LayoutKind.Sequential)] |
88 | public struct ShapeData | 89 | public struct ShapeData |
89 | { | 90 | { |
90 | public uint ID; | 91 | public UInt32 ID; |
91 | public BSPhysicsShapeType Type; | 92 | public BSPhysicsShapeType Type; |
92 | public Vector3 Position; | 93 | public Vector3 Position; |
93 | public Quaternion Rotation; | 94 | public Quaternion Rotation; |
@@ -111,7 +112,7 @@ public struct ShapeData | |||
111 | [StructLayout(LayoutKind.Sequential)] | 112 | [StructLayout(LayoutKind.Sequential)] |
112 | public struct SweepHit | 113 | public struct SweepHit |
113 | { | 114 | { |
114 | public uint ID; | 115 | public UInt32 ID; |
115 | public float Fraction; | 116 | public float Fraction; |
116 | public Vector3 Normal; | 117 | public Vector3 Normal; |
117 | public Vector3 Point; | 118 | public Vector3 Point; |
@@ -119,27 +120,47 @@ public struct SweepHit | |||
119 | [StructLayout(LayoutKind.Sequential)] | 120 | [StructLayout(LayoutKind.Sequential)] |
120 | public struct RaycastHit | 121 | public struct RaycastHit |
121 | { | 122 | { |
122 | public uint ID; | 123 | public UInt32 ID; |
123 | public float Fraction; | 124 | public float Fraction; |
124 | public Vector3 Normal; | 125 | public Vector3 Normal; |
125 | } | 126 | } |
126 | [StructLayout(LayoutKind.Sequential)] | 127 | [StructLayout(LayoutKind.Sequential)] |
127 | public struct CollisionDesc | 128 | public struct CollisionDesc |
128 | { | 129 | { |
129 | public uint aID; | 130 | public UInt32 aID; |
130 | public uint bID; | 131 | public UInt32 bID; |
131 | public Vector3 point; | 132 | public Vector3 point; |
132 | public Vector3 normal; | 133 | public Vector3 normal; |
134 | public float penetration; | ||
133 | } | 135 | } |
134 | [StructLayout(LayoutKind.Sequential)] | 136 | [StructLayout(LayoutKind.Sequential)] |
135 | public struct EntityProperties | 137 | public struct EntityProperties |
136 | { | 138 | { |
137 | public uint ID; | 139 | public UInt32 ID; |
138 | public Vector3 Position; | 140 | public Vector3 Position; |
139 | public Quaternion Rotation; | 141 | public Quaternion Rotation; |
140 | public Vector3 Velocity; | 142 | public Vector3 Velocity; |
141 | public Vector3 Acceleration; | 143 | public Vector3 Acceleration; |
142 | public Vector3 RotationalVelocity; | 144 | public Vector3 RotationalVelocity; |
145 | |||
146 | public override string ToString() | ||
147 | { | ||
148 | StringBuilder buff = new StringBuilder(); | ||
149 | buff.Append("<i="); | ||
150 | buff.Append(ID.ToString()); | ||
151 | buff.Append(",p="); | ||
152 | buff.Append(Position.ToString()); | ||
153 | buff.Append(",r="); | ||
154 | buff.Append(Rotation.ToString()); | ||
155 | buff.Append(",v="); | ||
156 | buff.Append(Velocity.ToString()); | ||
157 | buff.Append(",a="); | ||
158 | buff.Append(Acceleration.ToString()); | ||
159 | buff.Append(",rv="); | ||
160 | buff.Append(RotationalVelocity.ToString()); | ||
161 | buff.Append(">"); | ||
162 | return buff.ToString(); | ||
163 | } | ||
143 | } | 164 | } |
144 | 165 | ||
145 | // Format of this structure must match the definition in the C++ code | 166 | // Format of this structure must match the definition in the C++ code |
@@ -154,32 +175,6 @@ public struct ConfigurationParameters | |||
154 | public float collisionMargin; | 175 | public float collisionMargin; |
155 | public float gravity; | 176 | public float gravity; |
156 | 177 | ||
157 | public float XlinearDamping; | ||
158 | public float XangularDamping; | ||
159 | public float XdeactivationTime; | ||
160 | public float XlinearSleepingThreshold; | ||
161 | public float XangularSleepingThreshold; | ||
162 | public float XccdMotionThreshold; | ||
163 | public float XccdSweptSphereRadius; | ||
164 | public float XcontactProcessingThreshold; | ||
165 | |||
166 | public float XterrainImplementation; | ||
167 | public float XterrainFriction; | ||
168 | public float XterrainHitFraction; | ||
169 | public float XterrainRestitution; | ||
170 | public float XterrainCollisionMargin; | ||
171 | |||
172 | public float XavatarFriction; | ||
173 | public float XavatarStandingFriction; | ||
174 | public float XavatarDensity; | ||
175 | public float XavatarRestitution; | ||
176 | public float XavatarCapsuleWidth; | ||
177 | public float XavatarCapsuleDepth; | ||
178 | public float XavatarCapsuleHeight; | ||
179 | public float XavatarContactProcessingThreshold; | ||
180 | |||
181 | public float XvehicleAngularDamping; | ||
182 | |||
183 | public float maxPersistantManifoldPoolSize; | 178 | public float maxPersistantManifoldPoolSize; |
184 | public float maxCollisionAlgorithmPoolSize; | 179 | public float maxCollisionAlgorithmPoolSize; |
185 | public float shouldDisableContactPoolDynamicAllocation; | 180 | public float shouldDisableContactPoolDynamicAllocation; |
@@ -188,22 +183,30 @@ public struct ConfigurationParameters | |||
188 | public float shouldSplitSimulationIslands; | 183 | public float shouldSplitSimulationIslands; |
189 | public float shouldEnableFrictionCaching; | 184 | public float shouldEnableFrictionCaching; |
190 | public float numberOfSolverIterations; | 185 | public float numberOfSolverIterations; |
186 | public float useSingleSidedMeshes; | ||
187 | public float globalContactBreakingThreshold; | ||
191 | 188 | ||
192 | public float XlinksetImplementation; | 189 | public float physicsLoggingFrames; |
193 | public float XlinkConstraintUseFrameOffset; | ||
194 | public float XlinkConstraintEnableTransMotor; | ||
195 | public float XlinkConstraintTransMotorMaxVel; | ||
196 | public float XlinkConstraintTransMotorMaxForce; | ||
197 | public float XlinkConstraintERP; | ||
198 | public float XlinkConstraintCFM; | ||
199 | public float XlinkConstraintSolverIterations; | ||
200 | |||
201 | public float XphysicsLoggingFrames; | ||
202 | 190 | ||
203 | public const float numericTrue = 1f; | 191 | public const float numericTrue = 1f; |
204 | public const float numericFalse = 0f; | 192 | public const float numericFalse = 0f; |
205 | } | 193 | } |
206 | 194 | ||
195 | // Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. | ||
196 | [StructLayout(LayoutKind.Sequential)] | ||
197 | public struct HACDParams | ||
198 | { | ||
199 | // usual default values | ||
200 | public float maxVerticesPerHull; // 100 | ||
201 | public float minClusters; // 2 | ||
202 | public float compacityWeight; // 0.1 | ||
203 | public float volumeWeight; // 0.0 | ||
204 | public float concavity; // 100 | ||
205 | public float addExtraDistPoints; // false | ||
206 | public float addNeighboursDistPoints; // false | ||
207 | public float addFacesPoints; // false | ||
208 | public float shouldAdjustCollisionMargin; // false | ||
209 | } | ||
207 | 210 | ||
208 | // The states a bullet collision object can have | 211 | // The states a bullet collision object can have |
209 | public enum ActivationState : uint | 212 | public enum ActivationState : uint |
@@ -238,9 +241,10 @@ public enum CollisionFlags : uint | |||
238 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | 241 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, |
239 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 242 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
240 | // Following used by BulletSim to control collisions and updates | 243 | // Following used by BulletSim to control collisions and updates |
241 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 244 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed |
242 | BS_FLOATS_ON_WATER = 1 << 11, | 245 | BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level |
243 | BS_VEHICLE_COLLISIONS = 1 << 12, | 246 | BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking |
247 | BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape | ||
244 | BS_NONE = 0, | 248 | BS_NONE = 0, |
245 | BS_ALL = 0xFFFFFFFF | 249 | BS_ALL = 0xFFFFFFFF |
246 | }; | 250 | }; |
@@ -294,7 +298,7 @@ public abstract class BSAPITemplate | |||
294 | { | 298 | { |
295 | // Returns the name of the underlying Bullet engine | 299 | // Returns the name of the underlying Bullet engine |
296 | public abstract string BulletEngineName { get; } | 300 | public abstract string BulletEngineName { get; } |
297 | public abstract string BulletEngineVersion { get; protected set;} | 301 | public abstract string BulletEngineVersion { get; protected set;} |
298 | 302 | ||
299 | // Initialization and simulation | 303 | // Initialization and simulation |
300 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, | 304 | public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, |
@@ -305,7 +309,7 @@ public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet | |||
305 | public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, | 309 | public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, |
306 | out int updatedEntityCount, out int collidersCount); | 310 | out int updatedEntityCount, out int collidersCount); |
307 | 311 | ||
308 | public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); | 312 | public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); |
309 | 313 | ||
310 | public abstract void Shutdown(BulletWorld sim); | 314 | public abstract void Shutdown(BulletWorld sim); |
311 | 315 | ||
@@ -320,7 +324,13 @@ public abstract BulletShape CreateMeshShape(BulletWorld world, | |||
320 | public abstract BulletShape CreateHullShape(BulletWorld world, | 324 | public abstract BulletShape CreateHullShape(BulletWorld world, |
321 | int hullCount, float[] hulls); | 325 | int hullCount, float[] hulls); |
322 | 326 | ||
323 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | 327 | public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); |
328 | |||
329 | public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); | ||
330 | |||
331 | public abstract BulletShape CreateConvexHullShape(BulletWorld world, | ||
332 | int indicesCount, int[] indices, | ||
333 | int verticesCount, float[] vertices ); | ||
324 | 334 | ||
325 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); | 335 | public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); |
326 | 336 | ||
@@ -342,26 +352,28 @@ public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape c | |||
342 | 352 | ||
343 | public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); | 353 | public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); |
344 | 354 | ||
355 | public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); | ||
356 | |||
345 | public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); | 357 | public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); |
346 | 358 | ||
347 | public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); | 359 | public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); |
348 | 360 | ||
349 | public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); | 361 | public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); |
350 | 362 | ||
351 | public abstract CollisionObjectTypes GetBodyType(BulletBody obj); | 363 | public abstract CollisionObjectTypes GetBodyType(BulletBody obj); |
352 | 364 | ||
353 | public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); | 365 | public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); |
354 | 366 | ||
355 | public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); | 367 | public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); |
356 | 368 | ||
357 | public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); | 369 | public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); |
358 | 370 | ||
359 | public abstract void DestroyObject(BulletWorld sim, BulletBody obj); | 371 | public abstract void DestroyObject(BulletWorld sim, BulletBody obj); |
360 | 372 | ||
361 | // ===================================================================================== | 373 | // ===================================================================================== |
362 | public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); | 374 | public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); |
363 | 375 | ||
364 | public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, | 376 | public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, |
365 | float scaleFactor, float collisionMargin); | 377 | float scaleFactor, float collisionMargin); |
366 | 378 | ||
367 | // ===================================================================================== | 379 | // ===================================================================================== |
@@ -375,11 +387,38 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, | |||
375 | Vector3 joinPoint, | 387 | Vector3 joinPoint, |
376 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 388 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
377 | 389 | ||
390 | public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, | ||
391 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
392 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); | ||
393 | |||
394 | public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
395 | Vector3 frame1loc, Quaternion frame1rot, | ||
396 | Vector3 frame2loc, Quaternion frame2rot, | ||
397 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
398 | |||
378 | public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | 399 | public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, |
379 | Vector3 pivotinA, Vector3 pivotinB, | 400 | Vector3 pivotinA, Vector3 pivotinB, |
380 | Vector3 axisInA, Vector3 axisInB, | 401 | Vector3 axisInA, Vector3 axisInB, |
381 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | 402 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); |
382 | 403 | ||
404 | public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
405 | Vector3 frameInAloc, Quaternion frameInArot, | ||
406 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
407 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); | ||
408 | |||
409 | public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
410 | Vector3 frameInAloc, Quaternion frameInArot, | ||
411 | Vector3 frameInBloc, Quaternion frameInBrot, | ||
412 | bool disableCollisionsBetweenLinkedBodies); | ||
413 | |||
414 | public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
415 | Vector3 axisInA, Vector3 axisInB, | ||
416 | float ratio, bool disableCollisionsBetweenLinkedBodies); | ||
417 | |||
418 | public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, | ||
419 | Vector3 pivotInA, Vector3 pivotInB, | ||
420 | bool disableCollisionsBetweenLinkedBodies); | ||
421 | |||
383 | public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); | 422 | public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); |
384 | 423 | ||
385 | public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); | 424 | public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); |
@@ -607,7 +646,7 @@ public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); | |||
607 | 646 | ||
608 | public abstract int GetNumConstraintRefs(BulletBody obj); | 647 | public abstract int GetNumConstraintRefs(BulletBody obj); |
609 | 648 | ||
610 | public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); | 649 | public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); |
611 | 650 | ||
612 | // ===================================================================================== | 651 | // ===================================================================================== |
613 | // btCollisionShape entries | 652 | // btCollisionShape entries |
@@ -646,17 +685,21 @@ public abstract float GetMargin(BulletShape shape); | |||
646 | 685 | ||
647 | // ===================================================================================== | 686 | // ===================================================================================== |
648 | // Debugging | 687 | // Debugging |
649 | public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject); | 688 | public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } |
689 | |||
690 | public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } | ||
691 | |||
692 | public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } | ||
650 | 693 | ||
651 | public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape); | 694 | public virtual void DumpActivationInfo(BulletWorld sim) { } |
652 | 695 | ||
653 | public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain); | 696 | public virtual void DumpAllInfo(BulletWorld sim) { } |
654 | 697 | ||
655 | public abstract void DumpActivationInfo(BulletWorld sim); | 698 | public virtual void DumpPhysicsStatistics(BulletWorld sim) { } |
656 | 699 | ||
657 | public abstract void DumpAllInfo(BulletWorld sim); | 700 | public virtual void ResetBroadphasePool(BulletWorld sim) { } |
658 | 701 | ||
659 | public abstract void DumpPhysicsStatistics(BulletWorld sim); | 702 | public virtual void ResetConstraintSolver(BulletWorld sim) { } |
660 | 703 | ||
661 | }; | 704 | }; |
662 | } | 705 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 103d8fc..542f732 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -45,11 +45,7 @@ public sealed class BSCharacter : BSPhysObject | |||
45 | private bool _selected; | 45 | private bool _selected; |
46 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
47 | private float _mass; | 47 | private float _mass; |
48 | private float _avatarDensity; | ||
49 | private float _avatarVolume; | 48 | private float _avatarVolume; |
50 | private OMV.Vector3 _force; | ||
51 | private OMV.Vector3 _velocity; | ||
52 | private OMV.Vector3 _torque; | ||
53 | private float _collisionScore; | 49 | private float _collisionScore; |
54 | private OMV.Vector3 _acceleration; | 50 | private OMV.Vector3 _acceleration; |
55 | private OMV.Quaternion _orientation; | 51 | private OMV.Quaternion _orientation; |
@@ -58,25 +54,17 @@ public sealed class BSCharacter : BSPhysObject | |||
58 | private bool _flying; | 54 | private bool _flying; |
59 | private bool _setAlwaysRun; | 55 | private bool _setAlwaysRun; |
60 | private bool _throttleUpdates; | 56 | private bool _throttleUpdates; |
61 | private bool _isColliding; | ||
62 | private bool _collidingObj; | ||
63 | private bool _floatOnWater; | 57 | private bool _floatOnWater; |
64 | private OMV.Vector3 _rotationalVelocity; | 58 | private OMV.Vector3 _rotationalVelocity; |
65 | private bool _kinematic; | 59 | private bool _kinematic; |
66 | private float _buoyancy; | 60 | private float _buoyancy; |
67 | 61 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | 62 | private BSActorAvatarMove m_moveActor; |
69 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | 63 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; |
70 | |||
71 | private BSVMotor _velocityMotor; | ||
72 | 64 | ||
73 | private OMV.Vector3 _PIDTarget; | 65 | private OMV.Vector3 _PIDTarget; |
74 | private bool _usePID; | 66 | private bool _usePID; |
75 | private float _PIDTau; | 67 | private float _PIDTau; |
76 | private bool _useHoverPID; | ||
77 | private float _PIDHoverHeight; | ||
78 | private PIDHoverType _PIDHoverType; | ||
79 | private float _PIDHoverTao; | ||
80 | 68 | ||
81 | 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) |
82 | : base(parent_scene, localID, avName, "BSCharacter") | 70 | : base(parent_scene, localID, avName, "BSCharacter") |
@@ -86,10 +74,10 @@ public sealed class BSCharacter : BSPhysObject | |||
86 | 74 | ||
87 | _flying = isFlying; | 75 | _flying = isFlying; |
88 | _orientation = OMV.Quaternion.Identity; | 76 | _orientation = OMV.Quaternion.Identity; |
89 | _velocity = OMV.Vector3.Zero; | 77 | RawVelocity = OMV.Vector3.Zero; |
90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 78 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
91 | _currentFriction = BSParam.AvatarStandingFriction; | 79 | Friction = BSParam.AvatarStandingFriction; |
92 | _avatarDensity = BSParam.AvatarDensity; | 80 | Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; |
93 | 81 | ||
94 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | 82 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
95 | // replace with the default values. | 83 | // replace with the default values. |
@@ -103,17 +91,22 @@ public sealed class BSCharacter : BSPhysObject | |||
103 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 91 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
104 | ComputeAvatarVolumeAndMass(); | 92 | ComputeAvatarVolumeAndMass(); |
105 | 93 | ||
106 | 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); | ||
107 | 100 | ||
108 | 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}", |
109 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 102 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
110 | 103 | ||
111 | // do actual creation in taint time | 104 | // do actual creation in taint time |
112 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 105 | PhysScene.TaintedObject("BSCharacter.create", delegate() |
113 | { | 106 | { |
114 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 107 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
115 | // New body and shape into PhysBody and PhysShape | 108 | // New body and shape into PhysBody and PhysShape |
116 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | 109 | PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); |
117 | 110 | ||
118 | SetPhysicalProperties(); | 111 | SetPhysicalProperties(); |
119 | }); | 112 | }); |
@@ -126,114 +119,63 @@ public sealed class BSCharacter : BSPhysObject | |||
126 | base.Destroy(); | 119 | base.Destroy(); |
127 | 120 | ||
128 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 121 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
129 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 122 | PhysScene.TaintedObject("BSCharacter.destroy", delegate() |
130 | { | 123 | { |
131 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 124 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
132 | PhysBody.Clear(); | 125 | PhysBody.Clear(); |
133 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 126 | PhysShape.Dereference(PhysScene); |
134 | PhysShape.Clear(); | 127 | PhysShape = new BSShapeNull(); |
135 | }); | 128 | }); |
136 | } | 129 | } |
137 | 130 | ||
138 | private void SetPhysicalProperties() | 131 | private void SetPhysicalProperties() |
139 | { | 132 | { |
140 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 133 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
141 | 134 | ||
142 | ZeroMotion(true); | 135 | ZeroMotion(true); |
143 | ForcePosition = _position; | 136 | ForcePosition = _position; |
144 | 137 | ||
145 | // Set the velocity and compute the proper friction | 138 | // Set the velocity |
146 | _velocityMotor.Reset(); | 139 | if (m_moveActor != null) |
147 | _velocityMotor.SetTarget(_velocity); | 140 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); |
148 | _velocityMotor.SetCurrent(_velocity); | 141 | |
149 | ForceVelocity = _velocity; | 142 | ForceVelocity = RawVelocity; |
150 | 143 | ||
151 | // This will enable or disable the flying buoyancy of the avatar. | 144 | // This will enable or disable the flying buoyancy of the avatar. |
152 | // 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. |
153 | Flying = _flying; | 146 | Flying = _flying; |
154 | 147 | ||
155 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | 148 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
156 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | 149 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); |
157 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 150 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
158 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 151 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
159 | if (BSParam.CcdMotionThreshold > 0f) | 152 | if (BSParam.CcdMotionThreshold > 0f) |
160 | { | 153 | { |
161 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 154 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
162 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 155 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
163 | } | 156 | } |
164 | 157 | ||
165 | UpdatePhysicalMassProperties(RawMass, false); | 158 | UpdatePhysicalMassProperties(RawMass, false); |
166 | 159 | ||
167 | // Make so capsule does not fall over | 160 | // Make so capsule does not fall over |
168 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | 161 | PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
169 | 162 | ||
170 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 163 | // The avatar mover sets some parameters. |
164 | PhysicalActors.Refresh(); | ||
171 | 165 | ||
172 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 166 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
167 | |||
168 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); | ||
173 | 169 | ||
174 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 170 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
175 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | 171 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
176 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 172 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
177 | 173 | ||
178 | // Do this after the object has been added to the world | 174 | // Do this after the object has been added to the world |
179 | PhysBody.collisionType = CollisionType.Avatar; | 175 | PhysBody.collisionType = CollisionType.Avatar; |
180 | PhysBody.ApplyCollisionMask(PhysicsScene); | 176 | PhysBody.ApplyCollisionMask(PhysScene); |
181 | } | 177 | } |
182 | 178 | ||
183 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
184 | // the avatar seeking to reach the motor's target speed. | ||
185 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
186 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
187 | private void SetupMovementMotor() | ||
188 | { | ||
189 | |||
190 | // Someday, use a PID motor for asymmetric speed up and slow down | ||
191 | // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
192 | |||
193 | // Infinite decay and timescale values so motor only changes current to target values. | ||
194 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
195 | 0.2f, // time scale | ||
196 | BSMotor.Infinite, // decay time scale | ||
197 | BSMotor.InfiniteVector, // friction timescale | ||
198 | 1f // efficiency | ||
199 | ); | ||
200 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
201 | |||
202 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
203 | { | ||
204 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
205 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
206 | |||
207 | OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); | ||
208 | |||
209 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
210 | if (!Flying && !IsColliding) | ||
211 | { | ||
212 | stepVelocity.Z = _velocity.Z; | ||
213 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
214 | } | ||
215 | |||
216 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
217 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep; | ||
218 | |||
219 | /* | ||
220 | // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user | ||
221 | float moveForceMagnitudeSquared = moveForce.LengthSquared(); | ||
222 | if (moveForceMagnitudeSquared < 0.0001) | ||
223 | { | ||
224 | DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}", | ||
225 | LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce); | ||
226 | ForceVelocity = OMV.Vector3.Zero; | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | AddForce(moveForce, false, true); | ||
231 | } | ||
232 | */ | ||
233 | // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
234 | AddForce(moveForce, false, true); | ||
235 | }); | ||
236 | } | ||
237 | 179 | ||
238 | public override void RequestPhysicsterseUpdate() | 180 | public override void RequestPhysicsterseUpdate() |
239 | { | 181 | { |
@@ -259,16 +201,16 @@ public sealed class BSCharacter : BSPhysObject | |||
259 | Scale = ComputeAvatarScale(_size); | 201 | Scale = ComputeAvatarScale(_size); |
260 | ComputeAvatarVolumeAndMass(); | 202 | ComputeAvatarVolumeAndMass(); |
261 | 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}", |
262 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 204 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
263 | 205 | ||
264 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 206 | PhysScene.TaintedObject("BSCharacter.setSize", delegate() |
265 | { | 207 | { |
266 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | 208 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) |
267 | { | 209 | { |
268 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 210 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
269 | UpdatePhysicalMassProperties(RawMass, true); | 211 | UpdatePhysicalMassProperties(RawMass, true); |
270 | // Make sure this change appears as a property update event | 212 | // Make sure this change appears as a property update event |
271 | PhysicsScene.PE.PushUpdate(PhysBody); | 213 | PhysScene.PE.PushUpdate(PhysBody); |
272 | } | 214 | } |
273 | }); | 215 | }); |
274 | 216 | ||
@@ -279,11 +221,6 @@ public sealed class BSCharacter : BSPhysObject | |||
279 | { | 221 | { |
280 | set { BaseShape = value; } | 222 | set { BaseShape = value; } |
281 | } | 223 | } |
282 | // I want the physics engine to make an avatar capsule | ||
283 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
284 | { | ||
285 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
286 | } | ||
287 | 224 | ||
288 | public override bool Grabbed { | 225 | public override bool Grabbed { |
289 | set { _grabbed = value; } | 226 | set { _grabbed = value; } |
@@ -291,6 +228,10 @@ public sealed class BSCharacter : BSPhysObject | |||
291 | public override bool Selected { | 228 | public override bool Selected { |
292 | set { _selected = value; } | 229 | set { _selected = value; } |
293 | } | 230 | } |
231 | public override bool IsSelected | ||
232 | { | ||
233 | get { return _selected; } | ||
234 | } | ||
294 | public override void CrossingFailure() { return; } | 235 | public override void CrossingFailure() { return; } |
295 | public override void link(PhysicsActor obj) { return; } | 236 | public override void link(PhysicsActor obj) { return; } |
296 | public override void delink() { return; } | 237 | public override void delink() { return; } |
@@ -301,29 +242,29 @@ public sealed class BSCharacter : BSPhysObject | |||
301 | // Called at taint time! | 242 | // Called at taint time! |
302 | public override void ZeroMotion(bool inTaintTime) | 243 | public override void ZeroMotion(bool inTaintTime) |
303 | { | 244 | { |
304 | _velocity = OMV.Vector3.Zero; | 245 | RawVelocity = OMV.Vector3.Zero; |
305 | _acceleration = OMV.Vector3.Zero; | 246 | _acceleration = OMV.Vector3.Zero; |
306 | _rotationalVelocity = OMV.Vector3.Zero; | 247 | _rotationalVelocity = OMV.Vector3.Zero; |
307 | 248 | ||
308 | // Zero some other properties directly into the physics engine | 249 | // Zero some other properties directly into the physics engine |
309 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 250 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
310 | { | 251 | { |
311 | if (PhysBody.HasPhysicalBody) | 252 | if (PhysBody.HasPhysicalBody) |
312 | PhysicsScene.PE.ClearAllForces(PhysBody); | 253 | PhysScene.PE.ClearAllForces(PhysBody); |
313 | }); | 254 | }); |
314 | } | 255 | } |
315 | public override void ZeroAngularMotion(bool inTaintTime) | 256 | public override void ZeroAngularMotion(bool inTaintTime) |
316 | { | 257 | { |
317 | _rotationalVelocity = OMV.Vector3.Zero; | 258 | _rotationalVelocity = OMV.Vector3.Zero; |
318 | 259 | ||
319 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 260 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
320 | { | 261 | { |
321 | if (PhysBody.HasPhysicalBody) | 262 | if (PhysBody.HasPhysicalBody) |
322 | { | 263 | { |
323 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | 264 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
324 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | 265 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
325 | // 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. |
326 | PhysicsScene.PE.ClearForces(PhysBody); | 267 | PhysScene.PE.ClearForces(PhysBody); |
327 | } | 268 | } |
328 | }); | 269 | }); |
329 | } | 270 | } |
@@ -344,25 +285,26 @@ public sealed class BSCharacter : BSPhysObject | |||
344 | } | 285 | } |
345 | set { | 286 | set { |
346 | _position = value; | 287 | _position = value; |
347 | PositionSanityCheck(); | ||
348 | 288 | ||
349 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 289 | PhysScene.TaintedObject("BSCharacter.setPosition", delegate() |
350 | { | 290 | { |
351 | 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); |
352 | if (PhysBody.HasPhysicalBody) | 292 | PositionSanityCheck(); |
353 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 293 | ForcePosition = _position; |
354 | }); | 294 | }); |
355 | } | 295 | } |
356 | } | 296 | } |
357 | public override OMV.Vector3 ForcePosition { | 297 | public override OMV.Vector3 ForcePosition { |
358 | get { | 298 | get { |
359 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 299 | _position = PhysScene.PE.GetPosition(PhysBody); |
360 | return _position; | 300 | return _position; |
361 | } | 301 | } |
362 | set { | 302 | set { |
363 | _position = value; | 303 | _position = value; |
364 | PositionSanityCheck(); | 304 | if (PhysBody.HasPhysicalBody) |
365 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 305 | { |
306 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
307 | } | ||
366 | } | 308 | } |
367 | } | 309 | } |
368 | 310 | ||
@@ -375,25 +317,27 @@ public sealed class BSCharacter : BSPhysObject | |||
375 | bool ret = false; | 317 | bool ret = false; |
376 | 318 | ||
377 | // TODO: check for out of bounds | 319 | // TODO: check for out of bounds |
378 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | 320 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
379 | { | 321 | { |
380 | // The character is out of the known/simulated area. | 322 | // The character is out of the known/simulated area. |
381 | // Upper levels of code will handle the transition to other areas so, for | 323 | // Force the avatar position to be within known. ScenePresence will use the position |
382 | // the time, we just ignore the position. | 324 | // plus the velocity to decide if the avatar is moving out of the region. |
383 | return ret; | 325 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); |
326 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | ||
327 | return true; | ||
384 | } | 328 | } |
385 | 329 | ||
386 | // If below the ground, move the avatar up | 330 | // If below the ground, move the avatar up |
387 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 331 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
388 | if (Position.Z < terrainHeight) | 332 | if (Position.Z < terrainHeight) |
389 | { | 333 | { |
390 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 334 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
391 | _position.Z = terrainHeight + 2.0f; | 335 | _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; |
392 | ret = true; | 336 | ret = true; |
393 | } | 337 | } |
394 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 338 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
395 | { | 339 | { |
396 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 340 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
397 | if (Position.Z < waterHeight) | 341 | if (Position.Z < waterHeight) |
398 | { | 342 | { |
399 | _position.Z = waterHeight; | 343 | _position.Z = waterHeight; |
@@ -414,11 +358,10 @@ public sealed class BSCharacter : BSPhysObject | |||
414 | { | 358 | { |
415 | // 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 |
416 | // just assign to "Position" because of potential call loops. | 360 | // just assign to "Position" because of potential call loops. |
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 361 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
418 | { | 362 | { |
419 | 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); |
420 | if (PhysBody.HasPhysicalBody) | 364 | ForcePosition = _position; |
421 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
422 | }); | 365 | }); |
423 | ret = true; | 366 | ret = true; |
424 | } | 367 | } |
@@ -428,25 +371,25 @@ public sealed class BSCharacter : BSPhysObject | |||
428 | public override float Mass { get { return _mass; } } | 371 | public override float Mass { get { return _mass; } } |
429 | 372 | ||
430 | // 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 |
431 | public override float RawMass { | 374 | public override float RawMass { |
432 | get {return _mass; } | 375 | get {return _mass; } |
433 | } | 376 | } |
434 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 377 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
435 | { | 378 | { |
436 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 379 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
437 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | 380 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
438 | } | 381 | } |
439 | 382 | ||
440 | public override OMV.Vector3 Force { | 383 | public override OMV.Vector3 Force { |
441 | get { return _force; } | 384 | get { return RawForce; } |
442 | set { | 385 | set { |
443 | _force = value; | 386 | RawForce = value; |
444 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 387 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
445 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 388 | PhysScene.TaintedObject("BSCharacter.SetForce", delegate() |
446 | { | 389 | { |
447 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 390 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
448 | if (PhysBody.HasPhysicalBody) | 391 | if (PhysBody.HasPhysicalBody) |
449 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 392 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); |
450 | }); | 393 | }); |
451 | } | 394 | } |
452 | } | 395 | } |
@@ -469,77 +412,49 @@ public sealed class BSCharacter : BSPhysObject | |||
469 | { | 412 | { |
470 | get | 413 | get |
471 | { | 414 | { |
472 | return _velocityMotor.TargetValue; | 415 | return base.m_targetVelocity; |
473 | } | 416 | } |
474 | set | 417 | set |
475 | { | 418 | { |
476 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | 419 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); |
420 | m_targetVelocity = value; | ||
477 | OMV.Vector3 targetVel = value; | 421 | OMV.Vector3 targetVel = value; |
478 | if (_setAlwaysRun) | 422 | if (_setAlwaysRun) |
479 | targetVel *= BSParam.AvatarAlwaysRunFactor; | 423 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); |
480 | 424 | ||
481 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 425 | if (m_moveActor != null) |
482 | { | 426 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
483 | _velocityMotor.Reset(); | ||
484 | _velocityMotor.SetTarget(targetVel); | ||
485 | _velocityMotor.SetCurrent(_velocity); | ||
486 | _velocityMotor.Enabled = true; | ||
487 | }); | ||
488 | } | 427 | } |
489 | } | 428 | } |
490 | // 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. |
491 | public override OMV.Vector3 Velocity { | 430 | public override OMV.Vector3 Velocity { |
492 | get { return _velocity; } | 431 | get { return RawVelocity; } |
493 | set { | 432 | set { |
494 | _velocity = value; | 433 | RawVelocity = value; |
495 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 434 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity); |
496 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 435 | PhysScene.TaintedObject("BSCharacter.setVelocity", delegate() |
497 | { | 436 | { |
498 | _velocityMotor.Reset(); | 437 | if (m_moveActor != null) |
499 | _velocityMotor.SetCurrent(_velocity); | 438 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */); |
500 | _velocityMotor.SetTarget(_velocity); | 439 | |
501 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | 440 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity); |
502 | _velocityMotor.Enabled = false; | 441 | ForceVelocity = RawVelocity; |
503 | |||
504 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||
505 | ForceVelocity = _velocity; | ||
506 | }); | 442 | }); |
507 | } | 443 | } |
508 | } | 444 | } |
509 | public override OMV.Vector3 ForceVelocity { | 445 | public override OMV.Vector3 ForceVelocity { |
510 | get { return _velocity; } | 446 | get { return RawVelocity; } |
511 | set { | 447 | set { |
512 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 448 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
513 | 449 | ||
514 | _velocity = value; | 450 | RawVelocity = value; |
515 | // Depending on whether the avatar is moving or not, change the friction | 451 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
516 | // to keep the avatar from slipping around | 452 | PhysScene.PE.Activate(PhysBody, true); |
517 | if (_velocity.Length() == 0) | ||
518 | { | ||
519 | if (_currentFriction != BSParam.AvatarStandingFriction) | ||
520 | { | ||
521 | _currentFriction = BSParam.AvatarStandingFriction; | ||
522 | if (PhysBody.HasPhysicalBody) | ||
523 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
524 | } | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | if (_currentFriction != BSParam.AvatarFriction) | ||
529 | { | ||
530 | _currentFriction = BSParam.AvatarFriction; | ||
531 | if (PhysBody.HasPhysicalBody) | ||
532 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | ||
537 | PhysicsScene.PE.Activate(PhysBody, true); | ||
538 | } | 453 | } |
539 | } | 454 | } |
540 | public override OMV.Vector3 Torque { | 455 | public override OMV.Vector3 Torque { |
541 | get { return _torque; } | 456 | get { return RawTorque; } |
542 | set { _torque = value; | 457 | set { RawTorque = value; |
543 | } | 458 | } |
544 | } | 459 | } |
545 | public override float CollisionScore { | 460 | public override float CollisionScore { |
@@ -564,7 +479,7 @@ public sealed class BSCharacter : BSPhysObject | |||
564 | if (_orientation != value) | 479 | if (_orientation != value) |
565 | { | 480 | { |
566 | _orientation = value; | 481 | _orientation = value; |
567 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 482 | PhysScene.TaintedObject("BSCharacter.setOrientation", delegate() |
568 | { | 483 | { |
569 | ForceOrientation = _orientation; | 484 | ForceOrientation = _orientation; |
570 | }); | 485 | }); |
@@ -576,7 +491,7 @@ public sealed class BSCharacter : BSPhysObject | |||
576 | { | 491 | { |
577 | get | 492 | get |
578 | { | 493 | { |
579 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 494 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
580 | return _orientation; | 495 | return _orientation; |
581 | } | 496 | } |
582 | set | 497 | set |
@@ -585,7 +500,7 @@ public sealed class BSCharacter : BSPhysObject | |||
585 | if (PhysBody.HasPhysicalBody) | 500 | if (PhysBody.HasPhysicalBody) |
586 | { | 501 | { |
587 | // _position = PhysicsScene.PE.GetPosition(BSBody); | 502 | // _position = PhysicsScene.PE.GetPosition(BSBody); |
588 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 503 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
589 | } | 504 | } |
590 | } | 505 | } |
591 | } | 506 | } |
@@ -605,6 +520,9 @@ public sealed class BSCharacter : BSPhysObject | |||
605 | public override bool IsStatic { | 520 | public override bool IsStatic { |
606 | get { return false; } | 521 | get { return false; } |
607 | } | 522 | } |
523 | public override bool IsPhysicallyActive { | ||
524 | get { return true; } | ||
525 | } | ||
608 | public override bool Flying { | 526 | public override bool Flying { |
609 | get { return _flying; } | 527 | get { return _flying; } |
610 | set { | 528 | set { |
@@ -631,14 +549,14 @@ public sealed class BSCharacter : BSPhysObject | |||
631 | public override bool FloatOnWater { | 549 | public override bool FloatOnWater { |
632 | set { | 550 | set { |
633 | _floatOnWater = value; | 551 | _floatOnWater = value; |
634 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 552 | PhysScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
635 | { | 553 | { |
636 | if (PhysBody.HasPhysicalBody) | 554 | if (PhysBody.HasPhysicalBody) |
637 | { | 555 | { |
638 | if (_floatOnWater) | 556 | if (_floatOnWater) |
639 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 557 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
640 | else | 558 | else |
641 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 559 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
642 | } | 560 | } |
643 | }); | 561 | }); |
644 | } | 562 | } |
@@ -659,7 +577,7 @@ public sealed class BSCharacter : BSPhysObject | |||
659 | public override float Buoyancy { | 577 | public override float Buoyancy { |
660 | get { return _buoyancy; } | 578 | get { return _buoyancy; } |
661 | set { _buoyancy = value; | 579 | set { _buoyancy = value; |
662 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 580 | PhysScene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
663 | { | 581 | { |
664 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 582 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
665 | ForceBuoyancy = _buoyancy; | 583 | ForceBuoyancy = _buoyancy; |
@@ -668,15 +586,16 @@ public sealed class BSCharacter : BSPhysObject | |||
668 | } | 586 | } |
669 | public override float ForceBuoyancy { | 587 | public override float ForceBuoyancy { |
670 | get { return _buoyancy; } | 588 | get { return _buoyancy; } |
671 | set { | 589 | set { |
672 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | 590 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); |
673 | 591 | ||
674 | _buoyancy = value; | 592 | _buoyancy = value; |
675 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 593 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
676 | // Buoyancy is faked by changing the gravity applied to the object | 594 | // Buoyancy is faked by changing the gravity applied to the object |
677 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 595 | float grav = BSParam.Gravity * (1f - _buoyancy); |
596 | Gravity = new OMV.Vector3(0f, 0f, grav); | ||
678 | if (PhysBody.HasPhysicalBody) | 597 | if (PhysBody.HasPhysicalBody) |
679 | PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); | 598 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
680 | } | 599 | } |
681 | } | 600 | } |
682 | 601 | ||
@@ -691,53 +610,25 @@ public sealed class BSCharacter : BSPhysObject | |||
691 | set { _PIDTau = value; } | 610 | set { _PIDTau = value; } |
692 | } | 611 | } |
693 | 612 | ||
694 | // Used for llSetHoverHeight and maybe vehicle height | ||
695 | // Hover Height will override MoveTo target's Z | ||
696 | public override bool PIDHoverActive { | ||
697 | set { _useHoverPID = value; } | ||
698 | } | ||
699 | public override float PIDHoverHeight { | ||
700 | set { _PIDHoverHeight = value; } | ||
701 | } | ||
702 | public override PIDHoverType PIDHoverType { | ||
703 | set { _PIDHoverType = value; } | ||
704 | } | ||
705 | public override float PIDHoverTau { | ||
706 | set { _PIDHoverTao = value; } | ||
707 | } | ||
708 | |||
709 | // For RotLookAt | ||
710 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
711 | public override bool APIDActive { set { return; } } | ||
712 | public override float APIDStrength { set { return; } } | ||
713 | public override float APIDDamping { set { return; } } | ||
714 | |||
715 | public override void AddForce(OMV.Vector3 force, bool pushforce) | 613 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
716 | { | 614 | { |
717 | // Since this force is being applied in only one step, make this a force per second. | 615 | // Since this force is being applied in only one step, make this a force per second. |
718 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 616 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; |
719 | AddForce(addForce, pushforce, false); | 617 | AddForce(addForce, pushforce, false); |
720 | } | 618 | } |
721 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 619 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
722 | if (force.IsFinite()) | 620 | if (force.IsFinite()) |
723 | { | 621 | { |
724 | float magnitude = force.Length(); | 622 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
725 | if (magnitude > BSParam.MaxAddForceMagnitude) | ||
726 | { | ||
727 | // Force has a limit | ||
728 | force = force / magnitude * BSParam.MaxAddForceMagnitude; | ||
729 | } | ||
730 | |||
731 | OMV.Vector3 addForce = force; | ||
732 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | 623 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
733 | 624 | ||
734 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | 625 | PhysScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() |
735 | { | 626 | { |
736 | // Bullet adds this central force to the total force for this tick | 627 | // Bullet adds this central force to the total force for this tick |
737 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | 628 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
738 | if (PhysBody.HasPhysicalBody) | 629 | if (PhysBody.HasPhysicalBody) |
739 | { | 630 | { |
740 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 631 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
741 | } | 632 | } |
742 | }); | 633 | }); |
743 | } | 634 | } |
@@ -748,7 +639,7 @@ public sealed class BSCharacter : BSPhysObject | |||
748 | } | 639 | } |
749 | } | 640 | } |
750 | 641 | ||
751 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 642 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
752 | } | 643 | } |
753 | public override void SetMomentum(OMV.Vector3 momentum) { | 644 | public override void SetMomentum(OMV.Vector3 momentum) { |
754 | } | 645 | } |
@@ -756,7 +647,7 @@ public sealed class BSCharacter : BSPhysObject | |||
756 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | 647 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
757 | { | 648 | { |
758 | OMV.Vector3 newScale; | 649 | OMV.Vector3 newScale; |
759 | 650 | ||
760 | // Bullet's capsule total height is the "passed height + radius * 2"; | 651 | // Bullet's capsule total height is the "passed height + radius * 2"; |
761 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) | 652 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) |
762 | // The number we pass in for 'scaling' is the multiplier to get that base | 653 | // The number we pass in for 'scaling' is the multiplier to get that base |
@@ -794,34 +685,48 @@ public sealed class BSCharacter : BSPhysObject | |||
794 | * Math.Min(Size.X, Size.Y) / 2 | 685 | * Math.Min(Size.X, Size.Y) / 2 |
795 | * Size.Y / 2f // plus the volume of the capsule end caps | 686 | * Size.Y / 2f // plus the volume of the capsule end caps |
796 | ); | 687 | ); |
797 | _mass = _avatarDensity * _avatarVolume; | 688 | _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; |
798 | } | 689 | } |
799 | 690 | ||
800 | // The physics engine says that properties have updated. Update same and inform | 691 | // The physics engine says that properties have updated. Update same and inform |
801 | // the world that things have changed. | 692 | // the world that things have changed. |
802 | public override void UpdateProperties(EntityProperties entprop) | 693 | public override void UpdateProperties(EntityProperties entprop) |
803 | { | 694 | { |
804 | _position = entprop.Position; | 695 | // Don't change position if standing on a stationary object. |
696 | if (!IsStationary) | ||
697 | _position = entprop.Position; | ||
698 | |||
805 | _orientation = entprop.Rotation; | 699 | _orientation = entprop.Rotation; |
806 | _velocity = entprop.Velocity; | 700 | |
701 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | ||
702 | // and will send agent updates to the clients if velocity changes by more than | ||
703 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | ||
704 | // extra updates. | ||
705 | if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) | ||
706 | RawVelocity = entprop.Velocity; | ||
707 | |||
807 | _acceleration = entprop.Acceleration; | 708 | _acceleration = entprop.Acceleration; |
808 | _rotationalVelocity = entprop.RotationalVelocity; | 709 | _rotationalVelocity = entprop.RotationalVelocity; |
809 | 710 | ||
810 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 711 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
811 | PositionSanityCheck(true); | 712 | if (PositionSanityCheck(true)) |
713 | { | ||
714 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); | ||
715 | entprop.Position = _position; | ||
716 | } | ||
812 | 717 | ||
813 | // remember the current and last set values | 718 | // remember the current and last set values |
814 | LastEntityProperties = CurrentEntityProperties; | 719 | LastEntityProperties = CurrentEntityProperties; |
815 | CurrentEntityProperties = entprop; | 720 | CurrentEntityProperties = entprop; |
816 | 721 | ||
817 | // Tell the linkset about value changes | 722 | // Tell the linkset about value changes |
818 | Linkset.UpdateProperties(this, true); | 723 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
819 | 724 | ||
820 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 725 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
821 | // base.RequestPhysicsterseUpdate(); | 726 | // base.RequestPhysicsterseUpdate(); |
822 | 727 | ||
823 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 728 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
824 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 729 | LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity); |
825 | } | 730 | } |
826 | } | 731 | } |
827 | } | 732 | } |
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 ecb1b32..d0949f5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -57,6 +57,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
57 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); | 57 | obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); |
58 | } | 58 | } |
59 | 59 | ||
60 | // 6 Dof constraint based on a midpoint between the two constrained bodies | ||
60 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, | 61 | public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, |
61 | Vector3 joinPoint, | 62 | Vector3 joinPoint, |
62 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) | 63 | bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) |
@@ -94,6 +95,21 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
94 | } | 95 | } |
95 | } | 96 | } |
96 | 97 | ||
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, | ||
100 | bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) | ||
101 | : base(world) | ||
102 | { | ||
103 | m_body1 = obj1; | ||
104 | m_body2 = obj1; // Look out for confusion down the road | ||
105 | m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, | ||
106 | frameInBloc, frameInBrot, | ||
107 | useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); | ||
108 | m_enabled = true; | ||
109 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", | ||
110 | BSScene.DetailLogZero, world.worldID, obj1.ID, obj1.AddrString); | ||
111 | } | ||
112 | |||
97 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) | 113 | public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) |
98 | { | 114 | { |
99 | bool ret = false; | 115 | bool ret = false; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs index 2aeff25..5c8d94e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | |||
@@ -117,8 +117,7 @@ public sealed class BSConstraintCollection : IDisposable | |||
117 | if (this.TryGetConstraint(body1, body2, out constrain)) | 117 | if (this.TryGetConstraint(body1, body2, out constrain)) |
118 | { | 118 | { |
119 | // remove the constraint from our collection | 119 | // remove the constraint from our collection |
120 | RemoveAndDestroyConstraint(constrain); | 120 | ret = RemoveAndDestroyConstraint(constrain); |
121 | ret = true; | ||
122 | } | 121 | } |
123 | } | 122 | } |
124 | 123 | ||
@@ -126,17 +125,19 @@ public sealed class BSConstraintCollection : IDisposable | |||
126 | } | 125 | } |
127 | 126 | ||
128 | // The constraint MUST exist in the collection | 127 | // The constraint MUST exist in the collection |
128 | // Could be called if the constraint was previously removed. | ||
129 | // Return 'true' if the constraint was actually removed and disposed. | ||
129 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) | 130 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) |
130 | { | 131 | { |
132 | bool removed = false; | ||
131 | lock (m_constraints) | 133 | lock (m_constraints) |
132 | { | 134 | { |
133 | // remove the constraint from our collection | 135 | // remove the constraint from our collection |
134 | m_constraints.Remove(constrain); | 136 | removed = m_constraints.Remove(constrain); |
135 | } | 137 | } |
136 | // tell the engine that all its structures need to be freed | 138 | // Dispose() is safe to call multiple times |
137 | constrain.Dispose(); | 139 | constrain.Dispose(); |
138 | // we destroyed something | 140 | return removed; |
139 | return true; | ||
140 | } | 141 | } |
141 | 142 | ||
142 | // Remove all constraints that reference the passed body. | 143 | // Remove all constraints that reference the passed body. |
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 13c2539..c16b7d3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -35,17 +35,19 @@ using System.Collections.Generic; | |||
35 | using System.Reflection; | 35 | using System.Reflection; |
36 | using System.Runtime.InteropServices; | 36 | using System.Runtime.InteropServices; |
37 | using OpenMetaverse; | 37 | using OpenMetaverse; |
38 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Physics.Manager; | 39 | using OpenSim.Region.Physics.Manager; |
39 | 40 | ||
40 | namespace OpenSim.Region.Physics.BulletSPlugin | 41 | namespace OpenSim.Region.Physics.BulletSPlugin |
41 | { | 42 | { |
42 | public sealed class BSDynamics | 43 | public sealed class BSDynamics : BSActor |
43 | { | 44 | { |
44 | private static string LogHeader = "[BULLETSIM VEHICLE]"; | 45 | private static string LogHeader = "[BULLETSIM VEHICLE]"; |
45 | 46 | ||
46 | private BSScene PhysicsScene { get; set; } | ||
47 | // the prim this dynamic controller belongs to | 47 | // the prim this dynamic controller belongs to |
48 | private BSPrim Prim { get; set; } | 48 | private BSPrim ControllingPrim { get; set; } |
49 | |||
50 | private bool m_haveRegisteredForSceneEvents; | ||
49 | 51 | ||
50 | // mass of the vehicle fetched each time we're calles | 52 | // mass of the vehicle fetched each time we're calles |
51 | private float m_vehicleMass; | 53 | private float m_vehicleMass; |
@@ -108,10 +110,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
108 | private float m_VhoverEfficiency = 0f; | 110 | private float m_VhoverEfficiency = 0f; |
109 | private float m_VhoverTimescale = 0f; | 111 | private float m_VhoverTimescale = 0f; |
110 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | 112 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height |
111 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. | 113 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) |
112 | // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) | 114 | private float m_VehicleBuoyancy = 0f; |
113 | // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. | 115 | private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set |
114 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | ||
115 | 116 | ||
116 | //Attractor properties | 117 | //Attractor properties |
117 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); | 118 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
@@ -124,22 +125,51 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | static readonly float PIOverFour = ((float)Math.PI) / 4f; | 125 | static readonly float PIOverFour = ((float)Math.PI) / 4f; |
125 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; | 126 | static readonly float PIOverTwo = ((float)Math.PI) / 2f; |
126 | 127 | ||
127 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 128 | // For debugging, flags to turn on and off individual corrections. |
129 | public bool enableAngularVerticalAttraction; | ||
130 | public bool enableAngularDeflection; | ||
131 | public bool enableAngularBanking; | ||
132 | |||
133 | public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName) | ||
134 | : base(myScene, myPrim, actorName) | ||
128 | { | 135 | { |
129 | PhysicsScene = myScene; | 136 | ControllingPrim = myPrim; |
130 | Prim = myPrim; | ||
131 | Type = Vehicle.TYPE_NONE; | 137 | Type = Vehicle.TYPE_NONE; |
138 | m_haveRegisteredForSceneEvents = false; | ||
139 | SetupVehicleDebugging(); | ||
140 | } | ||
141 | |||
142 | // Stopgap debugging enablement. Allows source level debugging but still checking | ||
143 | // in changes by making enablement of debugging flags from INI file. | ||
144 | public void SetupVehicleDebugging() | ||
145 | { | ||
146 | enableAngularVerticalAttraction = true; | ||
147 | enableAngularDeflection = false; | ||
148 | enableAngularBanking = true; | ||
149 | if (BSParam.VehicleDebuggingEnable) | ||
150 | { | ||
151 | enableAngularVerticalAttraction = true; | ||
152 | enableAngularDeflection = false; | ||
153 | enableAngularBanking = false; | ||
154 | } | ||
132 | } | 155 | } |
133 | 156 | ||
134 | // Return 'true' if this vehicle is doing vehicle things | 157 | // Return 'true' if this vehicle is doing vehicle things |
135 | public bool IsActive | 158 | public bool IsActive |
136 | { | 159 | { |
137 | get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } | 160 | get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); } |
161 | } | ||
162 | |||
163 | // Return 'true' if this a vehicle that should be sitting on the ground | ||
164 | public bool IsGroundVehicle | ||
165 | { | ||
166 | get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); } | ||
138 | } | 167 | } |
139 | 168 | ||
140 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 169 | #region Vehicle parameter setting |
170 | public void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | ||
141 | { | 171 | { |
142 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 172 | VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
143 | switch (pParam) | 173 | switch (pParam) |
144 | { | 174 | { |
145 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 175 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
@@ -167,6 +197,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | break; | 197 | break; |
168 | case Vehicle.BUOYANCY: | 198 | case Vehicle.BUOYANCY: |
169 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); | 199 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
200 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); | ||
170 | break; | 201 | break; |
171 | case Vehicle.HOVER_EFFICIENCY: | 202 | case Vehicle.HOVER_EFFICIENCY: |
172 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); | 203 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
@@ -204,15 +235,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
204 | // set all of the components to the same value | 235 | // set all of the components to the same value |
205 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
206 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 237 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
207 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
208 | break; | 238 | break; |
209 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 239 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
210 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 240 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
241 | m_angularMotor.Zero(); | ||
211 | m_angularMotor.SetTarget(m_angularMotorDirection); | 242 | m_angularMotor.SetTarget(m_angularMotorDirection); |
212 | break; | 243 | break; |
213 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 244 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
214 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 245 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
215 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
216 | break; | 246 | break; |
217 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 247 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
218 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 248 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
@@ -228,12 +258,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
228 | 258 | ||
229 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 259 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) |
230 | { | 260 | { |
231 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 261 | VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
232 | switch (pParam) | 262 | switch (pParam) |
233 | { | 263 | { |
234 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 264 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
235 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 265 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
236 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
237 | break; | 266 | break; |
238 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 267 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
239 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 268 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
@@ -241,11 +270,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
241 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); | 270 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
242 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); | 271 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
243 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 272 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
273 | m_angularMotor.Zero(); | ||
244 | m_angularMotor.SetTarget(m_angularMotorDirection); | 274 | m_angularMotor.SetTarget(m_angularMotorDirection); |
245 | break; | 275 | break; |
246 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 276 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
247 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 277 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
248 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
249 | break; | 278 | break; |
250 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 279 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
251 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 280 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -263,7 +292,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
263 | 292 | ||
264 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 293 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
265 | { | 294 | { |
266 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); | 295 | VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue); |
267 | switch (pParam) | 296 | switch (pParam) |
268 | { | 297 | { |
269 | case Vehicle.REFERENCE_FRAME: | 298 | case Vehicle.REFERENCE_FRAME: |
@@ -277,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
277 | 306 | ||
278 | internal void ProcessVehicleFlags(int pParam, bool remove) | 307 | internal void ProcessVehicleFlags(int pParam, bool remove) |
279 | { | 308 | { |
280 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 309 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove); |
281 | VehicleFlag parm = (VehicleFlag)pParam; | 310 | VehicleFlag parm = (VehicleFlag)pParam; |
282 | if (pParam == -1) | 311 | if (pParam == -1) |
283 | m_flags = (VehicleFlag)0; | 312 | m_flags = (VehicleFlag)0; |
@@ -290,9 +319,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
290 | } | 319 | } |
291 | } | 320 | } |
292 | 321 | ||
293 | internal void ProcessTypeChange(Vehicle pType) | 322 | public void ProcessTypeChange(Vehicle pType) |
294 | { | 323 | { |
295 | VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); | 324 | VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType); |
296 | // Set Defaults For Type | 325 | // Set Defaults For Type |
297 | Type = pType; | 326 | Type = pType; |
298 | switch (pType) | 327 | switch (pType) |
@@ -526,81 +555,136 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
526 | break; | 555 | break; |
527 | } | 556 | } |
528 | 557 | ||
529 | // Update any physical parameters based on this type. | 558 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f); |
530 | Refresh(); | 559 | m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
531 | |||
532 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
533 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
534 | 1f); | ||
535 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
536 | 560 | ||
537 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | 561 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f); |
538 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | 562 | m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
539 | 1f); | ||
540 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
541 | 563 | ||
564 | /* Not implemented | ||
542 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, | 565 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, |
543 | BSMotor.Infinite, BSMotor.InfiniteVector, | 566 | BSMotor.Infinite, BSMotor.InfiniteVector, |
544 | m_verticalAttractionEfficiency); | 567 | m_verticalAttractionEfficiency); |
545 | // Z goes away and we keep X and Y | 568 | // Z goes away and we keep X and Y |
546 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
547 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | 569 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
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(); | ||
583 | } | ||
584 | #endregion // Vehicle parameter setting | ||
585 | |||
586 | // BSActor.Refresh() | ||
587 | public override void Refresh() | ||
588 | { | ||
589 | // If asking for a refresh, reset the physical parameters before the next simulation step. | ||
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() | ||
592 | { | ||
593 | SetPhysicalParameters(); | ||
594 | }); | ||
548 | } | 595 | } |
549 | 596 | ||
550 | // Some of the properties of this prim may have changed. | 597 | // Some of the properties of this prim may have changed. |
551 | // Do any updating needed for a vehicle | 598 | // Do any updating needed for a vehicle |
552 | public void Refresh() | 599 | private void SetPhysicalParameters() |
553 | { | 600 | { |
554 | if (IsActive) | 601 | if (IsActive) |
555 | { | 602 | { |
556 | // 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 |
557 | m_vehicleMass = Prim.Linkset.LinksetMass; | 604 | m_vehicleMass = ControllingPrim.TotalMass; |
558 | 605 | ||
559 | // Friction affects are handled by this vehicle code | 606 | // Friction affects are handled by this vehicle code |
560 | float friction = 0f; | 607 | m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); |
561 | PhysicsScene.PE.SetFriction(Prim.PhysBody, friction); | 608 | m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); |
562 | 609 | ||
563 | // Moderate angular movement introduced by Bullet. | 610 | // Moderate angular movement introduced by Bullet. |
564 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | 611 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. |
565 | // Maybe compute linear and angular factor and damping from params. | 612 | // Maybe compute linear and angular factor and damping from params. |
566 | float angularDamping = BSParam.VehicleAngularDamping; | 613 | m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping); |
567 | PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping); | 614 | m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor); |
615 | m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); | ||
568 | 616 | ||
569 | // 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 |
570 | PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 618 | m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); |
619 | |||
620 | ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); | ||
621 | m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); | ||
622 | m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); | ||
623 | |||
624 | // Set the gravity for the vehicle depending on the buoyancy | ||
625 | // TODO: what should be done if prim and vehicle buoyancy differ? | ||
626 | m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); | ||
627 | // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. | ||
628 | m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); | ||
629 | |||
630 | VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", | ||
631 | ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, | ||
632 | BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution, | ||
633 | BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor | ||
634 | ); | ||
635 | } | ||
636 | else | ||
637 | { | ||
638 | if (ControllingPrim.PhysBody.HasPhysicalBody) | ||
639 | m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
640 | } | ||
641 | } | ||
571 | 642 | ||
572 | Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); | 643 | // BSActor.RemoveBodyDependencies |
573 | PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia); | 644 | public override void RemoveDependencies() |
574 | PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); | 645 | { |
646 | Refresh(); | ||
647 | } | ||
575 | 648 | ||
576 | Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); | 649 | // BSActor.Release() |
577 | PhysicsScene.PE.SetGravity(Prim.PhysBody, grav); | 650 | public override void Dispose() |
651 | { | ||
652 | UnregisterForSceneEvents(); | ||
653 | Type = Vehicle.TYPE_NONE; | ||
654 | Enabled = false; | ||
655 | return; | ||
656 | } | ||
578 | 657 | ||
579 | VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", | 658 | private void RegisterForSceneEvents() |
580 | Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); | 659 | { |
581 | } | 660 | if (!m_haveRegisteredForSceneEvents) |
582 | else | ||
583 | { | 661 | { |
584 | PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); | 662 | m_physicsScene.BeforeStep += this.Step; |
663 | m_physicsScene.AfterStep += this.PostStep; | ||
664 | ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty; | ||
665 | m_haveRegisteredForSceneEvents = true; | ||
585 | } | 666 | } |
586 | } | 667 | } |
587 | 668 | ||
588 | public bool RemoveBodyDependencies(BSPhysObject prim) | 669 | private void UnregisterForSceneEvents() |
589 | { | 670 | { |
590 | // If active, we need to add our properties back when the body is rebuilt. | 671 | if (m_haveRegisteredForSceneEvents) |
591 | return IsActive; | 672 | { |
673 | m_physicsScene.BeforeStep -= this.Step; | ||
674 | m_physicsScene.AfterStep -= this.PostStep; | ||
675 | ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty; | ||
676 | m_haveRegisteredForSceneEvents = false; | ||
677 | } | ||
592 | } | 678 | } |
593 | 679 | ||
594 | public void RestoreBodyDependencies(BSPhysObject prim) | 680 | private void PreUpdateProperty(ref EntityProperties entprop) |
595 | { | 681 | { |
596 | if (Prim.LocalID != prim.LocalID) | 682 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
683 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
684 | if (IsActive) | ||
597 | { | 685 | { |
598 | // The call should be on us by our prim. Error if not. | 686 | entprop.RotationalVelocity = Vector3.Zero; |
599 | PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}", | ||
600 | LogHeader, prim.LocalID, Prim.LocalID); | ||
601 | return; | ||
602 | } | 687 | } |
603 | Refresh(); | ||
604 | } | 688 | } |
605 | 689 | ||
606 | #region Known vehicle value functions | 690 | #region Known vehicle value functions |
@@ -617,70 +701,87 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
617 | private Vector3 m_knownPosition; | 701 | private Vector3 m_knownPosition; |
618 | private Vector3 m_knownVelocity; | 702 | private Vector3 m_knownVelocity; |
619 | private Vector3 m_knownForce; | 703 | private Vector3 m_knownForce; |
704 | private Vector3 m_knownForceImpulse; | ||
620 | private Quaternion m_knownOrientation; | 705 | private Quaternion m_knownOrientation; |
621 | private Vector3 m_knownRotationalVelocity; | 706 | private Vector3 m_knownRotationalVelocity; |
622 | private Vector3 m_knownRotationalForce; | 707 | private Vector3 m_knownRotationalForce; |
708 | private Vector3 m_knownRotationalImpulse; | ||
623 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed | 709 | private Vector3 m_knownForwardVelocity; // vehicle relative forward speed |
624 | 710 | ||
625 | private const int m_knownChangedPosition = 1 << 0; | 711 | private const int m_knownChangedPosition = 1 << 0; |
626 | private const int m_knownChangedVelocity = 1 << 1; | 712 | private const int m_knownChangedVelocity = 1 << 1; |
627 | private const int m_knownChangedForce = 1 << 2; | 713 | private const int m_knownChangedForce = 1 << 2; |
628 | private const int m_knownChangedOrientation = 1 << 3; | 714 | private const int m_knownChangedForceImpulse = 1 << 3; |
629 | private const int m_knownChangedRotationalVelocity = 1 << 4; | 715 | private const int m_knownChangedOrientation = 1 << 4; |
630 | private const int m_knownChangedRotationalForce = 1 << 5; | 716 | private const int m_knownChangedRotationalVelocity = 1 << 5; |
631 | private const int m_knownChangedTerrainHeight = 1 << 6; | 717 | private const int m_knownChangedRotationalForce = 1 << 6; |
632 | private const int m_knownChangedWaterLevel = 1 << 7; | 718 | private const int m_knownChangedRotationalImpulse = 1 << 7; |
633 | private const int m_knownChangedForwardVelocity = 1 << 8; | 719 | private const int m_knownChangedTerrainHeight = 1 << 8; |
634 | 720 | private const int m_knownChangedWaterLevel = 1 << 9; | |
635 | private void ForgetKnownVehicleProperties() | 721 | private const int m_knownChangedForwardVelocity = 1 <<10; |
722 | |||
723 | public void ForgetKnownVehicleProperties() | ||
636 | { | 724 | { |
637 | m_knownHas = 0; | 725 | m_knownHas = 0; |
638 | m_knownChanged = 0; | 726 | m_knownChanged = 0; |
639 | } | 727 | } |
640 | // Push all the changed values back into the physics engine | 728 | // Push all the changed values back into the physics engine |
641 | private void PushKnownChanged() | 729 | public void PushKnownChanged() |
642 | { | 730 | { |
643 | if (m_knownChanged != 0) | 731 | if (m_knownChanged != 0) |
644 | { | 732 | { |
645 | if ((m_knownChanged & m_knownChangedPosition) != 0) | 733 | if ((m_knownChanged & m_knownChangedPosition) != 0) |
646 | Prim.ForcePosition = m_knownPosition; | 734 | ControllingPrim.ForcePosition = m_knownPosition; |
647 | 735 | ||
648 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | 736 | if ((m_knownChanged & m_knownChangedOrientation) != 0) |
649 | Prim.ForceOrientation = m_knownOrientation; | 737 | ControllingPrim.ForceOrientation = m_knownOrientation; |
650 | 738 | ||
651 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | 739 | if ((m_knownChanged & m_knownChangedVelocity) != 0) |
652 | { | 740 | { |
653 | Prim.ForceVelocity = m_knownVelocity; | 741 | ControllingPrim.ForceVelocity = m_knownVelocity; |
654 | PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity); | 742 | // Fake out Bullet by making it think the velocity is the same as last time. |
743 | // Bullet does a bunch of smoothing for changing parameters. | ||
744 | // Since the vehicle is demanding this setting, we override Bullet's smoothing | ||
745 | // by telling Bullet the value was the same last time. | ||
746 | // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity); | ||
655 | } | 747 | } |
656 | 748 | ||
657 | if ((m_knownChanged & m_knownChangedForce) != 0) | 749 | if ((m_knownChanged & m_knownChangedForce) != 0) |
658 | Prim.AddForce((Vector3)m_knownForce, false, true); | 750 | ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/); |
751 | |||
752 | if ((m_knownChanged & m_knownChangedForceImpulse) != 0) | ||
753 | ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/); | ||
659 | 754 | ||
660 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | 755 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) |
661 | { | 756 | { |
662 | Prim.ForceRotationalVelocity = m_knownRotationalVelocity; | 757 | ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity; |
663 | // Fake out Bullet by making it think the velocity is the same as last time. | 758 | // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); |
664 | PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity); | ||
665 | } | 759 | } |
666 | 760 | ||
761 | if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0) | ||
762 | ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/); | ||
763 | |||
667 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | 764 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) |
668 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | 765 | { |
766 | ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/); | ||
767 | } | ||
669 | 768 | ||
670 | // If we set one of the values (ie, the physics engine didn't do it) we must force | 769 | // If we set one of the values (ie, the physics engine didn't do it) we must force |
671 | // an UpdateProperties event to send the changes up to the simulator. | 770 | // an UpdateProperties event to send the changes up to the simulator. |
672 | PhysicsScene.PE.PushUpdate(Prim.PhysBody); | 771 | m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody); |
673 | } | 772 | } |
674 | m_knownChanged = 0; | 773 | m_knownChanged = 0; |
675 | } | 774 | } |
676 | 775 | ||
677 | // Since the computation of terrain height can be a little involved, this routine | 776 | // Since the computation of terrain height can be a little involved, this routine |
678 | // is used to fetch the height only once for each vehicle simulation step. | 777 | // is used to fetch the height only once for each vehicle simulation step. |
778 | Vector3 lastRememberedHeightPos; | ||
679 | private float GetTerrainHeight(Vector3 pos) | 779 | private float GetTerrainHeight(Vector3 pos) |
680 | { | 780 | { |
681 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0) | 781 | if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos) |
682 | { | 782 | { |
683 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 783 | lastRememberedHeightPos = pos; |
784 | m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
684 | m_knownHas |= m_knownChangedTerrainHeight; | 785 | m_knownHas |= m_knownChangedTerrainHeight; |
685 | } | 786 | } |
686 | return m_knownTerrainHeight; | 787 | return m_knownTerrainHeight; |
@@ -692,7 +793,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
692 | { | 793 | { |
693 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) | 794 | if ((m_knownHas & m_knownChangedWaterLevel) == 0) |
694 | { | 795 | { |
695 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | 796 | m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos); |
696 | m_knownHas |= m_knownChangedWaterLevel; | 797 | m_knownHas |= m_knownChangedWaterLevel; |
697 | } | 798 | } |
698 | return (float)m_knownWaterLevel; | 799 | return (float)m_knownWaterLevel; |
@@ -704,7 +805,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
704 | { | 805 | { |
705 | if ((m_knownHas & m_knownChangedPosition) == 0) | 806 | if ((m_knownHas & m_knownChangedPosition) == 0) |
706 | { | 807 | { |
707 | m_knownPosition = Prim.ForcePosition; | 808 | m_knownPosition = ControllingPrim.ForcePosition; |
708 | m_knownHas |= m_knownChangedPosition; | 809 | m_knownHas |= m_knownChangedPosition; |
709 | } | 810 | } |
710 | return m_knownPosition; | 811 | return m_knownPosition; |
@@ -723,7 +824,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
723 | { | 824 | { |
724 | if ((m_knownHas & m_knownChangedOrientation) == 0) | 825 | if ((m_knownHas & m_knownChangedOrientation) == 0) |
725 | { | 826 | { |
726 | m_knownOrientation = Prim.ForceOrientation; | 827 | m_knownOrientation = ControllingPrim.ForceOrientation; |
727 | m_knownHas |= m_knownChangedOrientation; | 828 | m_knownHas |= m_knownChangedOrientation; |
728 | } | 829 | } |
729 | return m_knownOrientation; | 830 | return m_knownOrientation; |
@@ -742,10 +843,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
742 | { | 843 | { |
743 | if ((m_knownHas & m_knownChangedVelocity) == 0) | 844 | if ((m_knownHas & m_knownChangedVelocity) == 0) |
744 | { | 845 | { |
745 | m_knownVelocity = Prim.ForceVelocity; | 846 | m_knownVelocity = ControllingPrim.ForceVelocity; |
746 | m_knownHas |= m_knownChangedVelocity; | 847 | m_knownHas |= m_knownChangedVelocity; |
747 | } | 848 | } |
748 | return (Vector3)m_knownVelocity; | 849 | return m_knownVelocity; |
749 | } | 850 | } |
750 | set | 851 | set |
751 | { | 852 | { |
@@ -755,15 +856,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
755 | } | 856 | } |
756 | } | 857 | } |
757 | 858 | ||
758 | private void VehicleAddForce(Vector3 aForce) | 859 | private void VehicleAddForce(Vector3 pForce) |
759 | { | 860 | { |
760 | if ((m_knownHas & m_knownChangedForce) == 0) | 861 | if ((m_knownHas & m_knownChangedForce) == 0) |
761 | { | 862 | { |
762 | m_knownForce = Vector3.Zero; | 863 | m_knownForce = Vector3.Zero; |
864 | m_knownHas |= m_knownChangedForce; | ||
763 | } | 865 | } |
764 | m_knownForce += aForce; | 866 | m_knownForce += pForce; |
765 | m_knownChanged |= m_knownChangedForce; | 867 | m_knownChanged |= m_knownChangedForce; |
766 | m_knownHas |= m_knownChangedForce; | 868 | } |
869 | |||
870 | private void VehicleAddForceImpulse(Vector3 pImpulse) | ||
871 | { | ||
872 | if ((m_knownHas & m_knownChangedForceImpulse) == 0) | ||
873 | { | ||
874 | m_knownForceImpulse = Vector3.Zero; | ||
875 | m_knownHas |= m_knownChangedForceImpulse; | ||
876 | } | ||
877 | m_knownForceImpulse += pImpulse; | ||
878 | m_knownChanged |= m_knownChangedForceImpulse; | ||
767 | } | 879 | } |
768 | 880 | ||
769 | private Vector3 VehicleRotationalVelocity | 881 | private Vector3 VehicleRotationalVelocity |
@@ -772,7 +884,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
772 | { | 884 | { |
773 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) | 885 | if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) |
774 | { | 886 | { |
775 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | 887 | m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity; |
776 | m_knownHas |= m_knownChangedRotationalVelocity; | 888 | m_knownHas |= m_knownChangedRotationalVelocity; |
777 | } | 889 | } |
778 | return (Vector3)m_knownRotationalVelocity; | 890 | return (Vector3)m_knownRotationalVelocity; |
@@ -794,6 +906,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
794 | m_knownChanged |= m_knownChangedRotationalForce; | 906 | m_knownChanged |= m_knownChangedRotationalForce; |
795 | m_knownHas |= m_knownChangedRotationalForce; | 907 | m_knownHas |= m_knownChangedRotationalForce; |
796 | } | 908 | } |
909 | private void VehicleAddRotationalImpulse(Vector3 pImpulse) | ||
910 | { | ||
911 | if ((m_knownHas & m_knownChangedRotationalImpulse) == 0) | ||
912 | { | ||
913 | m_knownRotationalImpulse = Vector3.Zero; | ||
914 | m_knownHas |= m_knownChangedRotationalImpulse; | ||
915 | } | ||
916 | m_knownRotationalImpulse += pImpulse; | ||
917 | m_knownChanged |= m_knownChangedRotationalImpulse; | ||
918 | } | ||
919 | |||
797 | // Vehicle relative forward velocity | 920 | // Vehicle relative forward velocity |
798 | private Vector3 VehicleForwardVelocity | 921 | private Vector3 VehicleForwardVelocity |
799 | { | 922 | { |
@@ -822,9 +945,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
822 | { | 945 | { |
823 | if (!IsActive) return; | 946 | if (!IsActive) return; |
824 | 947 | ||
825 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | ||
826 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | ||
827 | |||
828 | ForgetKnownVehicleProperties(); | 948 | ForgetKnownVehicleProperties(); |
829 | 949 | ||
830 | MoveLinear(pTimestep); | 950 | MoveLinear(pTimestep); |
@@ -839,106 +959,116 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
839 | // for the physics engine to note the changes so an UpdateProperties event will happen. | 959 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
840 | PushKnownChanged(); | 960 | PushKnownChanged(); |
841 | 961 | ||
842 | if (PhysicsScene.VehiclePhysicalLoggingEnabled) | 962 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
843 | PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); | 963 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
844 | 964 | ||
845 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 965 | VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}", |
846 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); | 966 | ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity); |
847 | } | 967 | } |
848 | 968 | ||
849 | // Apply the effect of the linear motor and other linear motions (like hover and float). | 969 | // Called after the simulation step |
850 | private void MoveLinear(float pTimestep) | 970 | internal void PostStep(float pTimestep) |
851 | { | 971 | { |
852 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); | 972 | if (!IsActive) return; |
853 | 973 | ||
854 | // The movement computed in the linear motor is relative to the vehicle | 974 | if (m_physicsScene.VehiclePhysicalLoggingEnabled) |
855 | // coordinates. Rotate the movement to world coordinates. | 975 | m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody); |
856 | linearMotorContribution *= VehicleOrientation; | 976 | } |
857 | 977 | ||
858 | // ================================================================== | 978 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
859 | // Buoyancy: force to overcome gravity. | 979 | private void MoveLinear(float pTimestep) |
860 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 980 | { |
861 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. | 981 | ComputeLinearVelocity(pTimestep); |
862 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
863 | 982 | ||
864 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); | 983 | ComputeLinearTerrainHeightCorrection(pTimestep); |
865 | 984 | ||
866 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); | 985 | ComputeLinearHover(pTimestep); |
867 | 986 | ||
868 | ComputeLinearBlockingEndPoint(pTimestep); | 987 | ComputeLinearBlockingEndPoint(pTimestep); |
869 | 988 | ||
870 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); | 989 | ComputeLinearMotorUp(pTimestep); |
871 | 990 | ||
872 | // ================================================================== | 991 | ApplyGravity(pTimestep); |
873 | Vector3 newVelocity = linearMotorContribution | ||
874 | + terrainHeightContribution | ||
875 | + hoverContribution | ||
876 | + limitMotorUpContribution; | ||
877 | |||
878 | Vector3 newForce = buoyancyContribution; | ||
879 | 992 | ||
880 | // If not changing some axis, reduce out velocity | 993 | // If not changing some axis, reduce out velocity |
881 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | 994 | if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0) |
882 | newVelocity.X = 0; | 995 | { |
883 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | 996 | Vector3 vel = VehicleVelocity; |
884 | newVelocity.Y = 0; | 997 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
885 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | 998 | vel.X = 0; |
886 | newVelocity.Z = 0; | 999 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) |
1000 | vel.Y = 0; | ||
1001 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
1002 | vel.Z = 0; | ||
1003 | VehicleVelocity = vel; | ||
1004 | } | ||
887 | 1005 | ||
888 | // ================================================================== | 1006 | // ================================================================== |
889 | // Clamp high or low velocities | 1007 | // Clamp high or low velocities |
890 | float newVelocityLengthSq = newVelocity.LengthSquared(); | 1008 | float newVelocityLengthSq = VehicleVelocity.LengthSquared(); |
891 | if (newVelocityLengthSq > 1000f) | 1009 | if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared) |
892 | { | 1010 | { |
893 | newVelocity /= newVelocity.Length(); | 1011 | Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG |
894 | newVelocity *= 1000f; | 1012 | VehicleVelocity /= VehicleVelocity.Length(); |
1013 | VehicleVelocity *= BSParam.VehicleMaxLinearVelocity; | ||
1014 | VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}", | ||
1015 | ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity); | ||
895 | } | 1016 | } |
896 | else if (newVelocityLengthSq < 0.001f) | 1017 | else if (newVelocityLengthSq < 0.001f) |
897 | newVelocity = Vector3.Zero; | 1018 | VehicleVelocity = Vector3.Zero; |
898 | 1019 | ||
899 | // ================================================================== | 1020 | VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity ); |
900 | // Stuff new linear velocity into the vehicle. | 1021 | |
901 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | 1022 | } // end MoveLinear() |
902 | VehicleVelocity = newVelocity; | 1023 | |
1024 | public void ComputeLinearVelocity(float pTimestep) | ||
1025 | { | ||
1026 | // Step the motor from the current value. Get the correction needed this step. | ||
1027 | Vector3 origVelW = VehicleVelocity; // DEBUG | ||
1028 | Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation); | ||
1029 | Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV); | ||
1030 | |||
1031 | // Friction reduces vehicle motion | ||
1032 | Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep); | ||
1033 | linearMotorCorrectionV -= (currentVelV * frictionFactorW); | ||
903 | 1034 | ||
904 | // Other linear forces are applied as forces. | 1035 | // Motor is vehicle coordinates. Rotate it to world coordinates |
905 | Vector3 totalDownForce = newForce * m_vehicleMass; | 1036 | Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation; |
906 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) | 1037 | |
1038 | // If we're a ground vehicle, don't add any upward Z movement | ||
1039 | if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) | ||
907 | { | 1040 | { |
908 | VehicleAddForce(totalDownForce); | 1041 | if (linearMotorVelocityW.Z > 0f) |
1042 | linearMotorVelocityW.Z = 0f; | ||
909 | } | 1043 | } |
910 | 1044 | ||
911 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", | 1045 | // Add this correction to the velocity to make it faster/slower. |
912 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); | 1046 | VehicleVelocity += linearMotorVelocityW; |
913 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", | ||
914 | Prim.LocalID, | ||
915 | linearMotorContribution, terrainHeightContribution, hoverContribution, | ||
916 | limitMotorUpContribution, buoyancyContribution | ||
917 | ); | ||
918 | 1047 | ||
919 | } // end MoveLinear() | ||
920 | 1048 | ||
921 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | 1049 | |
1050 | VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}", | ||
1051 | ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV, | ||
1052 | linearMotorVelocityW, VehicleVelocity, frictionFactorW); | ||
1053 | } | ||
1054 | |||
1055 | public void ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
922 | { | 1056 | { |
923 | Vector3 ret = Vector3.Zero; | ||
924 | // If below the terrain, move us above the ground a little. | 1057 | // If below the terrain, move us above the ground a little. |
925 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. | 1058 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
926 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) | 1059 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
927 | { | 1060 | { |
928 | // TODO: correct position by applying force rather than forcing position. | 1061 | // Force position because applying force won't get the vehicle through the terrain |
929 | Vector3 newPosition = VehiclePosition; | 1062 | Vector3 newPosition = VehiclePosition; |
930 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; | 1063 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
931 | VehiclePosition = newPosition; | 1064 | VehiclePosition = newPosition; |
932 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | 1065 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", |
933 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | 1066 | ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
934 | } | 1067 | } |
935 | return ret; | ||
936 | } | 1068 | } |
937 | 1069 | ||
938 | public Vector3 ComputeLinearHover(float pTimestep) | 1070 | public void ComputeLinearHover(float pTimestep) |
939 | { | 1071 | { |
940 | Vector3 ret = Vector3.Zero; | ||
941 | |||
942 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 1072 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
943 | // m_VhoverTimescale: time to achieve height | 1073 | // m_VhoverTimescale: time to achieve height |
944 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 1074 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -963,7 +1093,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
963 | if (VehiclePosition.Z > m_VhoverTargetHeight) | 1093 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
964 | m_VhoverTargetHeight = VehiclePosition.Z; | 1094 | m_VhoverTargetHeight = VehiclePosition.Z; |
965 | } | 1095 | } |
966 | 1096 | ||
967 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 1097 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
968 | { | 1098 | { |
969 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) | 1099 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
@@ -971,26 +1101,42 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
971 | Vector3 pos = VehiclePosition; | 1101 | Vector3 pos = VehiclePosition; |
972 | pos.Z = m_VhoverTargetHeight; | 1102 | pos.Z = m_VhoverTargetHeight; |
973 | VehiclePosition = pos; | 1103 | VehiclePosition = pos; |
1104 | |||
1105 | VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos); | ||
974 | } | 1106 | } |
975 | } | 1107 | } |
976 | else | 1108 | else |
977 | { | 1109 | { |
978 | // Error is positive if below the target and negative if above. | 1110 | // Error is positive if below the target and negative if above. |
979 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; | 1111 | Vector3 hpos = VehiclePosition; |
1112 | float verticalError = m_VhoverTargetHeight - hpos.Z; | ||
1113 | float verticalCorrection = verticalError / m_VhoverTimescale; | ||
1114 | verticalCorrection *= m_VhoverEfficiency; | ||
1115 | |||
1116 | hpos.Z += verticalCorrection; | ||
1117 | VehiclePosition = hpos; | ||
1118 | |||
1119 | // Since we are hovering, we need to do the opposite of falling -- get rid of world Z | ||
1120 | Vector3 vel = VehicleVelocity; | ||
1121 | vel.Z = 0f; | ||
1122 | VehicleVelocity = vel; | ||
1123 | |||
1124 | /* | ||
980 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; | 1125 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
1126 | Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity); | ||
1127 | verticalCorrection *= m_vehicleMass; | ||
981 | 1128 | ||
982 | // TODO: implement m_VhoverEfficiency correctly | 1129 | // TODO: implement m_VhoverEfficiency correctly |
983 | if (Math.Abs(verticalError) > m_VhoverEfficiency) | 1130 | VehicleAddForceImpulse(verticalCorrection); |
984 | { | 1131 | */ |
985 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); | 1132 | |
986 | } | 1133 | VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}", |
1134 | ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency, | ||
1135 | m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, | ||
1136 | verticalError, verticalCorrection); | ||
987 | } | 1137 | } |
988 | 1138 | ||
989 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", | ||
990 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); | ||
991 | } | 1139 | } |
992 | |||
993 | return ret; | ||
994 | } | 1140 | } |
995 | 1141 | ||
996 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | 1142 | public bool ComputeLinearBlockingEndPoint(float pTimestep) |
@@ -1030,7 +1176,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1030 | { | 1176 | { |
1031 | VehiclePosition = pos; | 1177 | VehiclePosition = pos; |
1032 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 1178 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
1033 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 1179 | ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos); |
1034 | } | 1180 | } |
1035 | } | 1181 | } |
1036 | return changed; | 1182 | return changed; |
@@ -1041,34 +1187,75 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1041 | // used with conjunction with banking: the strength of the banking will decay when the | 1187 | // used with conjunction with banking: the strength of the banking will decay when the |
1042 | // vehicle no longer experiences collisions. The decay timescale is the same as | 1188 | // vehicle no longer experiences collisions. The decay timescale is the same as |
1043 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | 1189 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering |
1044 | // when they are in mid jump. | 1190 | // when they are in mid jump. |
1045 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | 1191 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? |
1046 | // This is just using the ground and a general collision check. Should really be using | 1192 | // This is just using the ground and a general collision check. Should really be using |
1047 | // a downward raycast to find what is below. | 1193 | // a downward raycast to find what is below. |
1048 | public Vector3 ComputeLinearMotorUp(float pTimestep) | 1194 | public void ComputeLinearMotorUp(float pTimestep) |
1049 | { | 1195 | { |
1050 | Vector3 ret = Vector3.Zero; | ||
1051 | float distanceAboveGround = 0f; | ||
1052 | |||
1053 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 1196 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
1054 | { | 1197 | { |
1198 | // This code tries to decide if the object is not on the ground and then pushing down | ||
1199 | /* | ||
1055 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); | 1200 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
1056 | distanceAboveGround = VehiclePosition.Z - targetHeight; | 1201 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
1057 | // Not colliding if the vehicle is off the ground | 1202 | // Not colliding if the vehicle is off the ground |
1058 | if (!Prim.IsColliding) | 1203 | if (!Prim.IsColliding) |
1059 | { | 1204 | { |
1060 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1205 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
1061 | ret = new Vector3(0, 0, -distanceAboveGround); | 1206 | VehicleVelocity += new Vector3(0, 0, -distanceAboveGround); |
1062 | } | 1207 | } |
1063 | // TODO: this calculation is wrong. From the description at | 1208 | // TODO: this calculation is wrong. From the description at |
1064 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1209 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
1065 | // has a decay factor. This says this force should | 1210 | // has a decay factor. This says this force should |
1066 | // be computed with a motor. | 1211 | // be computed with a motor. |
1067 | // TODO: add interaction with banking. | 1212 | // TODO: add interaction with banking. |
1068 | } | 1213 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", |
1069 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", | ||
1070 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); | 1214 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); |
1071 | return ret; | 1215 | */ |
1216 | |||
1217 | // Another approach is to measure if we're going up. If going up and not colliding, | ||
1218 | // the vehicle is in the air. Fix that by pushing down. | ||
1219 | if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1) | ||
1220 | { | ||
1221 | // Get rid of any of the velocity vector that is pushing us up. | ||
1222 | float upVelocity = VehicleVelocity.Z; | ||
1223 | VehicleVelocity += new Vector3(0, 0, -upVelocity); | ||
1224 | |||
1225 | /* | ||
1226 | // If we're pointed up into the air, we should nose down | ||
1227 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1228 | // The rotation around the Y axis is pitch up or down | ||
1229 | if (pointingDirection.Y > 0.01f) | ||
1230 | { | ||
1231 | float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y); | ||
1232 | Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f); | ||
1233 | // Rotate into world coordinates and apply to vehicle | ||
1234 | angularCorrectionVector *= VehicleOrientation; | ||
1235 | VehicleAddAngularForce(angularCorrectionVector); | ||
1236 | VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}", | ||
1237 | Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector); | ||
1238 | } | ||
1239 | */ | ||
1240 | VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}", | ||
1241 | ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity); | ||
1242 | } | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | private void ApplyGravity(float pTimeStep) | ||
1247 | { | ||
1248 | Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass; | ||
1249 | |||
1250 | // Hack to reduce downward force if the vehicle is probably sitting on the ground | ||
1251 | if (ControllingPrim.IsColliding && IsGroundVehicle) | ||
1252 | appliedGravity *= BSParam.VehicleGroundGravityFudge; | ||
1253 | |||
1254 | VehicleAddForce(appliedGravity); | ||
1255 | |||
1256 | VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}", | ||
1257 | ControllingPrim.LocalID, m_VehicleGravity, | ||
1258 | ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity); | ||
1072 | } | 1259 | } |
1073 | 1260 | ||
1074 | // ======================================================================= | 1261 | // ======================================================================= |
@@ -1079,55 +1266,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1079 | // set directly on the vehicle. | 1266 | // set directly on the vehicle. |
1080 | private void MoveAngular(float pTimestep) | 1267 | private void MoveAngular(float pTimestep) |
1081 | { | 1268 | { |
1082 | // The user wants this many radians per second angular change? | 1269 | ComputeAngularTurning(pTimestep); |
1083 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); | ||
1084 | 1270 | ||
1085 | // ================================================================== | 1271 | ComputeAngularVerticalAttraction(); |
1086 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1087 | // This flag prevents linear deflection parallel to world z-axis. This is useful | ||
1088 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
1089 | // from climbing their linear deflection into the sky. | ||
1090 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1091 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1092 | { | ||
1093 | angularMotorContribution.X = 0f; | ||
1094 | angularMotorContribution.Y = 0f; | ||
1095 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
1096 | } | ||
1097 | |||
1098 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); | ||
1099 | 1272 | ||
1100 | Vector3 deflectionContribution = ComputeAngularDeflection(); | 1273 | ComputeAngularDeflection(); |
1101 | 1274 | ||
1102 | Vector3 bankingContribution = ComputeAngularBanking(); | 1275 | ComputeAngularBanking(); |
1103 | 1276 | ||
1104 | // ================================================================== | 1277 | // ================================================================== |
1105 | m_lastVertAttractor = verticalAttractionContribution; | 1278 | if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f)) |
1106 | |||
1107 | m_lastAngularVelocity = angularMotorContribution | ||
1108 | + verticalAttractionContribution | ||
1109 | + deflectionContribution | ||
1110 | + bankingContribution; | ||
1111 | |||
1112 | // ================================================================== | ||
1113 | // Apply the correction velocity. | ||
1114 | // TODO: Should this be applied as an angular force (torque)? | ||
1115 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
1116 | { | 1279 | { |
1117 | VehicleRotationalVelocity = m_lastAngularVelocity; | 1280 | // The vehicle is not adding anything angular wise. |
1118 | 1281 | VehicleRotationalVelocity = Vector3.Zero; | |
1119 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", | 1282 | VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID); |
1120 | Prim.LocalID, | ||
1121 | angularMotorContribution, verticalAttractionContribution, | ||
1122 | bankingContribution, deflectionContribution, | ||
1123 | m_lastAngularVelocity | ||
1124 | ); | ||
1125 | } | 1283 | } |
1126 | else | 1284 | else |
1127 | { | 1285 | { |
1128 | // The vehicle is not adding anything angular wise. | 1286 | VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity); |
1129 | VehicleRotationalVelocity = Vector3.Zero; | ||
1130 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); | ||
1131 | } | 1287 | } |
1132 | 1288 | ||
1133 | // ================================================================== | 1289 | // ================================================================== |
@@ -1158,10 +1314,42 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1158 | torqueFromOffset.Z = 0; | 1314 | torqueFromOffset.Z = 0; |
1159 | 1315 | ||
1160 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); | 1316 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1161 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1317 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset); |
1162 | } | 1318 | } |
1163 | 1319 | ||
1164 | } | 1320 | } |
1321 | |||
1322 | private void ComputeAngularTurning(float pTimestep) | ||
1323 | { | ||
1324 | // The user wants this many radians per second angular change? | ||
1325 | Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); | ||
1326 | Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); | ||
1327 | |||
1328 | // ================================================================== | ||
1329 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
1330 | // This flag prevents linear deflection parallel to world z-axis. This is useful | ||
1331 | // for preventing ground vehicles with large linear deflection, like bumper cars, | ||
1332 | // from climbing their linear deflection into the sky. | ||
1333 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1334 | // TODO: This is here because this is where ODE put it but documentation says it | ||
1335 | // is a linear effect. Where should this check go? | ||
1336 | //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
1337 | // { | ||
1338 | // angularMotorContributionV.X = 0f; | ||
1339 | // angularMotorContributionV.Y = 0f; | ||
1340 | // } | ||
1341 | |||
1342 | // Reduce any velocity by friction. | ||
1343 | Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); | ||
1344 | angularMotorContributionV -= (currentAngularV * frictionFactorW); | ||
1345 | |||
1346 | VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; | ||
1347 | |||
1348 | |||
1349 | |||
1350 | VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV); | ||
1351 | } | ||
1352 | |||
1165 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | 1353 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
1166 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | 1354 | // Some vehicles, like boats, should always keep their up-side up. This can be done by |
1167 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | 1355 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to |
@@ -1170,15 +1358,84 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1170 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | 1358 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An |
1171 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | 1359 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an |
1172 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | 1360 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. |
1173 | public Vector3 ComputeAngularVerticalAttraction() | 1361 | public void ComputeAngularVerticalAttraction() |
1174 | { | 1362 | { |
1175 | Vector3 ret = Vector3.Zero; | ||
1176 | 1363 | ||
1177 | // If vertical attaction timescale is reasonable | 1364 | // If vertical attaction timescale is reasonable |
1178 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | 1365 | if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1179 | { | 1366 | { |
1367 | //Another formula to try got from : | ||
1368 | //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html | ||
1369 | |||
1370 | Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation; | ||
1371 | |||
1372 | // Flipping what was originally a timescale into a speed variable and then multiplying it by 2 | ||
1373 | // since only computing half the distance between the angles. | ||
1374 | float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; | ||
1375 | |||
1376 | // Make a prediction of where the up axis will be when this is applied rather then where it is now as | ||
1377 | // this makes for a smoother adjustment and less fighting between the various forces. | ||
1378 | Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f); | ||
1379 | |||
1380 | // This is only half the distance to the target so it will take 2 seconds to complete the turn. | ||
1381 | Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); | ||
1382 | |||
1383 | // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared | ||
1384 | Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; | ||
1385 | |||
1386 | VehicleRotationalVelocity += vertContributionV; | ||
1387 | |||
1388 | VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", | ||
1389 | ControllingPrim.LocalID, | ||
1390 | VehicleUpAxis, | ||
1391 | predictedUp, | ||
1392 | torqueVector, | ||
1393 | vertContributionV); | ||
1394 | //===================================================================== | ||
1395 | /* | ||
1396 | // Possible solution derived from a discussion at: | ||
1397 | // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no | ||
1398 | |||
1399 | // Create a rotation that is only the vehicle's rotation around Z | ||
1400 | Vector3 currentEuler = Vector3.Zero; | ||
1401 | VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); | ||
1402 | Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); | ||
1403 | |||
1404 | // Create the axis that is perpendicular to the up vector and the rotated up vector. | ||
1405 | Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); | ||
1406 | // Compute the angle between those to vectors. | ||
1407 | double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); | ||
1408 | // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical | ||
1409 | |||
1410 | // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. | ||
1411 | // TODO: add 'efficiency'. | ||
1412 | differenceAngle /= m_verticalAttractionTimescale; | ||
1413 | |||
1414 | // Create the quaterian representing the correction angle | ||
1415 | Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); | ||
1416 | |||
1417 | // Turn that quaternion into Euler values to make it into velocities to apply. | ||
1418 | Vector3 vertContributionV = Vector3.Zero; | ||
1419 | correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); | ||
1420 | vertContributionV *= -1f; | ||
1421 | |||
1422 | VehicleRotationalVelocity += vertContributionV; | ||
1423 | |||
1424 | VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}", | ||
1425 | ControllingPrim.LocalID, | ||
1426 | differenceAxis, | ||
1427 | differenceAngle, | ||
1428 | correctionRotation, | ||
1429 | vertContributionV); | ||
1430 | */ | ||
1431 | |||
1432 | // =================================================================== | ||
1433 | /* | ||
1434 | Vector3 vertContributionV = Vector3.Zero; | ||
1435 | Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG | ||
1436 | |||
1180 | // Take a vector pointing up and convert it from world to vehicle relative coords. | 1437 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
1181 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; | 1438 | Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation); |
1182 | 1439 | ||
1183 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | 1440 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) |
1184 | // is now: | 1441 | // is now: |
@@ -1190,49 +1447,57 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1190 | 1447 | ||
1191 | // Y error means needed rotation around X axis and visa versa. | 1448 | // Y error means needed rotation around X axis and visa versa. |
1192 | // Since the error goes from zero to one, the asin is the corresponding angle. | 1449 | // Since the error goes from zero to one, the asin is the corresponding angle. |
1193 | ret.X = (float)Math.Asin(verticalError.Y); | 1450 | vertContributionV.X = (float)Math.Asin(verticalError.Y); |
1194 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) | 1451 | // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) |
1195 | ret.Y = -(float)Math.Asin(verticalError.X); | 1452 | vertContributionV.Y = -(float)Math.Asin(verticalError.X); |
1196 | 1453 | ||
1197 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | 1454 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. |
1198 | if (verticalError.Z < 0f) | 1455 | if (verticalError.Z < 0f) |
1199 | { | 1456 | { |
1200 | ret.X += PIOverFour; | 1457 | vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour; |
1201 | ret.Y += PIOverFour; | 1458 | // vertContribution.Y -= PIOverFour; |
1202 | } | 1459 | } |
1203 | 1460 | ||
1204 | // 'ret' is now the necessary velocity to correct tilt in one second. | 1461 | // 'vertContrbution' is now the necessary angular correction to correct tilt in one second. |
1205 | // Correction happens over a number of seconds. | 1462 | // Correction happens over a number of seconds. |
1206 | Vector3 unscaledContrib = ret; | 1463 | Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG |
1207 | ret /= m_verticalAttractionTimescale; | 1464 | |
1465 | // The correction happens over the user's time period | ||
1466 | vertContributionV /= m_verticalAttractionTimescale; | ||
1208 | 1467 | ||
1209 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", | 1468 | // Rotate the vehicle rotation to the world coordinates. |
1210 | Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); | 1469 | VehicleRotationalVelocity += (vertContributionV * VehicleOrientation); |
1470 | |||
1471 | VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}", | ||
1472 | Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV, | ||
1473 | m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV); | ||
1474 | */ | ||
1211 | } | 1475 | } |
1212 | return ret; | ||
1213 | } | 1476 | } |
1214 | 1477 | ||
1215 | // Return the angular correction to correct the direction the vehicle is pointing to be | 1478 | // Angular correction to correct the direction the vehicle is pointing to be |
1216 | // the direction is should want to be pointing. | 1479 | // the direction is should want to be pointing. |
1217 | // The vehicle is moving in some direction and correct its orientation to it is pointing | 1480 | // The vehicle is moving in some direction and correct its orientation to it is pointing |
1218 | // in that direction. | 1481 | // in that direction. |
1219 | // TODO: implement reference frame. | 1482 | // TODO: implement reference frame. |
1220 | public Vector3 ComputeAngularDeflection() | 1483 | public void ComputeAngularDeflection() |
1221 | { | 1484 | { |
1222 | Vector3 ret = Vector3.Zero; | ||
1223 | return ret; // DEBUG DEBUG DEBUG | ||
1224 | // Disable angular deflection for the moment. | ||
1225 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate | 1485 | // Since angularMotorUp and angularDeflection are computed independently, they will calculate |
1226 | // approximately the same X or Y correction. When added together (when contributions are combined) | 1486 | // approximately the same X or Y correction. When added together (when contributions are combined) |
1227 | // this creates an over-correction and then wabbling as the target is overshot. | 1487 | // this creates an over-correction and then wabbling as the target is overshot. |
1228 | // TODO: rethink how the different correction computations inter-relate. | 1488 | // TODO: rethink how the different correction computations inter-relate. |
1229 | 1489 | ||
1230 | if (m_angularDeflectionEfficiency != 0) | 1490 | if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2) |
1231 | { | 1491 | { |
1492 | Vector3 deflectContributionV = Vector3.Zero; | ||
1493 | |||
1232 | // The direction the vehicle is moving | 1494 | // The direction the vehicle is moving |
1233 | Vector3 movingDirection = VehicleVelocity; | 1495 | Vector3 movingDirection = VehicleVelocity; |
1234 | movingDirection.Normalize(); | 1496 | movingDirection.Normalize(); |
1235 | 1497 | ||
1498 | // If the vehicle is going backward, it is still pointing forward | ||
1499 | movingDirection *= Math.Sign(VehicleForwardSpeed); | ||
1500 | |||
1236 | // The direction the vehicle is pointing | 1501 | // The direction the vehicle is pointing |
1237 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | 1502 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; |
1238 | pointingDirection.Normalize(); | 1503 | pointingDirection.Normalize(); |
@@ -1241,6 +1506,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1241 | Vector3 deflectionError = movingDirection - pointingDirection; | 1506 | Vector3 deflectionError = movingDirection - pointingDirection; |
1242 | 1507 | ||
1243 | // Don't try to correct very large errors (not our job) | 1508 | // Don't try to correct very large errors (not our job) |
1509 | // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X); | ||
1510 | // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y); | ||
1511 | // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z); | ||
1244 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; | 1512 | if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; |
1245 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; | 1513 | if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; |
1246 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; | 1514 | if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; |
@@ -1248,18 +1516,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1248 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); | 1516 | // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); |
1249 | 1517 | ||
1250 | // Scale the correction by recovery timescale and efficiency | 1518 | // Scale the correction by recovery timescale and efficiency |
1251 | ret = (-deflectionError) * m_angularDeflectionEfficiency; | 1519 | deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency; |
1252 | ret /= m_angularDeflectionTimescale; | 1520 | deflectContributionV /= m_angularDeflectionTimescale; |
1521 | |||
1522 | VehicleRotationalVelocity += deflectContributionV * VehicleOrientation; | ||
1253 | 1523 | ||
1254 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | 1524 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", |
1255 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | 1525 | ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV); |
1256 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", | 1526 | VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", |
1257 | Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); | 1527 | ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); |
1258 | } | 1528 | } |
1259 | return ret; | ||
1260 | } | 1529 | } |
1261 | 1530 | ||
1262 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | 1531 | // Angular change to rotate the vehicle around the Z axis when the vehicle |
1263 | // is tipped around the X axis. | 1532 | // is tipped around the X axis. |
1264 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | 1533 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
1265 | // The vertical attractor feature must be enabled in order for the banking behavior to | 1534 | // The vertical attractor feature must be enabled in order for the banking behavior to |
@@ -1267,13 +1536,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1267 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | 1536 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude |
1268 | // of the yaw effect will be proportional to the | 1537 | // of the yaw effect will be proportional to the |
1269 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | 1538 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's |
1270 | // velocity along its preferred axis of motion. | 1539 | // velocity along its preferred axis of motion. |
1271 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | 1540 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any |
1272 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | 1541 | // positive rotation (by the right-hand rule) about the roll-axis will effect a |
1273 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | 1542 | // (negative) torque around the yaw-axis, making it turn to the right--that is the |
1274 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | 1543 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. |
1275 | // Negating the banking coefficient will make it so that the vehicle leans to the | 1544 | // Negating the banking coefficient will make it so that the vehicle leans to the |
1276 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | 1545 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). |
1277 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | 1546 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making |
1278 | // banking vehicles do what you want rather than what the laws of physics allow. | 1547 | // banking vehicles do what you want rather than what the laws of physics allow. |
1279 | // For example, consider a real motorcycle...it must be moving forward in order for | 1548 | // For example, consider a real motorcycle...it must be moving forward in order for |
@@ -1285,46 +1554,44 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1285 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | 1554 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the |
1286 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | 1555 | // banking effect depends only on the vehicle's rotation about its roll-axis compared |
1287 | // to "dynamic" where the banking is also proportional to its velocity along its | 1556 | // to "dynamic" where the banking is also proportional to its velocity along its |
1288 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | 1557 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. |
1289 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | 1558 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the |
1290 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | 1559 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to |
1291 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | 1560 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can |
1292 | // make a sluggish vehicle by giving it a timescale of several seconds. | 1561 | // make a sluggish vehicle by giving it a timescale of several seconds. |
1293 | public Vector3 ComputeAngularBanking() | 1562 | public void ComputeAngularBanking() |
1294 | { | 1563 | { |
1295 | Vector3 ret = Vector3.Zero; | 1564 | if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) |
1296 | |||
1297 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1298 | { | 1565 | { |
1299 | // This works by rotating a unit vector to the orientation of the vehicle. The | 1566 | Vector3 bankingContributionV = Vector3.Zero; |
1300 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt | 1567 | |
1301 | // up to one for full over). | 1568 | // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented. |
1569 | // As the vehicle rolls to the right or left, the Y value will increase from | ||
1570 | // zero (straight up) to 1 or -1 (full tilt right or left) | ||
1302 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; | 1571 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1303 | 1572 | ||
1304 | // Figure out the yaw value for this much roll. | 1573 | // Figure out the yaw value for this much roll. |
1305 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; | 1574 | float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency; |
1306 | // Keep the sign | ||
1307 | if (rollComponents.Y < 0f) | ||
1308 | turnComponent = -turnComponent; | ||
1309 | |||
1310 | // TODO: there must be a better computation of the banking force. | ||
1311 | float bankingTurnForce = turnComponent; | ||
1312 | |||
1313 | // actual error = static turn error + dynamic turn error | 1575 | // actual error = static turn error + dynamic turn error |
1314 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | 1576 | float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed); |
1577 | |||
1315 | // TODO: the banking effect should not go to infinity but what to limit it to? | 1578 | // TODO: the banking effect should not go to infinity but what to limit it to? |
1316 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | 1579 | // And what should happen when this is being added to a user defined yaw that is already PI*4? |
1580 | mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12); | ||
1317 | 1581 | ||
1318 | // Build the force vector to change rotation from what it is to what it should be | 1582 | // Build the force vector to change rotation from what it is to what it should be |
1319 | ret.Z = -mixedBankingError; | 1583 | bankingContributionV.Z = -mixedYawAngle; |
1584 | |||
1585 | // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4. | ||
1586 | bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge; | ||
1320 | 1587 | ||
1321 | // Don't do it all at once. | 1588 | //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation; |
1322 | ret /= m_bankingTimescale; | 1589 | VehicleRotationalVelocity += bankingContributionV; |
1323 | 1590 | ||
1324 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | 1591 | |
1325 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | 1592 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}", |
1593 | ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV); | ||
1326 | } | 1594 | } |
1327 | return ret; | ||
1328 | } | 1595 | } |
1329 | 1596 | ||
1330 | // This is from previous instantiations of XXXDynamics.cs. | 1597 | // This is from previous instantiations of XXXDynamics.cs. |
@@ -1362,11 +1629,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1362 | if (rotq != m_rot) | 1629 | if (rotq != m_rot) |
1363 | { | 1630 | { |
1364 | VehicleOrientation = m_rot; | 1631 | VehicleOrientation = m_rot; |
1365 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1632 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot); |
1366 | } | 1633 | } |
1367 | 1634 | ||
1368 | } | 1635 | } |
1369 | 1636 | ||
1637 | // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce | ||
1638 | // some value by to apply this friction. | ||
1639 | private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep) | ||
1640 | { | ||
1641 | Vector3 frictionFactor = Vector3.Zero; | ||
1642 | if (friction != BSMotor.InfiniteVector) | ||
1643 | { | ||
1644 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
1645 | // Individual friction components can be 'infinite' so compute each separately. | ||
1646 | frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X); | ||
1647 | frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y); | ||
1648 | frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z); | ||
1649 | frictionFactor *= pTimestep; | ||
1650 | } | ||
1651 | return frictionFactor; | ||
1652 | } | ||
1653 | |||
1370 | private float ClampInRange(float low, float val, float high) | 1654 | private float ClampInRange(float low, float val, float high) |
1371 | { | 1655 | { |
1372 | return Math.Max(low, Math.Min(val, high)); | 1656 | return Math.Max(low, Math.Min(val, high)); |
@@ -1376,8 +1660,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1376 | // Invoke the detailed logger and output something if it's enabled. | 1660 | // Invoke the detailed logger and output something if it's enabled. |
1377 | private void VDetailLog(string msg, params Object[] args) | 1661 | private void VDetailLog(string msg, params Object[] args) |
1378 | { | 1662 | { |
1379 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 1663 | if (ControllingPrim.PhysScene.VehicleLoggingEnabled) |
1380 | Prim.PhysicsScene.DetailLog(msg, args); | 1664 | ControllingPrim.PhysScene.DetailLog(msg, args); |
1381 | } | 1665 | } |
1382 | } | 1666 | } |
1383 | } | 1667 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 756faed..76c2187 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -52,7 +52,7 @@ public abstract class BSLinkset | |||
52 | Manual = 2 // linkset tied together manually (code moves all the pieces) | 52 | Manual = 2 // linkset tied together manually (code moves all the pieces) |
53 | } | 53 | } |
54 | // Create the correct type of linkset for this child | 54 | // Create the correct type of linkset for this child |
55 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | 55 | public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) |
56 | { | 56 | { |
57 | BSLinkset ret = null; | 57 | BSLinkset ret = null; |
58 | 58 | ||
@@ -71,31 +71,28 @@ public abstract class BSLinkset | |||
71 | ret = new BSLinksetCompound(physScene, parent); | 71 | ret = new BSLinksetCompound(physScene, parent); |
72 | break; | 72 | break; |
73 | } | 73 | } |
74 | if (ret == null) | ||
75 | { | ||
76 | physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); | ||
77 | } | ||
74 | return ret; | 78 | return ret; |
75 | } | 79 | } |
76 | 80 | ||
77 | public BSPhysObject LinksetRoot { get; protected set; } | 81 | public BSPrimLinkable LinksetRoot { get; protected set; } |
78 | 82 | ||
79 | public BSScene PhysicsScene { get; private set; } | 83 | protected BSScene m_physicsScene { get; private set; } |
80 | 84 | ||
81 | static int m_nextLinksetID = 1; | 85 | static int m_nextLinksetID = 1; |
82 | public int LinksetID { get; private set; } | 86 | public int LinksetID { get; private set; } |
83 | 87 | ||
84 | // The children under the root in this linkset. | 88 | // The children under the root in this linkset. |
85 | protected HashSet<BSPhysObject> m_children; | 89 | protected HashSet<BSPrimLinkable> m_children; |
86 | 90 | ||
87 | // We lock the diddling of linkset classes to prevent any badness. | 91 | // We lock the diddling of linkset classes to prevent any badness. |
88 | // This locks the modification of the instances of this class. Changes | 92 | // This locks the modification of the instances of this class. Changes |
89 | // to the physical representation is done via the tainting mechenism. | 93 | // to the physical representation is done via the tainting mechenism. |
90 | protected object m_linksetActivityLock = new Object(); | 94 | protected object m_linksetActivityLock = new Object(); |
91 | 95 | ||
92 | // Some linksets have a preferred physical shape. | ||
93 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
94 | public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
95 | { | ||
96 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
97 | } | ||
98 | |||
99 | // 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 |
100 | public float LinksetMass { get; protected set; } | 97 | public float LinksetMass { get; protected set; } |
101 | 98 | ||
@@ -111,25 +108,27 @@ public abstract class BSLinkset | |||
111 | get { return ComputeLinksetGeometricCenter(); } | 108 | get { return ComputeLinksetGeometricCenter(); } |
112 | } | 109 | } |
113 | 110 | ||
114 | protected BSLinkset(BSScene scene, BSPhysObject parent) | 111 | protected BSLinkset(BSScene scene, BSPrimLinkable parent) |
115 | { | 112 | { |
116 | // A simple linkset of one (no children) | 113 | // A simple linkset of one (no children) |
117 | LinksetID = m_nextLinksetID++; | 114 | LinksetID = m_nextLinksetID++; |
118 | // We create LOTS of linksets. | 115 | // We create LOTS of linksets. |
119 | if (m_nextLinksetID <= 0) | 116 | if (m_nextLinksetID <= 0) |
120 | m_nextLinksetID = 1; | 117 | m_nextLinksetID = 1; |
121 | PhysicsScene = scene; | 118 | m_physicsScene = scene; |
122 | LinksetRoot = parent; | 119 | LinksetRoot = parent; |
123 | m_children = new HashSet<BSPhysObject>(); | 120 | m_children = new HashSet<BSPrimLinkable>(); |
124 | LinksetMass = parent.RawMass; | 121 | LinksetMass = parent.RawMass; |
125 | Rebuilding = false; | 122 | Rebuilding = false; |
123 | |||
124 | parent.ClearDisplacement(); | ||
126 | } | 125 | } |
127 | 126 | ||
128 | // Link to a linkset where the child knows the parent. | 127 | // Link to a linkset where the child knows the parent. |
129 | // Parent changing should not happen so do some sanity checking. | 128 | // Parent changing should not happen so do some sanity checking. |
130 | // We return the parent's linkset so the child can track its membership. | 129 | // We return the parent's linkset so the child can track its membership. |
131 | // Called at runtime. | 130 | // Called at runtime. |
132 | public BSLinkset AddMeToLinkset(BSPhysObject child) | 131 | public BSLinkset AddMeToLinkset(BSPrimLinkable child) |
133 | { | 132 | { |
134 | lock (m_linksetActivityLock) | 133 | lock (m_linksetActivityLock) |
135 | { | 134 | { |
@@ -145,7 +144,7 @@ public abstract class BSLinkset | |||
145 | // Returns a new linkset for the child which is a linkset of one (just the | 144 | // Returns a new linkset for the child which is a linkset of one (just the |
146 | // orphened child). | 145 | // orphened child). |
147 | // Called at runtime. | 146 | // Called at runtime. |
148 | public BSLinkset RemoveMeFromLinkset(BSPhysObject child) | 147 | public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child) |
149 | { | 148 | { |
150 | lock (m_linksetActivityLock) | 149 | lock (m_linksetActivityLock) |
151 | { | 150 | { |
@@ -159,11 +158,11 @@ public abstract class BSLinkset | |||
159 | } | 158 | } |
160 | 159 | ||
161 | // The child is down to a linkset of just itself | 160 | // The child is down to a linkset of just itself |
162 | return BSLinkset.Factory(PhysicsScene, child); | 161 | return BSLinkset.Factory(m_physicsScene, child); |
163 | } | 162 | } |
164 | 163 | ||
165 | // 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 |
166 | public bool IsRoot(BSPhysObject requestor) | 165 | public bool IsRoot(BSPrimLinkable requestor) |
167 | { | 166 | { |
168 | return (requestor.LocalID == LinksetRoot.LocalID); | 167 | return (requestor.LocalID == LinksetRoot.LocalID); |
169 | } | 168 | } |
@@ -174,14 +173,14 @@ public abstract class BSLinkset | |||
174 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | 173 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } |
175 | 174 | ||
176 | // Return 'true' if this child is in this linkset | 175 | // Return 'true' if this child is in this linkset |
177 | public bool HasChild(BSPhysObject child) | 176 | public bool HasChild(BSPrimLinkable child) |
178 | { | 177 | { |
179 | bool ret = false; | 178 | bool ret = false; |
180 | lock (m_linksetActivityLock) | 179 | lock (m_linksetActivityLock) |
181 | { | 180 | { |
182 | ret = m_children.Contains(child); | 181 | ret = m_children.Contains(child); |
183 | /* Safer version but the above should work | 182 | /* Safer version but the above should work |
184 | foreach (BSPhysObject bp in m_children) | 183 | foreach (BSPrimLinkable bp in m_children) |
185 | { | 184 | { |
186 | if (child.LocalID == bp.LocalID) | 185 | if (child.LocalID == bp.LocalID) |
187 | { | 186 | { |
@@ -196,14 +195,14 @@ public abstract class BSLinkset | |||
196 | 195 | ||
197 | // Perform an action on each member of the linkset including root prim. | 196 | // Perform an action on each member of the linkset including root prim. |
198 | // Depends on the action on whether this should be done at taint time. | 197 | // Depends on the action on whether this should be done at taint time. |
199 | public delegate bool ForEachMemberAction(BSPhysObject obj); | 198 | public delegate bool ForEachMemberAction(BSPrimLinkable obj); |
200 | public virtual bool ForEachMember(ForEachMemberAction action) | 199 | public virtual bool ForEachMember(ForEachMemberAction action) |
201 | { | 200 | { |
202 | bool ret = false; | 201 | bool ret = false; |
203 | lock (m_linksetActivityLock) | 202 | lock (m_linksetActivityLock) |
204 | { | 203 | { |
205 | action(LinksetRoot); | 204 | action(LinksetRoot); |
206 | foreach (BSPhysObject po in m_children) | 205 | foreach (BSPrimLinkable po in m_children) |
207 | { | 206 | { |
208 | if (action(po)) | 207 | if (action(po)) |
209 | break; | 208 | break; |
@@ -214,16 +213,16 @@ public abstract class BSLinkset | |||
214 | 213 | ||
215 | // 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 |
216 | // Called while LinkActivity is locked. | 215 | // Called while LinkActivity is locked. |
217 | protected abstract void AddChildToLinkset(BSPhysObject child); | 216 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
218 | 217 | ||
219 | // 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. |
220 | // 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. |
221 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 220 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child); |
222 | 221 | ||
223 | // When physical properties are changed the linkset needs to recalculate | 222 | // When physical properties are changed the linkset needs to recalculate |
224 | // its internal properties. | 223 | // its internal properties. |
225 | // May be called at runtime or taint-time. | 224 | // May be called at runtime or taint-time. |
226 | public virtual void Refresh(BSPhysObject requestor) | 225 | public virtual void Refresh(BSPrimLinkable requestor) |
227 | { | 226 | { |
228 | LinksetMass = ComputeLinksetMass(); | 227 | LinksetMass = ComputeLinksetMass(); |
229 | } | 228 | } |
@@ -238,31 +237,26 @@ public abstract class BSLinkset | |||
238 | // has not yet been fully constructed. | 237 | // has not yet been fully constructed. |
239 | // Return 'true' if any properties updated on the passed object. | 238 | // Return 'true' if any properties updated on the passed object. |
240 | // Called at taint-time! | 239 | // Called at taint-time! |
241 | public abstract bool MakeDynamic(BSPhysObject child); | 240 | public abstract bool MakeDynamic(BSPrimLinkable child); |
242 | 241 | ||
243 | // The object is going static (non-physical). Do any setup necessary | 242 | // The object is going static (non-physical). Do any setup necessary |
244 | // for a static linkset. | 243 | // for a static linkset. |
245 | // Return 'true' if any properties updated on the passed object. | 244 | // Return 'true' if any properties updated on the passed object. |
246 | // Called at taint-time! | 245 | // Called at taint-time! |
247 | public abstract bool MakeStatic(BSPhysObject child); | 246 | public abstract bool MakeStatic(BSPrimLinkable child); |
248 | 247 | ||
249 | // Called when a parameter update comes from the physics engine for any object | 248 | // Called when a parameter update comes from the physics engine for any object |
250 | // of the linkset is received. | 249 | // of the linkset is received. |
251 | // Passed flag is update came from physics engine (true) or the user (false). | 250 | // Passed flag is update came from physics engine (true) or the user (false). |
252 | // Called at taint-time!! | 251 | // Called at taint-time!! |
253 | public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); | 252 | public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); |
254 | 253 | ||
255 | // Routine used when rebuilding the body of the root of the linkset | 254 | // Routine used when rebuilding the body of the root of the linkset |
256 | // Destroy all the constraints have have been made to root. | 255 | // Destroy all the constraints have have been made to root. |
257 | // This is called when the root body is changing. | 256 | // This is called when the root body is changing. |
258 | // Returns 'true' of something was actually removed and would need restoring | 257 | // Returns 'true' of something was actually removed and would need restoring |
259 | // Called at taint-time!! | 258 | // Called at taint-time!! |
260 | public abstract bool RemoveBodyDependencies(BSPrim child); | 259 | public abstract bool RemoveDependencies(BSPrimLinkable child); |
261 | |||
262 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
263 | // this routine will restore the removed constraints. | ||
264 | // Called at taint-time!! | ||
265 | public abstract void RestoreBodyDependencies(BSPrim child); | ||
266 | 260 | ||
267 | // ================================================================ | 261 | // ================================================================ |
268 | protected virtual float ComputeLinksetMass() | 262 | protected virtual float ComputeLinksetMass() |
@@ -272,7 +266,7 @@ public abstract class BSLinkset | |||
272 | { | 266 | { |
273 | lock (m_linksetActivityLock) | 267 | lock (m_linksetActivityLock) |
274 | { | 268 | { |
275 | foreach (BSPhysObject bp in m_children) | 269 | foreach (BSPrimLinkable bp in m_children) |
276 | { | 270 | { |
277 | mass += bp.RawMass; | 271 | mass += bp.RawMass; |
278 | } | 272 | } |
@@ -281,6 +275,7 @@ public abstract class BSLinkset | |||
281 | return mass; | 275 | return mass; |
282 | } | 276 | } |
283 | 277 | ||
278 | // Computes linkset's center of mass in world coordinates. | ||
284 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | 279 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() |
285 | { | 280 | { |
286 | OMV.Vector3 com; | 281 | OMV.Vector3 com; |
@@ -289,7 +284,7 @@ public abstract class BSLinkset | |||
289 | com = LinksetRoot.Position * LinksetRoot.RawMass; | 284 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
290 | float totalMass = LinksetRoot.RawMass; | 285 | float totalMass = LinksetRoot.RawMass; |
291 | 286 | ||
292 | foreach (BSPhysObject bp in m_children) | 287 | foreach (BSPrimLinkable bp in m_children) |
293 | { | 288 | { |
294 | com += bp.Position * bp.RawMass; | 289 | com += bp.Position * bp.RawMass; |
295 | totalMass += bp.RawMass; | 290 | totalMass += bp.RawMass; |
@@ -308,9 +303,9 @@ public abstract class BSLinkset | |||
308 | { | 303 | { |
309 | com = LinksetRoot.Position; | 304 | com = LinksetRoot.Position; |
310 | 305 | ||
311 | foreach (BSPhysObject bp in m_children) | 306 | foreach (BSPrimLinkable bp in m_children) |
312 | { | 307 | { |
313 | com += bp.Position * bp.RawMass; | 308 | com += bp.Position; |
314 | } | 309 | } |
315 | com /= (m_children.Count + 1); | 310 | com /= (m_children.Count + 1); |
316 | } | 311 | } |
@@ -321,8 +316,8 @@ public abstract class BSLinkset | |||
321 | // Invoke the detailed logger and output something if it's enabled. | 316 | // Invoke the detailed logger and output something if it's enabled. |
322 | protected void DetailLog(string msg, params Object[] args) | 317 | protected void DetailLog(string msg, params Object[] args) |
323 | { | 318 | { |
324 | if (PhysicsScene.PhysicsLogging.Enabled) | 319 | if (m_physicsScene.PhysicsLogging.Enabled) |
325 | PhysicsScene.DetailLog(msg, args); | 320 | m_physicsScene.DetailLog(msg, args); |
326 | } | 321 | } |
327 | 322 | ||
328 | } | 323 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index bd03d31..350a5d1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,59 +35,74 @@ 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. |
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | 42 | sealed class BSLinksetCompoundInfo : BSLinksetInfo |
42 | { | 43 | { |
43 | public OMV.Vector3 OffsetPos; | 44 | public int Index; |
45 | public OMV.Vector3 OffsetFromRoot; | ||
46 | public OMV.Vector3 OffsetFromCenterOfMass; | ||
44 | public OMV.Quaternion OffsetRot; | 47 | public OMV.Quaternion OffsetRot; |
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | 48 | public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) |
46 | { | 49 | { |
47 | OffsetPos = p; | 50 | Index = indx; |
51 | OffsetFromRoot = p; | ||
52 | OffsetFromCenterOfMass = p; | ||
48 | OffsetRot = r; | 53 | OffsetRot = r; |
49 | } | 54 | } |
55 | // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) | ||
56 | public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) | ||
57 | { | ||
58 | // Each child position and rotation is given relative to the center-of-mass. | ||
59 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); | ||
60 | OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; | ||
61 | OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; | ||
62 | OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; | ||
63 | |||
64 | // Save relative position for recomputing child's world position after moving linkset. | ||
65 | Index = indx; | ||
66 | OffsetFromRoot = displacementFromRoot; | ||
67 | OffsetFromCenterOfMass = displacementFromCOM; | ||
68 | OffsetRot = displacementRot; | ||
69 | } | ||
50 | public override void Clear() | 70 | public override void Clear() |
51 | { | 71 | { |
52 | OffsetPos = OMV.Vector3.Zero; | 72 | Index = 0; |
73 | OffsetFromRoot = OMV.Vector3.Zero; | ||
74 | OffsetFromCenterOfMass = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | 75 | OffsetRot = OMV.Quaternion.Identity; |
54 | } | 76 | } |
55 | public override string ToString() | 77 | public override string ToString() |
56 | { | 78 | { |
57 | StringBuilder buff = new StringBuilder(); | 79 | StringBuilder buff = new StringBuilder(); |
58 | buff.Append("<p="); | 80 | buff.Append("<i="); |
59 | buff.Append(OffsetPos.ToString()); | 81 | buff.Append(Index.ToString()); |
82 | buff.Append(",p="); | ||
83 | buff.Append(OffsetFromRoot.ToString()); | ||
84 | buff.Append(",m="); | ||
85 | buff.Append(OffsetFromCenterOfMass.ToString()); | ||
60 | buff.Append(",r="); | 86 | buff.Append(",r="); |
61 | buff.Append(OffsetRot.ToString()); | 87 | buff.Append(OffsetRot.ToString()); |
62 | buff.Append(">"); | 88 | buff.Append(">"); |
63 | return buff.ToString(); | 89 | return buff.ToString(); |
64 | } | 90 | } |
65 | }; | 91 | }; |
92 | */ | ||
66 | 93 | ||
67 | public sealed class BSLinksetCompound : BSLinkset | 94 | public sealed class BSLinksetCompound : BSLinkset |
68 | { | 95 | { |
69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 96 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
70 | 97 | ||
71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) | 98 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) |
99 | : base(scene, parent) | ||
72 | { | 100 | { |
73 | } | 101 | } |
74 | 102 | ||
75 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
77 | { | ||
78 | // Returning 'unknown' means we don't have a preference. | ||
79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
80 | if (IsRoot(requestor) && HasAnyChildren) | ||
81 | { | ||
82 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
83 | } | ||
84 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | // When physical properties are changed the linkset needs to recalculate | 103 | // When physical properties are changed the linkset needs to recalculate |
89 | // its internal properties. | 104 | // its internal properties. |
90 | public override void Refresh(BSPhysObject requestor) | 105 | public override void Refresh(BSPrimLinkable requestor) |
91 | { | 106 | { |
92 | base.Refresh(requestor); | 107 | base.Refresh(requestor); |
93 | 108 | ||
@@ -96,16 +111,16 @@ public sealed class BSLinksetCompound : BSLinkset | |||
96 | } | 111 | } |
97 | 112 | ||
98 | // Schedule a refresh to happen after all the other taint processing. | 113 | // Schedule a refresh to happen after all the other taint processing. |
99 | private void ScheduleRebuild(BSPhysObject requestor) | 114 | private void ScheduleRebuild(BSPrimLinkable requestor) |
100 | { | 115 | { |
101 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", | 116 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
102 | requestor.LocalID, Rebuilding, HasAnyChildren); | 117 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
103 | // 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. |
104 | // If already rebuilding, don't request another rebuild. | 119 | // If already rebuilding, don't request another rebuild. |
105 | // 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. |
106 | if (!Rebuilding && HasAnyChildren) | 121 | if (!Rebuilding && HasAnyChildren) |
107 | { | 122 | { |
108 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 123 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
109 | { | 124 | { |
110 | if (HasAnyChildren) | 125 | if (HasAnyChildren) |
111 | RecomputeLinksetCompound(); | 126 | RecomputeLinksetCompound(); |
@@ -118,7 +133,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
118 | // has not yet been fully constructed. | 133 | // has not yet been fully constructed. |
119 | // Return 'true' if any properties updated on the passed object. | 134 | // Return 'true' if any properties updated on the passed object. |
120 | // Called at taint-time! | 135 | // Called at taint-time! |
121 | public override bool MakeDynamic(BSPhysObject child) | 136 | public override bool MakeDynamic(BSPrimLinkable child) |
122 | { | 137 | { |
123 | bool ret = false; | 138 | bool ret = false; |
124 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 139 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
@@ -127,138 +142,131 @@ public sealed class BSLinksetCompound : BSLinkset | |||
127 | // 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. |
128 | ScheduleRebuild(LinksetRoot); | 143 | ScheduleRebuild(LinksetRoot); |
129 | } | 144 | } |
130 | else | ||
131 | { | ||
132 | // The origional prims are removed from the world as the shape of the root compound | ||
133 | // shape takes over. | ||
134 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
135 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
136 | // We don't want collisions from the old linkset children. | ||
137 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
138 | |||
139 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
140 | |||
141 | ret = true; | ||
142 | } | ||
143 | return ret; | 145 | return ret; |
144 | } | 146 | } |
145 | 147 | ||
146 | // 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. |
147 | // Return 'true' if any properties updated on the passed object. | 149 | // Return 'true' if any properties updated on the passed object. |
148 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
149 | // world if it is a static linkset. | ||
150 | // Called at taint-time! | 150 | // Called at taint-time! |
151 | public override bool MakeStatic(BSPhysObject child) | 151 | public override bool MakeStatic(BSPrimLinkable child) |
152 | { | 152 | { |
153 | bool ret = false; | 153 | bool ret = false; |
154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
155 | if (IsRoot(child)) | 155 | if (IsRoot(child)) |
156 | { | 156 | { |
157 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
157 | ScheduleRebuild(LinksetRoot); | 158 | ScheduleRebuild(LinksetRoot); |
158 | } | 159 | } |
159 | else | ||
160 | { | ||
161 | // The non-physical children can come back to life. | ||
162 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
163 | |||
164 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
165 | |||
166 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
167 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
168 | ret = true; | ||
169 | } | ||
170 | return ret; | 160 | return ret; |
171 | } | 161 | } |
172 | 162 | ||
173 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) | 163 | // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. |
164 | // Called at taint-time. | ||
165 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | ||
174 | { | 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 | |||
175 | // 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 |
176 | // 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 |
177 | // is to store 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 |
178 | // but it also means all the child positions get updated. | 177 | // but it also means all the child positions get updated. |
179 | // 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 |
180 | // region before bothering to do a rebuild. | 179 | // region before bothering to do a rebuild. |
181 | if (!IsRoot(updated) | 180 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
182 | && !physicalUpdate | ||
183 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
184 | { | 181 | { |
185 | updated.LinksetInfo = null; | 182 | // If a child of the linkset is updating only the position or rotation, that can be done |
186 | ScheduleRebuild(updated); | 183 | // without rebuilding the linkset. |
184 | // If a handle for the child can be fetch, we update the child here. If a rebuild was | ||
185 | // scheduled by someone else, the rebuild will just replace this setting. | ||
186 | |||
187 | bool updatedChild = false; | ||
188 | // Anything other than updating position or orientation usually means a physical update | ||
189 | // and that is caused by us updating the object. | ||
190 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | ||
191 | { | ||
192 | // Find the physical instance of the child | ||
193 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) | ||
194 | { | ||
195 | // It is possible that the linkset is still under construction and the child is not yet | ||
196 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | ||
197 | // build the whole thing with the new position or rotation. | ||
198 | // The index must be checked because Bullet references the child array but does no validity | ||
199 | // checking of the child index passed. | ||
200 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); | ||
201 | if (updated.LinksetChildIndex < numLinksetChildren) | ||
202 | { | ||
203 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); | ||
204 | if (linksetChildShape.HasPhysicalShape) | ||
205 | { | ||
206 | // Found the child shape within the compound shape | ||
207 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, | ||
208 | updated.RawPosition - LinksetRoot.RawPosition, | ||
209 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | ||
210 | true /* shouldRecalculateLocalAabb */); | ||
211 | updatedChild = true; | ||
212 | DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", | ||
213 | updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); | ||
214 | } | ||
215 | else // DEBUG DEBUG | ||
216 | { // DEBUG DEBUG | ||
217 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", | ||
218 | updated.LocalID, linksetChildShape); | ||
219 | } // DEBUG DEBUG | ||
220 | } | ||
221 | else // DEBUG DEBUG | ||
222 | { // DEBUG DEBUG | ||
223 | // the child is not yet in the compound shape. This is non-fatal. | ||
224 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", | ||
225 | updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); | ||
226 | } // DEBUG DEBUG | ||
227 | } | ||
228 | else // DEBUG DEBUG | ||
229 | { // DEBUG DEBUG | ||
230 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); | ||
231 | } // DEBUG DEBUG | ||
232 | |||
233 | if (!updatedChild) | ||
234 | { | ||
235 | // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. | ||
236 | // Note: there are several ways through this code that will not update the child if | ||
237 | // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since | ||
238 | // there will already be a rebuild scheduled. | ||
239 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | ||
240 | updated.LocalID, whichUpdated); | ||
241 | updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. | ||
242 | ScheduleRebuild(updated); | ||
243 | } | ||
244 | } | ||
187 | } | 245 | } |
188 | } | 246 | } |
189 | 247 | ||
190 | // 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. |
191 | // 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. | ||
192 | // Returns 'true' of something was actually removed and would need restoring | 251 | // Returns 'true' of something was actually removed and would need restoring |
193 | // Called at taint-time!! | 252 | // Called at taint-time!! |
194 | public override bool RemoveBodyDependencies(BSPrim child) | 253 | public override bool RemoveDependencies(BSPrimLinkable child) |
195 | { | 254 | { |
196 | bool ret = false; | 255 | bool ret = false; |
197 | 256 | ||
198 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 257 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
199 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child)); | 258 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
200 | 259 | ||
201 | if (!IsRoot(child)) | 260 | ScheduleRebuild(child); |
202 | { | ||
203 | // Because it is a convenient time, recompute child world position and rotation based on | ||
204 | // its position in the linkset. | ||
205 | RecomputeChildWorldPosition(child, true); | ||
206 | } | ||
207 | |||
208 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
209 | // the linkset is being rebuilt. | ||
210 | // InternalRefresh(LinksetRoot); | ||
211 | 261 | ||
212 | return ret; | 262 | return ret; |
213 | } | 263 | } |
214 | 264 | ||
215 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
216 | // this routine will restore the removed constraints. | ||
217 | // Called at taint-time!! | ||
218 | public override void RestoreBodyDependencies(BSPrim child) | ||
219 | { | ||
220 | } | ||
221 | |||
222 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
223 | // root shape. The linkset then moves around but this does not move the actual child | ||
224 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
225 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
226 | { | ||
227 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
228 | if (lci != null) | ||
229 | { | ||
230 | if (inTaintTime) | ||
231 | { | ||
232 | OMV.Vector3 oldPos = child.RawPosition; | ||
233 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
234 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
235 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
236 | child.LocalID, oldPos, lci, child.RawPosition); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
241 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
242 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
243 | } | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // This happens when children have been added to the linkset but the linkset | ||
248 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
249 | // and then changing properties of the children (makePhysical, for instance) | ||
250 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
251 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
252 | // LogHeader, child.LocalID); | ||
253 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // ================================================================ | 265 | // ================================================================ |
258 | 266 | ||
259 | // Add a new child to the linkset. | 267 | // Add a new child to the linkset. |
260 | // Called while LinkActivity is locked. | 268 | // Called while LinkActivity is locked. |
261 | protected override void AddChildToLinkset(BSPhysObject child) | 269 | protected override void AddChildToLinkset(BSPrimLinkable child) |
262 | { | 270 | { |
263 | if (!HasChild(child)) | 271 | if (!HasChild(child)) |
264 | { | 272 | { |
@@ -274,8 +282,10 @@ public sealed class BSLinksetCompound : BSLinkset | |||
274 | 282 | ||
275 | // Remove the specified child from the linkset. | 283 | // Remove the specified child from the linkset. |
276 | // Safe to call even if the child is not really in the linkset. | 284 | // Safe to call even if the child is not really in the linkset. |
277 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 285 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) |
278 | { | 286 | { |
287 | child.ClearDisplacement(); | ||
288 | |||
279 | if (m_children.Remove(child)) | 289 | if (m_children.Remove(child)) |
280 | { | 290 | { |
281 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 291 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
@@ -284,7 +294,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
284 | child.LocalID, child.PhysBody.AddrString); | 294 | child.LocalID, child.PhysBody.AddrString); |
285 | 295 | ||
286 | // 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 |
287 | RecomputeChildWorldPosition(child, false); | 297 | child.LinksetInfo = null; |
288 | child.ForceBodyShapeRebuild(false); | 298 | child.ForceBodyShapeRebuild(false); |
289 | 299 | ||
290 | if (!HasAnyChildren) | 300 | if (!HasAnyChildren) |
@@ -295,7 +305,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
295 | else | 305 | else |
296 | { | 306 | { |
297 | // Rebuild the compound shape with the child removed | 307 | // Rebuild the compound shape with the child removed |
298 | ScheduleRebuild(child); | 308 | ScheduleRebuild(LinksetRoot); |
299 | } | 309 | } |
300 | } | 310 | } |
301 | return; | 311 | return; |
@@ -306,87 +316,113 @@ public sealed class BSLinksetCompound : BSLinkset | |||
306 | // Constraint linksets are rebuilt every time. | 316 | // Constraint linksets are rebuilt every time. |
307 | // 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. |
308 | // Called at taint time!! | 318 | // Called at taint time!! |
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 | ||
309 | private void RecomputeLinksetCompound() | 321 | private void RecomputeLinksetCompound() |
310 | { | 322 | { |
311 | try | 323 | try |
312 | { | 324 | { |
313 | // Suppress rebuilding while rebuilding | ||
314 | Rebuilding = true; | 325 | Rebuilding = true; |
315 | 326 | ||
316 | // 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 |
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. | ||
317 | LinksetRoot.ForceBodyShapeRebuild(true); | 331 | LinksetRoot.ForceBodyShapeRebuild(true); |
318 | 332 | ||
319 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 333 | // There is no reason to build all this physical stuff for a non-physical linkset. |
320 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 334 | if (!LinksetRoot.IsPhysicallyActive) |
335 | { | ||
336 | // Clean up any old linkset shape and make sure the root shape is set to the root object. | ||
337 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); | ||
338 | |||
339 | return; // Note the 'finally' clause at the botton which will get executed. | ||
340 | } | ||
341 | |||
342 | // Get a new compound shape to build the linkset shape in. | ||
343 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | ||
321 | 344 | ||
322 | // Add a shape for each of the other children in the linkset | 345 | // The center of mass for the linkset is the geometric center of the group. |
323 | ForEachMember(delegate(BSPhysObject cPrim) | 346 | // Compute a displacement for each component so it is relative to the center-of-mass. |
347 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
348 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); | ||
349 | |||
350 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); | ||
351 | |||
352 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
353 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
354 | if (UseBulletSimRootOffsetHack || disableCOM) | ||
324 | { | 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); | ||
365 | |||
366 | // Add the shapes of all the components of the linkset | ||
367 | int memberIndex = 1; | ||
368 | ForEachMember(delegate(BSPrimLinkable cPrim) | ||
369 | { | ||
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 | ||
325 | if (!IsRoot(cPrim)) | 382 | if (!IsRoot(cPrim)) |
326 | { | 383 | { |
327 | // Compute the displacement of the child from the root of the linkset. | 384 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
328 | // This info is saved in the child prim so the relationship does not | 385 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); |
329 | // change over time and the new child position can be computed | 386 | // We don't want collisions from the old linkset children. |
330 | // when the linkset is being disassembled (the linkset may have moved). | 387 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
331 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | 388 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; |
332 | if (lci == null) | 389 | } |
333 | { | ||
334 | // Each child position and rotation is given relative to the root. | ||
335 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
336 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
337 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
338 | |||
339 | // Save relative position for recomputing child's world position after moving linkset. | ||
340 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
341 | cPrim.LinksetInfo = lci; | ||
342 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
343 | } | ||
344 | 390 | ||
345 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 391 | memberIndex++; |
346 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
347 | 392 | ||
348 | if (cPrim.PhysShape.isNativeShape) | ||
349 | { | ||
350 | // A native shape is turning into a hull collision shape because native | ||
351 | // shapes are not shared so we have to hullify it so it will be tracked | ||
352 | // and freed at the correct time. This also solves the scaling problem | ||
353 | // (native shapes scaled but hull/meshes are assumed to not be). | ||
354 | // TODO: decide of the native shape can just be used in the compound shape. | ||
355 | // Use call to CreateGeomNonSpecial(). | ||
356 | BulletShape saveShape = cPrim.PhysShape; | ||
357 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
358 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
359 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
360 | BulletShape newShape = cPrim.PhysShape; | ||
361 | cPrim.PhysShape = saveShape; | ||
362 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot); | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
367 | // The reference count added here will be decremented when the compound shape | ||
368 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
369 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
370 | { | ||
371 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
372 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
373 | } | ||
374 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
375 | } | ||
376 | } | ||
377 | 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 |
378 | }); | 394 | }); |
379 | 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 | |||
380 | // 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. |
381 | LinksetMass = ComputeLinksetMass(); | 407 | LinksetMass = ComputeLinksetMass(); |
382 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 408 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
409 | |||
410 | if (UseBulletSimRootOffsetHack) | ||
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 | } | ||
383 | } | 418 | } |
384 | finally | 419 | finally |
385 | { | 420 | { |
386 | Rebuilding = false; | 421 | Rebuilding = false; |
387 | } | 422 | } |
388 | 423 | ||
389 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | 424 | // See that the Aabb surrounds the new shape |
425 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); | ||
390 | } | 426 | } |
391 | } | 427 | } |
392 | } \ 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 d0b2a56..a06a44d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,7 +36,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) | 39 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) |
40 | { | 40 | { |
41 | } | 41 | } |
42 | 42 | ||
@@ -44,14 +44,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
44 | // its internal properties. | 44 | // its internal properties. |
45 | // This is queued in the 'post taint' queue so the | 45 | // This is queued in the 'post taint' queue so the |
46 | // refresh will happen once after all the other taints are applied. | 46 | // refresh will happen once after all the other taints are applied. |
47 | public override void Refresh(BSPhysObject requestor) | 47 | public override void Refresh(BSPrimLinkable requestor) |
48 | { | 48 | { |
49 | base.Refresh(requestor); | 49 | base.Refresh(requestor); |
50 | 50 | ||
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(); |
@@ -65,7 +65,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
65 | // has not yet been fully constructed. | 65 | // has not yet been fully constructed. |
66 | // Return 'true' if any properties updated on the passed object. | 66 | // Return 'true' if any properties updated on the passed object. |
67 | // Called at taint-time! | 67 | // Called at taint-time! |
68 | public override bool MakeDynamic(BSPhysObject child) | 68 | public override bool MakeDynamic(BSPrimLinkable child) |
69 | { | 69 | { |
70 | // What is done for each object in BSPrim is what we want. | 70 | // What is done for each object in BSPrim is what we want. |
71 | return false; | 71 | return false; |
@@ -76,14 +76,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
76 | // This doesn't normally happen -- OpenSim removes the objects from the physical | 76 | // This doesn't normally happen -- OpenSim removes the objects from the physical |
77 | // world if it is a static linkset. | 77 | // world if it is a static linkset. |
78 | // Called at taint-time! | 78 | // Called at taint-time! |
79 | public override bool MakeStatic(BSPhysObject child) | 79 | public override bool MakeStatic(BSPrimLinkable child) |
80 | { | 80 | { |
81 | // What is done for each object in BSPrim is what we want. | 81 | // What is done for each object in BSPrim is what we want. |
82 | return false; | 82 | return false; |
83 | } | 83 | } |
84 | 84 | ||
85 | // Called at taint-time!! | 85 | // Called at taint-time!! |
86 | public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) | 86 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) |
87 | { | 87 | { |
88 | // Nothing to do for constraints on property updates | 88 | // Nothing to do for constraints on property updates |
89 | } | 89 | } |
@@ -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(BSPrim 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) |
@@ -110,19 +110,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
110 | return ret; | 110 | return ret; |
111 | } | 111 | } |
112 | 112 | ||
113 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
114 | // this routine will restore the removed constraints. | ||
115 | // Called at taint-time!! | ||
116 | public override void RestoreBodyDependencies(BSPrim child) | ||
117 | { | ||
118 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | ||
119 | } | ||
120 | |||
121 | // ================================================================ | 113 | // ================================================================ |
122 | 114 | ||
123 | // Add a new child to the linkset. | 115 | // Add a new child to the linkset. |
124 | // Called while LinkActivity is locked. | 116 | // Called while LinkActivity is locked. |
125 | protected override void AddChildToLinkset(BSPhysObject child) | 117 | protected override void AddChildToLinkset(BSPrimLinkable child) |
126 | { | 118 | { |
127 | if (!HasChild(child)) | 119 | if (!HasChild(child)) |
128 | { | 120 | { |
@@ -138,19 +130,19 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
138 | 130 | ||
139 | // Remove the specified child from the linkset. | 131 | // Remove the specified child from the linkset. |
140 | // Safe to call even if the child is not really in my linkset. | 132 | // Safe to call even if the child is not really in my linkset. |
141 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 133 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) |
142 | { | 134 | { |
143 | if (m_children.Remove(child)) | 135 | if (m_children.Remove(child)) |
144 | { | 136 | { |
145 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | 137 | BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now |
146 | BSPhysObject childx = child; | 138 | BSPrimLinkable childx = child; |
147 | 139 | ||
148 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 140 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
149 | childx.LocalID, | 141 | childx.LocalID, |
150 | rootx.LocalID, rootx.PhysBody.AddrString, | 142 | rootx.LocalID, rootx.PhysBody.AddrString, |
151 | childx.LocalID, childx.PhysBody.AddrString); | 143 | childx.LocalID, childx.PhysBody.AddrString); |
152 | 144 | ||
153 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 145 | m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
154 | { | 146 | { |
155 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 147 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
156 | }); | 148 | }); |
@@ -167,13 +159,13 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
167 | 159 | ||
168 | // Create a constraint between me (root of linkset) and the passed prim (the child). | 160 | // Create a constraint between me (root of linkset) and the passed prim (the child). |
169 | // Called at taint time! | 161 | // Called at taint time! |
170 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 162 | private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
171 | { | 163 | { |
172 | // Don't build the constraint when asked. Put it off until just before the simulation step. | 164 | // Don't build the constraint when asked. Put it off until just before the simulation step. |
173 | Refresh(rootPrim); | 165 | Refresh(rootPrim); |
174 | } | 166 | } |
175 | 167 | ||
176 | private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim) | 168 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
177 | { | 169 | { |
178 | // Zero motion for children so they don't interpolate | 170 | // Zero motion for children so they don't interpolate |
179 | childPrim.ZeroMotion(true); | 171 | childPrim.ZeroMotion(true); |
@@ -195,7 +187,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
195 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 187 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
196 | 188 | ||
197 | BSConstraint6Dof constrain = new BSConstraint6Dof( | 189 | BSConstraint6Dof constrain = new BSConstraint6Dof( |
198 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); | 190 | m_physicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); |
199 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | 191 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); |
200 | 192 | ||
201 | /* 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. |
@@ -224,15 +216,15 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
224 | // ================================================================================== | 216 | // ================================================================================== |
225 | */ | 217 | */ |
226 | 218 | ||
227 | PhysicsScene.Constraints.AddConstraint(constrain); | 219 | m_physicsScene.Constraints.AddConstraint(constrain); |
228 | 220 | ||
229 | // 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 |
230 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 222 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
231 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 223 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
232 | 224 | ||
233 | // tweek the constraint to increase stability | 225 | // tweek the constraint to increase stability |
234 | constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset)); | 226 | constrain.UseFrameOffset(BSParam.LinkConstraintUseFrameOffset); |
235 | constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor), | 227 | constrain.TranslationalLimitMotor(BSParam.LinkConstraintEnableTransMotor, |
236 | BSParam.LinkConstraintTransMotorMaxVel, | 228 | BSParam.LinkConstraintTransMotorMaxVel, |
237 | BSParam.LinkConstraintTransMotorMaxForce); | 229 | BSParam.LinkConstraintTransMotorMaxForce); |
238 | constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); | 230 | constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP); |
@@ -247,7 +239,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
247 | // The root and child bodies are passed in because we need to remove the constraint between | 239 | // The root and child bodies are passed in because we need to remove the constraint between |
248 | // the bodies that were present at unlink time. | 240 | // the bodies that were present at unlink time. |
249 | // Called at taint time! | 241 | // Called at taint time! |
250 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 242 | private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) |
251 | { | 243 | { |
252 | bool ret = false; | 244 | bool ret = false; |
253 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 245 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", |
@@ -256,10 +248,10 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
256 | childPrim.LocalID, childPrim.PhysBody.AddrString); | 248 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
257 | 249 | ||
258 | // 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 |
259 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 251 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
260 | { | 252 | { |
261 | // Make the child refresh its location | 253 | // Make the child refresh its location |
262 | PhysicsScene.PE.PushUpdate(childPrim.PhysBody); | 254 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); |
263 | ret = true; | 255 | ret = true; |
264 | } | 256 | } |
265 | 257 | ||
@@ -269,11 +261,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
269 | // Remove linkage between myself and any possible children I might have. | 261 | // Remove linkage between myself and any possible children I might have. |
270 | // Returns 'true' of any constraints were destroyed. | 262 | // Returns 'true' of any constraints were destroyed. |
271 | // Called at taint time! | 263 | // Called at taint time! |
272 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | 264 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) |
273 | { | 265 | { |
274 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 266 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
275 | 267 | ||
276 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | 268 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); |
277 | } | 269 | } |
278 | 270 | ||
279 | // 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 +281,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
289 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | 281 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", |
290 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); | 282 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); |
291 | 283 | ||
292 | foreach (BSPhysObject child in m_children) | 284 | foreach (BSPrimLinkable child in m_children) |
293 | { | 285 | { |
294 | // A child in the linkset physically shows the mass of the whole linkset. | 286 | // A child in the linkset physically shows the mass of the whole linkset. |
295 | // This allows Bullet to apply enough force on the child to move the whole linkset. | 287 | // This allows Bullet to apply enough force on the child to move the whole linkset. |
@@ -297,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
297 | child.UpdatePhysicalMassProperties(linksetMass, true); | 289 | child.UpdatePhysicalMassProperties(linksetMass, true); |
298 | 290 | ||
299 | BSConstraint constrain; | 291 | BSConstraint constrain; |
300 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) | 292 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
301 | { | 293 | { |
302 | // If constraint doesn't exist yet, create it. | 294 | // If constraint doesn't exist yet, create it. |
303 | constrain = BuildConstraint(LinksetRoot, child); | 295 | constrain = BuildConstraint(LinksetRoot, child); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs index 92d62ff..ee77d6e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -180,11 +180,14 @@ public static class BSMaterials | |||
180 | // Use reflection to set the value in the attribute structure. | 180 | // Use reflection to set the value in the attribute structure. |
181 | private static void SetAttributeValue(int matType, string attribName, float val) | 181 | private static void SetAttributeValue(int matType, string attribName, float val) |
182 | { | 182 | { |
183 | // Get the current attribute values for this material | ||
183 | MaterialAttributes thisAttrib = Attributes[matType]; | 184 | MaterialAttributes thisAttrib = Attributes[matType]; |
185 | // Find the field for the passed attribute name (eg, find field named 'friction') | ||
184 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | 186 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); |
185 | if (fieldInfo != null) | 187 | if (fieldInfo != null) |
186 | { | 188 | { |
187 | fieldInfo.SetValue(thisAttrib, val); | 189 | fieldInfo.SetValue(thisAttrib, val); |
190 | // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. | ||
188 | Attributes[matType] = thisAttrib; | 191 | Attributes[matType] = thisAttrib; |
189 | } | 192 | } |
190 | } | 193 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 817a5f7..ef662b5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -59,22 +59,17 @@ public abstract class BSMotor | |||
59 | { | 59 | { |
60 | if (PhysicsScene != null) | 60 | if (PhysicsScene != null) |
61 | { | 61 | { |
62 | if (PhysicsScene.VehicleLoggingEnabled) | 62 | PhysicsScene.DetailLog(msg, parms); |
63 | { | ||
64 | PhysicsScene.DetailLog(msg, parms); | ||
65 | } | ||
66 | } | 63 | } |
67 | } | 64 | } |
68 | } | 65 | } |
69 | 66 | ||
70 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
71 | // The TargetValue decays in TargetValueDecayTimeScale and | 68 | // The TargetValue decays in TargetValueDecayTimeScale. |
72 | // the CurrentValue will be held back by FrictionTimeScale. | ||
73 | // 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 |
74 | // 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. |
75 | // 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 |
76 | // values (the total difference between current and target minus friction) | 72 | // values to small and eventually zero values. |
77 | // to small and eventually zero values. | ||
78 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. | 73 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. |
79 | 74 | ||
80 | // 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, |
@@ -91,7 +86,6 @@ public class BSVMotor : BSMotor | |||
91 | 86 | ||
92 | public virtual float TimeScale { get; set; } | 87 | public virtual float TimeScale { get; set; } |
93 | public virtual float TargetValueDecayTimeScale { get; set; } | 88 | public virtual float TargetValueDecayTimeScale { get; set; } |
94 | public virtual Vector3 FrictionTimescale { get; set; } | ||
95 | public virtual float Efficiency { get; set; } | 89 | public virtual float Efficiency { get; set; } |
96 | 90 | ||
97 | public virtual float ErrorZeroThreshold { get; set; } | 91 | public virtual float ErrorZeroThreshold { get; set; } |
@@ -100,10 +94,13 @@ public class BSVMotor : BSMotor | |||
100 | public virtual Vector3 CurrentValue { get; protected set; } | 94 | public virtual Vector3 CurrentValue { get; protected set; } |
101 | public virtual Vector3 LastError { get; protected set; } | 95 | public virtual Vector3 LastError { get; protected set; } |
102 | 96 | ||
103 | public virtual bool ErrorIsZero | 97 | public virtual bool ErrorIsZero() |
104 | { get { | 98 | { |
105 | return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold); | 99 | return ErrorIsZero(LastError); |
106 | } | 100 | } |
101 | public virtual bool ErrorIsZero(Vector3 err) | ||
102 | { | ||
103 | return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); | ||
107 | } | 104 | } |
108 | 105 | ||
109 | public BSVMotor(string useName) | 106 | public BSVMotor(string useName) |
@@ -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 | } |
@@ -138,7 +133,8 @@ public class BSVMotor : BSMotor | |||
138 | CurrentValue = TargetValue = Vector3.Zero; | 133 | CurrentValue = TargetValue = Vector3.Zero; |
139 | } | 134 | } |
140 | 135 | ||
141 | // Compute the next step and return the new current value | 136 | // Compute the next step and return the new current value. |
137 | // Returns the correction needed to move 'current' to 'target'. | ||
142 | public virtual Vector3 Step(float timeStep) | 138 | public virtual Vector3 Step(float timeStep) |
143 | { | 139 | { |
144 | if (!Enabled) return TargetValue; | 140 | if (!Enabled) return TargetValue; |
@@ -148,9 +144,10 @@ public class BSVMotor : BSMotor | |||
148 | 144 | ||
149 | Vector3 correction = Vector3.Zero; | 145 | Vector3 correction = Vector3.Zero; |
150 | Vector3 error = TargetValue - CurrentValue; | 146 | Vector3 error = TargetValue - CurrentValue; |
151 | if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | 147 | LastError = error; |
148 | if (!ErrorIsZero(error)) | ||
152 | { | 149 | { |
153 | correction = Step(timeStep, error); | 150 | correction = StepError(timeStep, error); |
154 | 151 | ||
155 | CurrentValue += correction; | 152 | CurrentValue += correction; |
156 | 153 | ||
@@ -163,44 +160,40 @@ public class BSVMotor : BSMotor | |||
163 | TargetValue *= (1f - decayFactor); | 160 | TargetValue *= (1f - decayFactor); |
164 | } | 161 | } |
165 | 162 | ||
166 | // The amount we can correct the error is reduced by the friction | ||
167 | Vector3 frictionFactor = Vector3.Zero; | ||
168 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
169 | { | ||
170 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
171 | // Individual friction components can be 'infinite' so compute each separately. | ||
172 | frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X); | ||
173 | frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y); | ||
174 | frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z); | ||
175 | frictionFactor *= timeStep; | ||
176 | CurrentValue *= (Vector3.One - frictionFactor); | ||
177 | } | ||
178 | |||
179 | 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}", |
180 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | 164 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
181 | timeStep, error, correction); | 165 | timeStep, error, correction); |
182 | 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}", |
183 | BSScene.DetailLogZero, UseName, | 167 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); |
184 | TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor, | ||
185 | TargetValue, CurrentValue); | ||
186 | } | 168 | } |
187 | else | 169 | else |
188 | { | 170 | { |
189 | // Difference between what we have and target is small. Motor is done. | 171 | // Difference between what we have and target is small. Motor is done. |
172 | if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | ||
173 | { | ||
174 | // The target can step down to nearly zero but not get there. If close to zero | ||
175 | // it is really zero. | ||
176 | TargetValue = Vector3.Zero; | ||
177 | } | ||
190 | CurrentValue = TargetValue; | 178 | CurrentValue = TargetValue; |
191 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | 179 | MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", |
192 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | 180 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); |
193 | } | 181 | } |
194 | 182 | ||
195 | return CurrentValue; | 183 | return correction; |
184 | } | ||
185 | // version of step that sets the current value before doing the step | ||
186 | public virtual Vector3 Step(float timeStep, Vector3 current) | ||
187 | { | ||
188 | CurrentValue = current; | ||
189 | return Step(timeStep); | ||
196 | } | 190 | } |
197 | public virtual Vector3 Step(float timeStep, Vector3 error) | 191 | public virtual Vector3 StepError(float timeStep, Vector3 error) |
198 | { | 192 | { |
199 | if (!Enabled) return Vector3.Zero; | 193 | if (!Enabled) return Vector3.Zero; |
200 | 194 | ||
201 | LastError = error; | ||
202 | Vector3 returnCorrection = Vector3.Zero; | 195 | Vector3 returnCorrection = Vector3.Zero; |
203 | if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) | 196 | if (!ErrorIsZero(error)) |
204 | { | 197 | { |
205 | // correction = error / secondsItShouldTakeToCorrect | 198 | // correction = error / secondsItShouldTakeToCorrect |
206 | Vector3 correctionAmount; | 199 | Vector3 correctionAmount; |
@@ -222,9 +215,9 @@ public class BSVMotor : BSMotor | |||
222 | // maximum number of outputs to generate. | 215 | // maximum number of outputs to generate. |
223 | int maxOutput = 50; | 216 | int maxOutput = 50; |
224 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); | 217 | MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); |
225 | 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}", |
226 | BSScene.DetailLogZero, UseName, | 219 | BSScene.DetailLogZero, UseName, |
227 | TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, | 220 | TimeScale, TargetValueDecayTimeScale, Efficiency, |
228 | CurrentValue, TargetValue); | 221 | CurrentValue, TargetValue); |
229 | 222 | ||
230 | LastError = BSMotor.InfiniteVector; | 223 | LastError = BSMotor.InfiniteVector; |
@@ -235,43 +228,141 @@ public class BSVMotor : BSMotor | |||
235 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); | 228 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); |
236 | } | 229 | } |
237 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); | 230 | MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); |
238 | 231 | ||
239 | 232 | ||
240 | } | 233 | } |
241 | 234 | ||
242 | public override string ToString() | 235 | public override string ToString() |
243 | { | 236 | { |
244 | 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}>", |
245 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); | 238 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); |
246 | } | 239 | } |
247 | } | 240 | } |
248 | 241 | ||
242 | // ============================================================================ | ||
243 | // ============================================================================ | ||
249 | public class BSFMotor : BSMotor | 244 | public class BSFMotor : BSMotor |
250 | { | 245 | { |
251 | public float TimeScale { get; set; } | 246 | public virtual float TimeScale { get; set; } |
252 | public float DecayTimeScale { get; set; } | 247 | public virtual float TargetValueDecayTimeScale { get; set; } |
253 | public float Friction { get; set; } | 248 | public virtual float Efficiency { get; set; } |
254 | public float Efficiency { get; set; } | ||
255 | 249 | ||
256 | public float Target { get; private set; } | 250 | public virtual float ErrorZeroThreshold { get; set; } |
257 | public float CurrentValue { get; private set; } | ||
258 | 251 | ||
259 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | 252 | public virtual float TargetValue { get; protected set; } |
253 | public virtual float CurrentValue { get; protected set; } | ||
254 | public virtual float LastError { get; protected set; } | ||
255 | |||
256 | public virtual bool ErrorIsZero() | ||
257 | { | ||
258 | return ErrorIsZero(LastError); | ||
259 | } | ||
260 | public virtual bool ErrorIsZero(float err) | ||
261 | { | ||
262 | return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); | ||
263 | } | ||
264 | |||
265 | public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) | ||
260 | : base(useName) | 266 | : base(useName) |
261 | { | 267 | { |
268 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; | ||
269 | Efficiency = 1f; | ||
270 | CurrentValue = TargetValue = 0f; | ||
271 | ErrorZeroThreshold = 0.01f; | ||
262 | } | 272 | } |
263 | public void SetCurrent(float target) | 273 | public void SetCurrent(float current) |
264 | { | 274 | { |
275 | CurrentValue = current; | ||
265 | } | 276 | } |
266 | public void SetTarget(float target) | 277 | public void SetTarget(float target) |
267 | { | 278 | { |
279 | TargetValue = target; | ||
268 | } | 280 | } |
281 | public override void Zero() | ||
282 | { | ||
283 | base.Zero(); | ||
284 | CurrentValue = TargetValue = 0f; | ||
285 | } | ||
286 | |||
269 | public virtual float Step(float timeStep) | 287 | public virtual float Step(float timeStep) |
270 | { | 288 | { |
271 | return 0f; | 289 | if (!Enabled) return TargetValue; |
290 | |||
291 | float origTarget = TargetValue; // DEBUG | ||
292 | float origCurrVal = CurrentValue; // DEBUG | ||
293 | |||
294 | float correction = 0f; | ||
295 | float error = TargetValue - CurrentValue; | ||
296 | LastError = error; | ||
297 | if (!ErrorIsZero(error)) | ||
298 | { | ||
299 | correction = StepError(timeStep, error); | ||
300 | |||
301 | CurrentValue += correction; | ||
302 | |||
303 | // The desired value reduces to zero which also reduces the difference with current. | ||
304 | // If the decay time is infinite, don't decay at all. | ||
305 | float decayFactor = 0f; | ||
306 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
307 | { | ||
308 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
309 | TargetValue *= (1f - decayFactor); | ||
310 | } | ||
311 | |||
312 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", | ||
313 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
314 | timeStep, error, correction); | ||
315 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", | ||
316 | BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); | ||
317 | } | ||
318 | else | ||
319 | { | ||
320 | // Difference between what we have and target is small. Motor is done. | ||
321 | if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) | ||
322 | { | ||
323 | // The target can step down to nearly zero but not get there. If close to zero | ||
324 | // it is really zero. | ||
325 | TargetValue = 0f; | ||
326 | } | ||
327 | CurrentValue = TargetValue; | ||
328 | MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", | ||
329 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); | ||
330 | } | ||
331 | |||
332 | return CurrentValue; | ||
333 | } | ||
334 | |||
335 | public virtual float StepError(float timeStep, float error) | ||
336 | { | ||
337 | if (!Enabled) return 0f; | ||
338 | |||
339 | float returnCorrection = 0f; | ||
340 | if (!ErrorIsZero(error)) | ||
341 | { | ||
342 | // correction = error / secondsItShouldTakeToCorrect | ||
343 | float correctionAmount; | ||
344 | if (TimeScale == 0f || TimeScale == BSMotor.Infinite) | ||
345 | correctionAmount = error * timeStep; | ||
346 | else | ||
347 | correctionAmount = error / TimeScale * timeStep; | ||
348 | |||
349 | returnCorrection = correctionAmount; | ||
350 | MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", | ||
351 | BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); | ||
352 | } | ||
353 | return returnCorrection; | ||
354 | } | ||
355 | |||
356 | public override string ToString() | ||
357 | { | ||
358 | return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", | ||
359 | UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); | ||
272 | } | 360 | } |
361 | |||
273 | } | 362 | } |
274 | 363 | ||
364 | // ============================================================================ | ||
365 | // ============================================================================ | ||
275 | // Proportional, Integral, Derivitive Motor | 366 | // Proportional, Integral, Derivitive Motor |
276 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. | 367 | // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. |
277 | public class BSPIDVMotor : BSVMotor | 368 | public class BSPIDVMotor : BSVMotor |
@@ -281,6 +372,12 @@ public class BSPIDVMotor : BSVMotor | |||
281 | public Vector3 integralFactor { get; set; } | 372 | public Vector3 integralFactor { get; set; } |
282 | public Vector3 derivFactor { get; set; } | 373 | public Vector3 derivFactor { get; set; } |
283 | 374 | ||
375 | // The factors are vectors for the three dimensions. This is the proportional of each | ||
376 | // that is applied. This could be multiplied through the actual factors but it | ||
377 | // is sometimes easier to manipulate the factors and their mix separately. | ||
378 | // to | ||
379 | public Vector3 FactorMix; | ||
380 | |||
284 | // Arbritrary factor range. | 381 | // Arbritrary factor range. |
285 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. | 382 | // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. |
286 | public float EfficiencyHigh = 0.4f; | 383 | public float EfficiencyHigh = 0.4f; |
@@ -295,6 +392,7 @@ public class BSPIDVMotor : BSVMotor | |||
295 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); | 392 | proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); |
296 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); | 393 | integralFactor = new Vector3(1.00f, 1.00f, 1.00f); |
297 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); | 394 | derivFactor = new Vector3(1.00f, 1.00f, 1.00f); |
395 | FactorMix = new Vector3(0.5f, 0.25f, 0.25f); | ||
298 | RunningIntegration = Vector3.Zero; | 396 | RunningIntegration = Vector3.Zero; |
299 | LastError = Vector3.Zero; | 397 | LastError = Vector3.Zero; |
300 | } | 398 | } |
@@ -310,20 +408,24 @@ public class BSPIDVMotor : BSVMotor | |||
310 | set | 408 | set |
311 | { | 409 | { |
312 | base.Efficiency = Util.Clamp(value, 0f, 1f); | 410 | base.Efficiency = Util.Clamp(value, 0f, 1f); |
411 | |||
313 | // Compute factors based on efficiency. | 412 | // Compute factors based on efficiency. |
314 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. | 413 | // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. |
315 | // If efficiency is low (0f), use a factor value that overcorrects. | 414 | // If efficiency is low (0f), use a factor value that overcorrects. |
316 | // TODO: might want to vary contribution of different factor depending on efficiency. | 415 | // TODO: might want to vary contribution of different factor depending on efficiency. |
317 | float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; | 416 | float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; |
318 | // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; | 417 | // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; |
418 | |||
319 | proportionFactor = new Vector3(factor, factor, factor); | 419 | proportionFactor = new Vector3(factor, factor, factor); |
320 | integralFactor = new Vector3(factor, factor, factor); | 420 | integralFactor = new Vector3(factor, factor, factor); |
321 | derivFactor = new Vector3(factor, factor, factor); | 421 | derivFactor = new Vector3(factor, factor, factor); |
422 | |||
423 | MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); | ||
322 | } | 424 | } |
323 | } | 425 | } |
324 | 426 | ||
325 | // Ignore Current and Target Values and just advance the PID computation on this error. | 427 | // Advance the PID computation on this error. |
326 | public override Vector3 Step(float timeStep, Vector3 error) | 428 | public override Vector3 StepError(float timeStep, Vector3 error) |
327 | { | 429 | { |
328 | if (!Enabled) return Vector3.Zero; | 430 | if (!Enabled) return Vector3.Zero; |
329 | 431 | ||
@@ -331,15 +433,17 @@ public class BSPIDVMotor : BSVMotor | |||
331 | RunningIntegration += error * timeStep; | 433 | RunningIntegration += error * timeStep; |
332 | 434 | ||
333 | // A simple derivitive is the rate of change from the last error. | 435 | // A simple derivitive is the rate of change from the last error. |
334 | Vector3 derivFactor = (error - LastError) * timeStep; | 436 | Vector3 derivitive = (error - LastError) * timeStep; |
335 | LastError = error; | 437 | LastError = error; |
336 | 438 | ||
337 | // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) | 439 | // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) |
338 | Vector3 ret = -( | 440 | Vector3 ret = error * timeStep * proportionFactor * FactorMix.X |
339 | error * proportionFactor | 441 | + RunningIntegration * integralFactor * FactorMix.Y |
340 | + RunningIntegration * integralFactor | 442 | + derivitive * derivFactor * FactorMix.Z |
341 | + derivFactor * derivFactor | 443 | ; |
342 | ); | 444 | |
445 | MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}", | ||
446 | BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret); | ||
343 | 447 | ||
344 | return ret; | 448 | return ret; |
345 | } | 449 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs index 69ac8cd..3ca7e16 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,14 +38,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
37 | { | 38 | { |
38 | public static class BSParam | 39 | public static class BSParam |
39 | { | 40 | { |
41 | private static string LogHeader = "[BULLETSIM PARAMETERS]"; | ||
42 | |||
43 | // Tuning notes: | ||
44 | // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 | ||
45 | // Contact points can be added even if the distance is positive. The constraint solver can deal with | ||
46 | // contacts with positive distances as well as negative (penetration). Contact points are discarded | ||
47 | // if the distance exceeds a certain threshold. | ||
48 | // Bullet has a contact processing threshold and a contact breaking threshold. | ||
49 | // If the distance is larger than the contact breaking threshold, it will be removed after one frame. | ||
50 | // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. | ||
51 | |||
52 | // This is separate/independent from the collision margin. The collision margin increases the object a bit | ||
53 | // to improve collision detection performance and accuracy. | ||
54 | // =================== | ||
55 | // From: | ||
56 | |||
40 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 57 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
41 | public static float MeshLOD { get; private set; } | 58 | public static float MeshLOD { get; private set; } |
59 | public static float MeshCircularLOD { get; private set; } | ||
42 | public static float MeshMegaPrimLOD { get; private set; } | 60 | public static float MeshMegaPrimLOD { get; private set; } |
43 | public static float MeshMegaPrimThreshold { get; private set; } | 61 | public static float MeshMegaPrimThreshold { get; private set; } |
44 | public static float SculptLOD { get; private set; } | 62 | public static float SculptLOD { get; private set; } |
45 | 63 | ||
64 | public static int CrossingFailuresBeforeOutOfBounds { get; private set; } | ||
65 | public static float UpdateVelocityChangeThreshold { get; private set; } | ||
66 | |||
46 | public static float MinimumObjectMass { get; private set; } | 67 | public static float MinimumObjectMass { get; private set; } |
47 | public static float MaximumObjectMass { get; private set; } | 68 | public static float MaximumObjectMass { get; private set; } |
69 | public static float MaxLinearVelocity { get; private set; } | ||
70 | public static float MaxLinearVelocitySquared { get; private set; } | ||
71 | public static float MaxAngularVelocity { get; private set; } | ||
72 | public static float MaxAngularVelocitySquared { get; private set; } | ||
73 | public static float MaxAddForceMagnitude { get; private set; } | ||
74 | public static float MaxAddForceMagnitudeSquared { get; private set; } | ||
75 | public static float DensityScaleFactor { get; private set; } | ||
48 | 76 | ||
49 | public static float LinearDamping { get; private set; } | 77 | public static float LinearDamping { get; private set; } |
50 | public static float AngularDamping { get; private set; } | 78 | public static float AngularDamping { get; private set; } |
@@ -58,13 +86,36 @@ public static class BSParam | |||
58 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 86 | public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed |
59 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 87 | public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes |
60 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | 88 | public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects |
89 | public static bool ShouldRemoveZeroWidthTriangles { get; private set; } | ||
90 | public static bool ShouldUseBulletHACD { get; set; } | ||
91 | public static bool ShouldUseSingleConvexHullForPrims { get; set; } | ||
61 | 92 | ||
62 | public static float TerrainImplementation { get; private set; } | 93 | public static float TerrainImplementation { get; private set; } |
94 | public static int TerrainMeshMagnification { get; private set; } | ||
63 | public static float TerrainFriction { get; private set; } | 95 | public static float TerrainFriction { get; private set; } |
64 | public static float TerrainHitFraction { get; private set; } | 96 | public static float TerrainHitFraction { get; private set; } |
65 | public static float TerrainRestitution { get; private set; } | 97 | public static float TerrainRestitution { get; private set; } |
98 | public static float TerrainContactProcessingThreshold { get; private set; } | ||
66 | public static float TerrainCollisionMargin { get; private set; } | 99 | public static float TerrainCollisionMargin { get; private set; } |
67 | 100 | ||
101 | public static float DefaultFriction { get; private set; } | ||
102 | public static float DefaultDensity { get; private set; } | ||
103 | public static float DefaultRestitution { get; private set; } | ||
104 | public static float CollisionMargin { get; private set; } | ||
105 | public static float Gravity { get; private set; } | ||
106 | |||
107 | // Physics Engine operation | ||
108 | public static float MaxPersistantManifoldPoolSize { get; private set; } | ||
109 | public static float MaxCollisionAlgorithmPoolSize { get; private set; } | ||
110 | public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } | ||
111 | public static bool ShouldForceUpdateAllAabbs { get; private set; } | ||
112 | public static bool ShouldRandomizeSolverOrder { get; private set; } | ||
113 | public static bool ShouldSplitSimulationIslands { get; private set; } | ||
114 | public static bool ShouldEnableFrictionCaching { get; private set; } | ||
115 | public static float NumberOfSolverIterations { get; private set; } | ||
116 | public static bool UseSingleSidedMeshes { get; private set; } | ||
117 | public static float GlobalContactBreakingThreshold { get; private set; } | ||
118 | |||
68 | // Avatar parameters | 119 | // Avatar parameters |
69 | public static float AvatarFriction { get; private set; } | 120 | public static float AvatarFriction { get; private set; } |
70 | public static float AvatarStandingFriction { get; private set; } | 121 | public static float AvatarStandingFriction { get; private set; } |
@@ -75,12 +126,48 @@ public static class BSParam | |||
75 | public static float AvatarCapsuleDepth { get; private set; } | 126 | public static float AvatarCapsuleDepth { get; private set; } |
76 | public static float AvatarCapsuleHeight { get; private set; } | 127 | public static float AvatarCapsuleHeight { get; private set; } |
77 | public static float AvatarContactProcessingThreshold { get; private set; } | 128 | public static float AvatarContactProcessingThreshold { get; private set; } |
78 | 129 | public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } | |
130 | public static float AvatarStepHeight { get; private set; } | ||
131 | public static float AvatarStepApproachFactor { get; private set; } | ||
132 | public static float AvatarStepForceFactor { get; private set; } | ||
133 | public static float AvatarStepUpCorrectionFactor { get; private set; } | ||
134 | public static int AvatarStepSmoothingSteps { get; private set; } | ||
135 | |||
136 | // Vehicle parameters | ||
137 | public static float VehicleMaxLinearVelocity { get; private set; } | ||
138 | public static float VehicleMaxLinearVelocitySquared { get; private set; } | ||
139 | public static float VehicleMaxAngularVelocity { get; private set; } | ||
140 | public static float VehicleMaxAngularVelocitySq { get; private set; } | ||
79 | public static float VehicleAngularDamping { get; private set; } | 141 | public static float VehicleAngularDamping { get; private set; } |
80 | 142 | public static float VehicleFriction { get; private set; } | |
143 | public static float VehicleRestitution { get; private set; } | ||
144 | public static Vector3 VehicleLinearFactor { get; private set; } | ||
145 | public static Vector3 VehicleAngularFactor { get; private set; } | ||
146 | public static float VehicleGroundGravityFudge { get; private set; } | ||
147 | public static float VehicleAngularBankingTimescaleFudge { get; private set; } | ||
148 | public static bool VehicleDebuggingEnable { get; private set; } | ||
149 | |||
150 | // Convex Hulls | ||
151 | public static int CSHullMaxDepthSplit { get; private set; } | ||
152 | public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } | ||
153 | public static float CSHullConcavityThresholdPercent { get; private set; } | ||
154 | public static float CSHullVolumeConservationThresholdPercent { get; private set; } | ||
155 | public static int CSHullMaxVertices { get; private set; } | ||
156 | public static float CSHullMaxSkinWidth { get; private set; } | ||
157 | public static float BHullMaxVerticesPerHull { get; private set; } // 100 | ||
158 | public static float BHullMinClusters { get; private set; } // 2 | ||
159 | public static float BHullCompacityWeight { get; private set; } // 0.1 | ||
160 | public static float BHullVolumeWeight { get; private set; } // 0.0 | ||
161 | public static float BHullConcavity { get; private set; } // 100 | ||
162 | public static bool BHullAddExtraDistPoints { get; private set; } // false | ||
163 | public static bool BHullAddNeighboursDistPoints { get; private set; } // false | ||
164 | public static bool BHullAddFacesPoints { get; private set; } // false | ||
165 | public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false | ||
166 | |||
167 | // Linkset implementation parameters | ||
81 | public static float LinksetImplementation { get; private set; } | 168 | public static float LinksetImplementation { get; private set; } |
82 | public static float LinkConstraintUseFrameOffset { get; private set; } | 169 | public static bool LinkConstraintUseFrameOffset { get; private set; } |
83 | public static float LinkConstraintEnableTransMotor { get; private set; } | 170 | public static bool LinkConstraintEnableTransMotor { get; private set; } |
84 | public static float LinkConstraintTransMotorMaxVel { get; private set; } | 171 | public static float LinkConstraintTransMotorMaxVel { get; private set; } |
85 | public static float LinkConstraintTransMotorMaxForce { get; private set; } | 172 | public static float LinkConstraintTransMotorMaxForce { get; private set; } |
86 | public static float LinkConstraintERP { get; private set; } | 173 | public static float LinkConstraintERP { get; private set; } |
@@ -90,51 +177,152 @@ public static class BSParam | |||
90 | public static float PID_D { get; private set; } // derivative | 177 | public static float PID_D { get; private set; } // derivative |
91 | public static float PID_P { get; private set; } // proportional | 178 | public static float PID_P { get; private set; } // proportional |
92 | 179 | ||
93 | // Various constants that come from that other virtual world that shall not be named | 180 | // Various constants that come from that other virtual world that shall not be named. |
94 | public const float MinGravityZ = -1f; | 181 | public const float MinGravityZ = -1f; |
95 | public const float MaxGravityZ = 28f; | 182 | public const float MaxGravityZ = 28f; |
96 | public const float MinFriction = 0f; | 183 | public const float MinFriction = 0f; |
97 | public const float MaxFriction = 255f; | 184 | public const float MaxFriction = 255f; |
98 | public const float MinDensity = 0f; | 185 | public const float MinDensity = 0.01f; |
99 | public const float MaxDensity = 22587f; | 186 | public const float MaxDensity = 22587f; |
100 | public const float MinRestitution = 0f; | 187 | public const float MinRestitution = 0f; |
101 | public const float MaxRestitution = 1f; | 188 | public const float MaxRestitution = 1f; |
102 | public const float MaxAddForceMagnitude = 20000f; | ||
103 | 189 | ||
104 | // =========================================================================== | 190 | // ===================================================================================== |
105 | public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | 191 | // ===================================================================================== |
106 | public delegate float ParamGet(BSScene scene); | ||
107 | public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | ||
108 | public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
109 | 192 | ||
110 | public struct ParameterDefn | 193 | // Base parameter definition that gets and sets parameter values via a string |
194 | public abstract class ParameterDefnBase | ||
111 | { | 195 | { |
112 | public string name; // string name of the parameter | 196 | public string name; // string name of the parameter |
113 | public string desc; // a short description of what the parameter means | 197 | public string desc; // a short description of what the parameter means |
114 | public float defaultValue; // default value if not specified anywhere else | 198 | public ParameterDefnBase(string pName, string pDesc) |
115 | public ParamUser userParam; // get the value from the configuration file | 199 | { |
116 | public ParamGet getter; // return the current value stored for this parameter | 200 | name = pName; |
117 | public ParamSet setter; // set the current value for this parameter | 201 | desc = pDesc; |
118 | public SetOnObject onObject; // set the value on an object in the physical domain | 202 | } |
119 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | 203 | // Set the parameter value to the default |
204 | public abstract void AssignDefault(BSScene s); | ||
205 | // Get the value as a string | ||
206 | public abstract string GetValue(BSScene s); | ||
207 | // Set the value to this string value | ||
208 | public abstract void SetValue(BSScene s, string valAsString); | ||
209 | // set the value on a particular object (usually sets in physics engine) | ||
210 | public abstract void SetOnObject(BSScene s, BSPhysObject obj); | ||
211 | public abstract bool HasSetOnObject { get; } | ||
212 | } | ||
213 | |||
214 | // Specific parameter definition for a parameter of a specific type. | ||
215 | public delegate T PGetValue<T>(BSScene s); | ||
216 | public delegate void PSetValue<T>(BSScene s, T val); | ||
217 | public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj); | ||
218 | public sealed class ParameterDefn<T> : ParameterDefnBase | ||
219 | { | ||
220 | private T defaultValue; | ||
221 | private PSetValue<T> setter; | ||
222 | private PGetValue<T> getter; | ||
223 | private PSetOnObject<T> objectSet; | ||
224 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter) | ||
225 | : base(pName, pDesc) | ||
226 | { | ||
227 | defaultValue = pDefault; | ||
228 | setter = pSetter; | ||
229 | getter = pGetter; | ||
230 | objectSet = null; | ||
231 | } | ||
232 | public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter) | ||
233 | : base(pName, pDesc) | ||
120 | { | 234 | { |
121 | name = n; | 235 | defaultValue = pDefault; |
122 | desc = d; | 236 | setter = pSetter; |
123 | defaultValue = v; | 237 | getter = pGetter; |
124 | userParam = u; | 238 | objectSet = pObjSetter; |
125 | getter = g; | ||
126 | setter = s; | ||
127 | onObject = null; | ||
128 | } | 239 | } |
129 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | 240 | // Simple parameter variable where property name is the same as the INI file name |
241 | // and the value is only a simple get and set. | ||
242 | public ParameterDefn(string pName, string pDesc, T pDefault) | ||
243 | : base(pName, pDesc) | ||
130 | { | 244 | { |
131 | name = n; | 245 | defaultValue = pDefault; |
132 | desc = d; | 246 | setter = (s, v) => { SetValueByName(s, name, v); }; |
133 | defaultValue = v; | 247 | getter = (s) => { return GetValueByName(s, name); }; |
134 | userParam = u; | 248 | objectSet = null; |
135 | getter = g; | 249 | } |
136 | setter = s; | 250 | // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. |
137 | onObject = o; | 251 | private void SetValueByName(BSScene s, string pName, T val) |
252 | { | ||
253 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
254 | if (prop == null) | ||
255 | { | ||
256 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
257 | s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | prop.SetValue(null, val, null); | ||
262 | } | ||
263 | } | ||
264 | // Use reflection to find the property named 'pName' in BSParam and return the value in same. | ||
265 | private T GetValueByName(BSScene s, string pName) | ||
266 | { | ||
267 | PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); | ||
268 | if (prop == null) | ||
269 | { | ||
270 | // This should only be output when someone adds a new INI parameter and misspells the name. | ||
271 | s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); | ||
272 | } | ||
273 | return (T)prop.GetValue(null, null); | ||
274 | } | ||
275 | public override void AssignDefault(BSScene s) | ||
276 | { | ||
277 | setter(s, defaultValue); | ||
278 | } | ||
279 | public override string GetValue(BSScene s) | ||
280 | { | ||
281 | return getter(s).ToString(); | ||
282 | } | ||
283 | public override void SetValue(BSScene s, string valAsString) | ||
284 | { | ||
285 | // Get the generic type of the setter | ||
286 | Type genericType = setter.GetType().GetGenericArguments()[0]; | ||
287 | // Find the 'Parse' method on that type | ||
288 | System.Reflection.MethodInfo parser = null; | ||
289 | try | ||
290 | { | ||
291 | parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); | ||
292 | } | ||
293 | catch (Exception e) | ||
294 | { | ||
295 | s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); | ||
296 | parser = null; | ||
297 | } | ||
298 | if (parser != null) | ||
299 | { | ||
300 | // Parse the input string | ||
301 | try | ||
302 | { | ||
303 | T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); | ||
304 | // Store the parsed value | ||
305 | setter(s, setValue); | ||
306 | // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); | ||
307 | } | ||
308 | catch | ||
309 | { | ||
310 | s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); | ||
311 | } | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); | ||
316 | } | ||
317 | } | ||
318 | public override bool HasSetOnObject | ||
319 | { | ||
320 | get { return objectSet != null; } | ||
321 | } | ||
322 | public override void SetOnObject(BSScene s, BSPhysObject obj) | ||
323 | { | ||
324 | if (objectSet != null) | ||
325 | objectSet(s, obj); | ||
138 | } | 326 | } |
139 | } | 327 | } |
140 | 328 | ||
@@ -144,359 +332,356 @@ public static class BSParam | |||
144 | // location somewhere in the program and make an entry in this table with the | 332 | // location somewhere in the program and make an entry in this table with the |
145 | // getters and setters. | 333 | // getters and setters. |
146 | // It is easiest to find an existing definition and copy it. | 334 | // It is easiest to find an existing definition and copy it. |
147 | // Parameter values are floats. Booleans are converted to a floating value. | ||
148 | // | 335 | // |
149 | // A ParameterDefn() takes the following parameters: | 336 | // A ParameterDefn<T>() takes the following parameters: |
150 | // -- the text name of the parameter. This is used for console input and ini file. | 337 | // -- the text name of the parameter. This is used for console input and ini file. |
151 | // -- a short text description of the parameter. This shows up in the console listing. | 338 | // -- a short text description of the parameter. This shows up in the console listing. |
152 | // -- a default value (float) | 339 | // -- a default value |
153 | // -- a delegate for fetching the parameter from the ini file. | 340 | // -- a delegate for getting the value |
154 | // Should handle fetching the right type from the ini file and converting it. | 341 | // -- a delegate for setting the value |
155 | // -- a delegate for getting the value as a float | ||
156 | // -- a delegate for setting the value from a float | ||
157 | // -- an optional delegate to update the value in the world. Most often used to | 342 | // -- an optional delegate to update the value in the world. Most often used to |
158 | // push the new value to an in-world object. | 343 | // push the new value to an in-world object. |
159 | // | 344 | // |
160 | // The single letter parameters for the delegates are: | 345 | // The single letter parameters for the delegates are: |
161 | // s = BSScene | 346 | // s = BSScene |
162 | // o = BSPhysObject | 347 | // o = BSPhysObject |
163 | // p = string parameter name | 348 | // v = value (appropriate type) |
164 | // l = localID of referenced object | 349 | private static ParameterDefnBase[] ParameterDefinitions = |
165 | // v = value (float) | ||
166 | // cf = parameter configuration class (for fetching values from ini file) | ||
167 | private static ParameterDefn[] ParameterDefinitions = | ||
168 | { | 350 | { |
169 | new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", | 351 | new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties", |
170 | ConfigurationParameters.numericTrue, | 352 | true, |
171 | (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | 353 | (s) => { return ShouldMeshSculptedPrim; }, |
172 | (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); }, | 354 | (s,v) => { ShouldMeshSculptedPrim = v; } ), |
173 | (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ), | 355 | new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", |
174 | new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", | 356 | false, |
175 | ConfigurationParameters.numericFalse, | 357 | (s) => { return ShouldForceSimplePrimMeshing; }, |
176 | (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | 358 | (s,v) => { ShouldForceSimplePrimMeshing = v; } ), |
177 | (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); }, | 359 | new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", |
178 | (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ), | 360 | true, |
179 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | 361 | (s) => { return ShouldUseHullsForPhysicalObjects; }, |
180 | ConfigurationParameters.numericTrue, | 362 | (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), |
181 | (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); }, | 363 | new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", |
182 | (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); }, | 364 | true ), |
183 | (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ), | 365 | new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", |
184 | 366 | false ), | |
185 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 367 | new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", |
186 | 8f, | 368 | true ), |
187 | (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); }, | 369 | |
370 | new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", | ||
371 | 5 ), | ||
372 | new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", | ||
373 | 0.1f ), | ||
374 | |||
375 | new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | ||
376 | 32f, | ||
188 | (s) => { return MeshLOD; }, | 377 | (s) => { return MeshLOD; }, |
189 | (s,p,l,v) => { MeshLOD = v; } ), | 378 | (s,v) => { MeshLOD = v; } ), |
190 | new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", | 379 | new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", |
191 | 16f, | 380 | 32f, |
192 | (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); }, | 381 | (s) => { return MeshCircularLOD; }, |
193 | (s) => { return MeshMegaPrimLOD; }, | 382 | (s,v) => { MeshCircularLOD = v; } ), |
194 | (s,p,l,v) => { MeshMegaPrimLOD = v; } ), | 383 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", |
195 | new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", | ||
196 | 10f, | 384 | 10f, |
197 | (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); }, | ||
198 | (s) => { return MeshMegaPrimThreshold; }, | 385 | (s) => { return MeshMegaPrimThreshold; }, |
199 | (s,p,l,v) => { MeshMegaPrimThreshold = v; } ), | 386 | (s,v) => { MeshMegaPrimThreshold = v; } ), |
200 | new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | 387 | new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", |
388 | 32f, | ||
389 | (s) => { return MeshMegaPrimLOD; }, | ||
390 | (s,v) => { MeshMegaPrimLOD = v; } ), | ||
391 | new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", | ||
201 | 32f, | 392 | 32f, |
202 | (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); }, | ||
203 | (s) => { return SculptLOD; }, | 393 | (s) => { return SculptLOD; }, |
204 | (s,p,l,v) => { SculptLOD = v; } ), | 394 | (s,v) => { SculptLOD = v; } ), |
205 | 395 | ||
206 | new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", | 396 | new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps", |
207 | 10f, | 397 | 10, |
208 | (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); }, | 398 | (s) => { return s.m_maxSubSteps; }, |
209 | (s) => { return (float)s.m_maxSubSteps; }, | 399 | (s,v) => { s.m_maxSubSteps = (int)v; } ), |
210 | (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ), | 400 | new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", |
211 | new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", | ||
212 | 1f / 60f, | 401 | 1f / 60f, |
213 | (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); }, | 402 | (s) => { return s.m_fixedTimeStep; }, |
214 | (s) => { return (float)s.m_fixedTimeStep; }, | 403 | (s,v) => { s.m_fixedTimeStep = v; } ), |
215 | (s,p,l,v) => { s.m_fixedTimeStep = v; } ), | 404 | new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim", |
216 | new ParameterDefn("NominalFrameRate", "The base frame rate we claim", | ||
217 | 55f, | 405 | 55f, |
218 | (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); }, | 406 | (s) => { return s.NominalFrameRate; }, |
219 | (s) => { return (float)s.NominalFrameRate; }, | 407 | (s,v) => { s.NominalFrameRate = (int)v; } ), |
220 | (s,p,l,v) => { s.NominalFrameRate = (int)v; } ), | 408 | new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", |
221 | new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", | 409 | 2048, |
222 | 2048f, | 410 | (s) => { return s.m_maxCollisionsPerFrame; }, |
223 | (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); }, | 411 | (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), |
224 | (s) => { return (float)s.m_maxCollisionsPerFrame; }, | 412 | new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame", |
225 | (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), | 413 | 8000, |
226 | new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", | 414 | (s) => { return s.m_maxUpdatesPerFrame; }, |
227 | 8000f, | 415 | (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |
228 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | 416 | |
229 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | 417 | new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)", |
230 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | ||
231 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
232 | 500f, | ||
233 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
234 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
235 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
236 | new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", | ||
237 | 0.0001f, | 418 | 0.0001f, |
238 | (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); }, | 419 | (s) => { return MinimumObjectMass; }, |
239 | (s) => { return (float)MinimumObjectMass; }, | 420 | (s,v) => { MinimumObjectMass = v; } ), |
240 | (s,p,l,v) => { MinimumObjectMass = v; } ), | 421 | new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)", |
241 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | ||
242 | 10000.01f, | 422 | 10000.01f, |
243 | (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); }, | 423 | (s) => { return MaximumObjectMass; }, |
244 | (s) => { return (float)MaximumObjectMass; }, | 424 | (s,v) => { MaximumObjectMass = v; } ), |
245 | (s,p,l,v) => { MaximumObjectMass = v; } ), | 425 | new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", |
246 | 426 | 1000.0f, | |
247 | new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", | 427 | (s) => { return MaxLinearVelocity; }, |
248 | 2200f, | 428 | (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), |
249 | (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); }, | 429 | new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", |
250 | (s) => { return (float)PID_D; }, | 430 | 1000.0f, |
251 | (s,p,l,v) => { PID_D = v; } ), | 431 | (s) => { return MaxAngularVelocity; }, |
252 | new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", | 432 | (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), |
253 | 900f, | 433 | // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject |
254 | (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); }, | 434 | new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", |
255 | (s) => { return (float)PID_P; }, | 435 | 20000.0f, |
256 | (s,p,l,v) => { PID_P = v; } ), | 436 | (s) => { return MaxAddForceMagnitude; }, |
257 | 437 | (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), | |
258 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | 438 | // Density is passed around as 100kg/m3. This scales that to 1kg/m3. |
439 | new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", | ||
440 | 0.01f ), | ||
441 | |||
442 | new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", | ||
443 | 2200f ), | ||
444 | new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing", | ||
445 | 900f ), | ||
446 | |||
447 | new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects", | ||
259 | 0.2f, | 448 | 0.2f, |
260 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); }, | 449 | (s) => { return DefaultFriction; }, |
261 | (s) => { return s.UnmanagedParams[0].defaultFriction; }, | 450 | (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), |
262 | (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ), | 451 | new ParameterDefn<float>("DefaultDensity", "Density for new objects" , |
263 | new ParameterDefn("DefaultDensity", "Density for new objects" , | ||
264 | 10.000006836f, // Aluminum g/cm3 | 452 | 10.000006836f, // Aluminum g/cm3 |
265 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); }, | 453 | (s) => { return DefaultDensity; }, |
266 | (s) => { return s.UnmanagedParams[0].defaultDensity; }, | 454 | (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), |
267 | (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ), | 455 | new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , |
268 | new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , | ||
269 | 0f, | 456 | 0f, |
270 | (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); }, | 457 | (s) => { return DefaultRestitution; }, |
271 | (s) => { return s.UnmanagedParams[0].defaultRestitution; }, | 458 | (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), |
272 | (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ), | 459 | new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", |
273 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | ||
274 | 0.04f, | 460 | 0.04f, |
275 | (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); }, | 461 | (s) => { return CollisionMargin; }, |
276 | (s) => { return s.UnmanagedParams[0].collisionMargin; }, | 462 | (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), |
277 | (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ), | 463 | new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)", |
278 | new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", | ||
279 | -9.80665f, | 464 | -9.80665f, |
280 | (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); }, | 465 | (s) => { return Gravity; }, |
281 | (s) => { return s.UnmanagedParams[0].gravity; }, | 466 | (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, |
282 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); }, | 467 | (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), |
283 | (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ), | ||
284 | 468 | ||
285 | 469 | ||
286 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | 470 | new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |
287 | 0f, | 471 | 0f, |
288 | (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); }, | ||
289 | (s) => { return LinearDamping; }, | 472 | (s) => { return LinearDamping; }, |
290 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); }, | 473 | (s,v) => { LinearDamping = v; }, |
291 | (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ), | 474 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), |
292 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 475 | new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
293 | 0f, | 476 | 0f, |
294 | (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); }, | ||
295 | (s) => { return AngularDamping; }, | 477 | (s) => { return AngularDamping; }, |
296 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); }, | 478 | (s,v) => { AngularDamping = v; }, |
297 | (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ), | 479 | (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), |
298 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 480 | new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static", |
299 | 0.2f, | 481 | 0.2f, |
300 | (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); }, | ||
301 | (s) => { return DeactivationTime; }, | 482 | (s) => { return DeactivationTime; }, |
302 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); }, | 483 | (s,v) => { DeactivationTime = v; }, |
303 | (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ), | 484 | (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), |
304 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 485 | new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
305 | 0.8f, | 486 | 0.8f, |
306 | (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); }, | ||
307 | (s) => { return LinearSleepingThreshold; }, | 487 | (s) => { return LinearSleepingThreshold; }, |
308 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); }, | 488 | (s,v) => { LinearSleepingThreshold = v;}, |
309 | (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), | 489 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), |
310 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 490 | new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
311 | 1.0f, | 491 | 1.0f, |
312 | (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); }, | ||
313 | (s) => { return AngularSleepingThreshold; }, | 492 | (s) => { return AngularSleepingThreshold; }, |
314 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); }, | 493 | (s,v) => { AngularSleepingThreshold = v;}, |
315 | (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ), | 494 | (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), |
316 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 495 | new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
317 | 0f, // set to zero to disable | 496 | 0.0f, // set to zero to disable |
318 | (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); }, | ||
319 | (s) => { return CcdMotionThreshold; }, | 497 | (s) => { return CcdMotionThreshold; }, |
320 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); }, | 498 | (s,v) => { CcdMotionThreshold = v;}, |
321 | (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ), | 499 | (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), |
322 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 500 | new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
323 | 0f, | 501 | 0.2f, |
324 | (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); }, | ||
325 | (s) => { return CcdSweptSphereRadius; }, | 502 | (s) => { return CcdSweptSphereRadius; }, |
326 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); }, | 503 | (s,v) => { CcdSweptSphereRadius = v;}, |
327 | (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ), | 504 | (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), |
328 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 505 | new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , |
329 | 0.1f, | 506 | 0.0f, |
330 | (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); }, | ||
331 | (s) => { return ContactProcessingThreshold; }, | 507 | (s) => { return ContactProcessingThreshold; }, |
332 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); }, | 508 | (s,v) => { ContactProcessingThreshold = v;}, |
333 | (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ), | 509 | (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), |
334 | 510 | ||
335 | new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", | 511 | new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", |
336 | (float)BSTerrainPhys.TerrainImplementation.Mesh, | 512 | (float)BSTerrainPhys.TerrainImplementation.Mesh ), |
337 | (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); }, | 513 | new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , |
338 | (s) => { return TerrainImplementation; }, | 514 | 2 ), |
339 | (s,p,l,v) => { TerrainImplementation = v; } ), | 515 | new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" , |
340 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 516 | 0.3f ), |
341 | 0.3f, | 517 | new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" , |
342 | (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); }, | 518 | 0.8f ), |
343 | (s) => { return TerrainFriction; }, | 519 | new ParameterDefn<float>("TerrainRestitution", "Bouncyness" , |
344 | (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ), | 520 | 0f ), |
345 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | 521 | new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , |
346 | 0.8f, | 522 | 0.0f ), |
347 | (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); }, | 523 | new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" , |
348 | (s) => { return TerrainHitFraction; }, | 524 | 0.08f ), |
349 | (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ), | 525 | |
350 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | 526 | new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
527 | 0.2f ), | ||
528 | new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
529 | 0.95f ), | ||
530 | new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | ||
531 | 1.3f ), | ||
532 | new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
533 | 3.5f) , | ||
534 | new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
535 | 0f ), | ||
536 | new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | ||
537 | 0.6f ) , | ||
538 | new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | ||
539 | 0.45f ), | ||
540 | new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar", | ||
541 | 1.5f ), | ||
542 | new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | ||
543 | 0.1f ), | ||
544 | new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", | ||
545 | 1.0f ), | ||
546 | new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction", | ||
547 | 0.6f ) , | ||
548 | new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", | ||
549 | 0.6f ), | ||
550 | new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", | ||
551 | 1.0f ), | ||
552 | new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", | ||
553 | 1.0f ), | ||
554 | new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", | ||
555 | 2 ), | ||
556 | |||
557 | new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", | ||
558 | 1000.0f, | ||
559 | (s) => { return (float)VehicleMaxLinearVelocity; }, | ||
560 | (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), | ||
561 | new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", | ||
562 | 12.0f, | ||
563 | (s) => { return (float)VehicleMaxAngularVelocity; }, | ||
564 | (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), | ||
565 | new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
566 | 0.0f ), | ||
567 | new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
568 | new Vector3(1f, 1f, 1f) ), | ||
569 | new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", | ||
570 | new Vector3(1f, 1f, 1f) ), | ||
571 | new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", | ||
572 | 0.0f ), | ||
573 | new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", | ||
574 | 0.0f ), | ||
575 | new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", | ||
576 | 0.2f ), | ||
577 | new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", | ||
578 | 60.0f ), | ||
579 | new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging", | ||
580 | false ), | ||
581 | |||
582 | new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | ||
351 | 0f, | 583 | 0f, |
352 | (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); }, | 584 | (s) => { return MaxPersistantManifoldPoolSize; }, |
353 | (s) => { return TerrainRestitution; }, | 585 | (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), |
354 | (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ), | 586 | new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", |
355 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
356 | 0.04f, | ||
357 | (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); }, | ||
358 | (s) => { return TerrainCollisionMargin; }, | ||
359 | (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
360 | |||
361 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | ||
362 | 0.2f, | ||
363 | (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); }, | ||
364 | (s) => { return AvatarFriction; }, | ||
365 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ), | ||
366 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
367 | 10.0f, | ||
368 | (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); }, | ||
369 | (s) => { return AvatarStandingFriction; }, | ||
370 | (s,p,l,v) => { AvatarStandingFriction = v; } ), | ||
371 | new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", | ||
372 | 1.3f, | ||
373 | (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); }, | ||
374 | (s) => { return AvatarAlwaysRunFactor; }, | ||
375 | (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ), | ||
376 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | ||
377 | 3.5f, | ||
378 | (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); }, | ||
379 | (s) => { return AvatarDensity; }, | ||
380 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ), | ||
381 | new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", | ||
382 | 0f, | 587 | 0f, |
383 | (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); }, | 588 | (s) => { return MaxCollisionAlgorithmPoolSize; }, |
384 | (s) => { return AvatarRestitution; }, | 589 | (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), |
385 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ), | 590 | new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", |
386 | new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", | 591 | false, |
387 | 0.6f, | 592 | (s) => { return ShouldDisableContactPoolDynamicAllocation; }, |
388 | (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); }, | 593 | (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; |
389 | (s) => { return AvatarCapsuleWidth; }, | 594 | s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), |
390 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ), | 595 | new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", |
391 | new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", | 596 | false, |
392 | 0.45f, | 597 | (s) => { return ShouldForceUpdateAllAabbs; }, |
393 | (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); }, | 598 | (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), |
394 | (s) => { return AvatarCapsuleDepth; }, | 599 | new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", |
395 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ), | 600 | true, |
396 | new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", | 601 | (s) => { return ShouldRandomizeSolverOrder; }, |
397 | 1.5f, | 602 | (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), |
398 | (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); }, | 603 | new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", |
399 | (s) => { return AvatarCapsuleHeight; }, | 604 | true, |
400 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ), | 605 | (s) => { return ShouldSplitSimulationIslands; }, |
401 | new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", | 606 | (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), |
402 | 0.1f, | 607 | new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching", |
403 | (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); }, | 608 | true, |
404 | (s) => { return AvatarContactProcessingThreshold; }, | 609 | (s) => { return ShouldEnableFrictionCaching; }, |
405 | (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ), | 610 | (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), |
406 | 611 | new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | |
407 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | 612 | 0f, // zero says use Bullet default |
408 | 0.95f, | 613 | (s) => { return NumberOfSolverIterations; }, |
409 | (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); }, | 614 | (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), |
410 | (s) => { return VehicleAngularDamping; }, | 615 | new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", |
411 | (s,p,l,v) => { VehicleAngularDamping = v; } ), | 616 | true, |
412 | 617 | (s) => { return UseSingleSidedMeshes; }, | |
413 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 618 | (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), |
619 | new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", | ||
414 | 0f, | 620 | 0f, |
415 | (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, | 621 | (s) => { return GlobalContactBreakingThreshold; }, |
416 | (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; }, | 622 | (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), |
417 | (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), | 623 | |
418 | new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", | 624 | new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", |
625 | 7 ), | ||
626 | new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", | ||
627 | 2 ), | ||
628 | new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", | ||
629 | 5f ), | ||
630 | new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", | ||
631 | 5f ), | ||
632 | new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", | ||
633 | 32 ), | ||
634 | new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", | ||
635 | 0f ), | ||
636 | |||
637 | new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", | ||
638 | 100f ), | ||
639 | new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", | ||
640 | 2f ), | ||
641 | new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", | ||
642 | 0.1f ), | ||
643 | new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", | ||
644 | 0f ), | ||
645 | new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", | ||
646 | 100f ), | ||
647 | new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", | ||
648 | false ), | ||
649 | new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", | ||
650 | false ), | ||
651 | new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", | ||
652 | false ), | ||
653 | new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", | ||
654 | false ), | ||
655 | |||
656 | new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
657 | (float)BSLinkset.LinksetImplementation.Compound ), | ||
658 | new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
659 | false ), | ||
660 | new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
661 | true ), | ||
662 | new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
663 | 5.0f ), | ||
664 | new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
665 | 0.1f ), | ||
666 | new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
667 | 0.1f ), | ||
668 | new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
669 | 0.1f ), | ||
670 | new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
671 | 40 ), | ||
672 | |||
673 | new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | ||
674 | 0, | ||
675 | (s) => { return s.PhysicsMetricDumpFrames; }, | ||
676 | (s,v) => { s.PhysicsMetricDumpFrames = v; } ), | ||
677 | new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", | ||
419 | 0f, | 678 | 0f, |
420 | (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, | 679 | (s) => { return 0f; }, |
421 | (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; }, | 680 | (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), |
422 | (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), | 681 | new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver", |
423 | new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", | ||
424 | ConfigurationParameters.numericFalse, | ||
425 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
426 | (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; }, | ||
427 | (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ), | ||
428 | new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", | ||
429 | ConfigurationParameters.numericFalse, | ||
430 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
431 | (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; }, | ||
432 | (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ), | ||
433 | new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", | ||
434 | ConfigurationParameters.numericTrue, | ||
435 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
436 | (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; }, | ||
437 | (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ), | ||
438 | new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", | ||
439 | ConfigurationParameters.numericTrue, | ||
440 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
441 | (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; }, | ||
442 | (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ), | ||
443 | new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", | ||
444 | ConfigurationParameters.numericFalse, | ||
445 | (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
446 | (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; }, | ||
447 | (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ), | ||
448 | new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", | ||
449 | 0f, // zero says use Bullet default | ||
450 | (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); }, | ||
451 | (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; }, | ||
452 | (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ), | ||
453 | |||
454 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
455 | (float)BSLinkset.LinksetImplementation.Compound, | ||
456 | (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); }, | ||
457 | (s) => { return LinksetImplementation; }, | ||
458 | (s,p,l,v) => { LinksetImplementation = v; } ), | ||
459 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", | ||
460 | ConfigurationParameters.numericFalse, | ||
461 | (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
462 | (s) => { return LinkConstraintUseFrameOffset; }, | ||
463 | (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ), | ||
464 | new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", | ||
465 | ConfigurationParameters.numericTrue, | ||
466 | (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); }, | ||
467 | (s) => { return LinkConstraintEnableTransMotor; }, | ||
468 | (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ), | ||
469 | new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", | ||
470 | 5.0f, | ||
471 | (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); }, | ||
472 | (s) => { return LinkConstraintTransMotorMaxVel; }, | ||
473 | (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ), | ||
474 | new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", | ||
475 | 0.1f, | ||
476 | (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, | ||
477 | (s) => { return LinkConstraintTransMotorMaxForce; }, | ||
478 | (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ), | ||
479 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | ||
480 | 0.1f, | ||
481 | (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); }, | ||
482 | (s) => { return LinkConstraintCFM; }, | ||
483 | (s,p,l,v) => { LinkConstraintCFM = v; } ), | ||
484 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | ||
485 | 0.1f, | ||
486 | (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); }, | ||
487 | (s) => { return LinkConstraintERP; }, | ||
488 | (s,p,l,v) => { LinkConstraintERP = v; } ), | ||
489 | new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", | ||
490 | 40, | ||
491 | (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); }, | ||
492 | (s) => { return LinkConstraintSolverIterations; }, | ||
493 | (s,p,l,v) => { LinkConstraintSolverIterations = v; } ), | ||
494 | |||
495 | new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", | ||
496 | 0f, | 682 | 0f, |
497 | (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); }, | 683 | (s) => { return 0f; }, |
498 | (s) => { return (float)s.PhysicsMetricDumpFrames; }, | 684 | (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), |
499 | (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ), | ||
500 | }; | 685 | }; |
501 | 686 | ||
502 | // Convert a boolean to our numeric true and false values | 687 | // Convert a boolean to our numeric true and false values |
@@ -515,13 +700,13 @@ public static class BSParam | |||
515 | // ParameterDefn structure. | 700 | // ParameterDefn structure. |
516 | // Case does not matter as names are compared after converting to lower case. | 701 | // Case does not matter as names are compared after converting to lower case. |
517 | // Returns 'false' if the parameter is not found. | 702 | // Returns 'false' if the parameter is not found. |
518 | internal static bool TryGetParameter(string paramName, out ParameterDefn defn) | 703 | internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) |
519 | { | 704 | { |
520 | bool ret = false; | 705 | bool ret = false; |
521 | ParameterDefn foundDefn = new ParameterDefn(); | 706 | ParameterDefnBase foundDefn = null; |
522 | string pName = paramName.ToLower(); | 707 | string pName = paramName.ToLower(); |
523 | 708 | ||
524 | foreach (ParameterDefn parm in ParameterDefinitions) | 709 | foreach (ParameterDefnBase parm in ParameterDefinitions) |
525 | { | 710 | { |
526 | if (pName == parm.name.ToLower()) | 711 | if (pName == parm.name.ToLower()) |
527 | { | 712 | { |
@@ -537,18 +722,18 @@ public static class BSParam | |||
537 | // Pass through the settable parameters and set the default values | 722 | // Pass through the settable parameters and set the default values |
538 | internal static void SetParameterDefaultValues(BSScene physicsScene) | 723 | internal static void SetParameterDefaultValues(BSScene physicsScene) |
539 | { | 724 | { |
540 | foreach (ParameterDefn parm in ParameterDefinitions) | 725 | foreach (ParameterDefnBase parm in ParameterDefinitions) |
541 | { | 726 | { |
542 | parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue); | 727 | parm.AssignDefault(physicsScene); |
543 | } | 728 | } |
544 | } | 729 | } |
545 | 730 | ||
546 | // Get user set values out of the ini file. | 731 | // Get user set values out of the ini file. |
547 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) | 732 | internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) |
548 | { | 733 | { |
549 | foreach (ParameterDefn parm in ParameterDefinitions) | 734 | foreach (ParameterDefnBase parm in ParameterDefinitions) |
550 | { | 735 | { |
551 | parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue); | 736 | parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); |
552 | } | 737 | } |
553 | } | 738 | } |
554 | 739 | ||
@@ -563,20 +748,38 @@ public static class BSParam | |||
563 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); | 748 | List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); |
564 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) | 749 | for (int ii = 0; ii < ParameterDefinitions.Length; ii++) |
565 | { | 750 | { |
566 | ParameterDefn pd = ParameterDefinitions[ii]; | 751 | ParameterDefnBase pd = ParameterDefinitions[ii]; |
567 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); | 752 | entries.Add(new PhysParameterEntry(pd.name, pd.desc)); |
568 | } | 753 | } |
569 | 754 | ||
570 | // make the list in alphabetical order for estetic reasons | 755 | // make the list alphabetical for ease of finding anything |
571 | entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2) | 756 | entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); |
572 | { | ||
573 | return ppe1.name.CompareTo(ppe2.name); | ||
574 | }); | ||
575 | 757 | ||
576 | SettableParameters = entries.ToArray(); | 758 | SettableParameters = entries.ToArray(); |
577 | } | 759 | } |
578 | } | 760 | } |
579 | 761 | ||
762 | // ===================================================================== | ||
763 | // ===================================================================== | ||
764 | // There are parameters that, when set, cause things to happen in the physics engine. | ||
765 | // This causes the broadphase collision cache to be cleared. | ||
766 | private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) | ||
767 | { | ||
768 | BSScene physScene = pPhysScene; | ||
769 | physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate() | ||
770 | { | ||
771 | physScene.PE.ResetBroadphasePool(physScene.World); | ||
772 | }); | ||
773 | } | ||
580 | 774 | ||
775 | // This causes the constraint solver cache to be cleared and reset. | ||
776 | private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) | ||
777 | { | ||
778 | BSScene physScene = pPhysScene; | ||
779 | physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate() | ||
780 | { | ||
781 | physScene.PE.ResetConstraintSolver(physScene.World); | ||
782 | }); | ||
783 | } | ||
581 | } | 784 | } |
582 | } | 785 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index e7cb3e0..cca887a 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,9 +52,19 @@ 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. | ||
59 | public enum UpdatedProperties : uint | ||
60 | { | ||
61 | Position = 1 << 0, | ||
62 | Orientation = 1 << 1, | ||
63 | Velocity = 1 << 2, | ||
64 | Acceleration = 1 << 3, | ||
65 | RotationalVelocity = 1 << 4, | ||
66 | EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, | ||
67 | } | ||
58 | public abstract class BSPhysObject : PhysicsActor | 68 | public abstract class BSPhysObject : PhysicsActor |
59 | { | 69 | { |
60 | protected BSPhysObject() | 70 | protected BSPhysObject() |
@@ -62,41 +72,61 @@ public abstract class BSPhysObject : PhysicsActor | |||
62 | } | 72 | } |
63 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) | 73 | protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) |
64 | { | 74 | { |
65 | PhysicsScene = parentScene; | 75 | PhysScene = parentScene; |
66 | LocalID = localID; | 76 | LocalID = localID; |
67 | PhysObjectName = name; | 77 | PhysObjectName = name; |
78 | Name = name; // PhysicsActor also has the name of the object. Someday consolidate. | ||
68 | TypeName = typeName; | 79 | TypeName = typeName; |
69 | 80 | ||
81 | // The collection of things that push me around | ||
82 | PhysicalActors = new BSActorCollection(PhysScene); | ||
83 | |||
84 | // Initialize variables kept in base. | ||
85 | GravModifier = 1.0f; | ||
86 | Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); | ||
87 | HoverActive = false; | ||
88 | |||
70 | // We don't have any physical representation yet. | 89 | // We don't have any physical representation yet. |
71 | PhysBody = new BulletBody(localID); | 90 | PhysBody = new BulletBody(localID); |
72 | PhysShape = new BulletShape(); | 91 | PhysShape = new BSShapeNull(); |
73 | 92 | ||
74 | // A linkset of just me | 93 | PrimAssetState = PrimAssetCondition.Unknown; |
75 | Linkset = BSLinkset.Factory(PhysicsScene, this); | ||
76 | LastAssetBuildFailed = false; | ||
77 | 94 | ||
78 | // Default material type | 95 | // Default material type. Also sets Friction, Restitution and Density. |
79 | Material = MaterialAttributes.Material.Wood; | 96 | SetMaterial((int)MaterialAttributes.Material.Wood); |
80 | 97 | ||
81 | CollisionCollection = new CollisionEventUpdate(); | 98 | CollisionCollection = new CollisionEventUpdate(); |
99 | CollisionsLastReported = CollisionCollection; | ||
100 | CollisionsLastTick = new CollisionEventUpdate(); | ||
101 | CollisionsLastTickStep = -1; | ||
102 | |||
82 | SubscribedEventsMs = 0; | 103 | SubscribedEventsMs = 0; |
83 | CollidingStep = 0; | 104 | CollidingStep = 0; |
84 | CollidingGroundStep = 0; | 105 | CollidingGroundStep = 0; |
106 | CollisionAccumulation = 0; | ||
107 | ColliderIsMoving = false; | ||
108 | CollisionScore = 0; | ||
109 | |||
110 | // All axis free. | ||
111 | LockedLinearAxis = LockedAxisFree; | ||
112 | LockedAngularAxis = LockedAxisFree; | ||
85 | } | 113 | } |
86 | 114 | ||
87 | // Tell the object to clean up. | 115 | // Tell the object to clean up. |
88 | public virtual void Destroy() | 116 | public virtual void Destroy() |
89 | { | 117 | { |
90 | UnRegisterAllPreStepActions(); | 118 | PhysicalActors.Enable(false); |
119 | PhysScene.TaintedObject("BSPhysObject.Destroy", delegate() | ||
120 | { | ||
121 | PhysicalActors.Dispose(); | ||
122 | }); | ||
91 | } | 123 | } |
92 | 124 | ||
93 | public BSScene PhysicsScene { get; protected set; } | 125 | public BSScene PhysScene { get; protected set; } |
94 | // 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 |
95 | public string PhysObjectName { get; protected set; } | 127 | public string PhysObjectName { get; protected set; } |
96 | public string TypeName { get; protected set; } | 128 | public string TypeName { get; protected set; } |
97 | 129 | ||
98 | public BSLinkset Linkset { get; set; } | ||
99 | public BSLinksetInfo LinksetInfo { get; set; } | ||
100 | 130 | ||
101 | // Return the object mass without calculating it or having side effects | 131 | // Return the object mass without calculating it or having side effects |
102 | public abstract float RawMass { get; } | 132 | public abstract float RawMass { get; } |
@@ -104,26 +134,26 @@ public abstract class BSPhysObject : PhysicsActor | |||
104 | // 'inWorld' true if the object has already been added to the dynamic world. | 134 | // 'inWorld' true if the object has already been added to the dynamic world. |
105 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); | 135 | public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); |
106 | 136 | ||
137 | // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. | ||
138 | public virtual OMV.Vector3 Gravity { get; set; } | ||
107 | // The last value calculated for the prim's inertia | 139 | // The last value calculated for the prim's inertia |
108 | public OMV.Vector3 Inertia { get; set; } | 140 | public OMV.Vector3 Inertia { get; set; } |
109 | 141 | ||
110 | // Reference to the physical body (btCollisionObject) of this object | 142 | // Reference to the physical body (btCollisionObject) of this object |
111 | public BulletBody PhysBody; | 143 | public BulletBody PhysBody; |
112 | // Reference to the physical shape (btCollisionShape) of this object | 144 | // Reference to the physical shape (btCollisionShape) of this object |
113 | public BulletShape PhysShape; | 145 | public BSShape PhysShape; |
114 | 146 | ||
115 | // 'true' if the mesh's underlying asset failed to build. | 147 | // The physical representation of the prim might require an asset fetch. |
116 | // This will keep us from looping after the first time the build failed. | 148 | // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. |
117 | public bool LastAssetBuildFailed { get; set; } | 149 | public enum PrimAssetCondition |
150 | { | ||
151 | Unknown, Waiting, Failed, Fetched | ||
152 | } | ||
153 | public PrimAssetCondition PrimAssetState { get; set; } | ||
118 | 154 | ||
119 | // 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. |
120 | public PrimitiveBaseShape BaseShape { get; protected set; } | 156 | public PrimitiveBaseShape BaseShape { get; protected set; } |
121 | // Some types of objects have preferred physical representations. | ||
122 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
123 | public virtual BSPhysicsShapeType PreferredPhysicalShape | ||
124 | { | ||
125 | get { return BSPhysicsShapeType.SHAPE_UNKNOWN; } | ||
126 | } | ||
127 | 157 | ||
128 | // 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. |
129 | // Keep the current and last EntityProperties to enable computation of differences | 159 | // Keep the current and last EntityProperties to enable computation of differences |
@@ -132,23 +162,35 @@ public abstract class BSPhysObject : PhysicsActor | |||
132 | public EntityProperties LastEntityProperties { get; set; } | 162 | public EntityProperties LastEntityProperties { get; set; } |
133 | 163 | ||
134 | public virtual OMV.Vector3 Scale { get; set; } | 164 | public virtual OMV.Vector3 Scale { get; set; } |
165 | |||
166 | // It can be confusing for an actor to know if it should move or update an object | ||
167 | // depeneding on the setting of 'selected', 'physical, ... | ||
168 | // This flag is the true test -- if true, the object is being acted on in the physical world | ||
169 | public abstract bool IsPhysicallyActive { get; } | ||
170 | |||
171 | // Detailed state of the object. | ||
135 | public abstract bool IsSolid { get; } | 172 | public abstract bool IsSolid { get; } |
136 | public abstract bool IsStatic { get; } | 173 | public abstract bool IsStatic { get; } |
174 | public abstract bool IsSelected { get; } | ||
137 | 175 | ||
138 | // Materialness | 176 | // Materialness |
139 | public MaterialAttributes.Material Material { get; private set; } | 177 | public MaterialAttributes.Material Material { get; private set; } |
140 | public override void SetMaterial(int material) | 178 | public override void SetMaterial(int material) |
141 | { | 179 | { |
142 | Material = (MaterialAttributes.Material)material; | 180 | Material = (MaterialAttributes.Material)material; |
181 | |||
182 | // Setting the material sets the material attributes also. | ||
183 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
184 | Friction = matAttrib.friction; | ||
185 | Restitution = matAttrib.restitution; | ||
186 | Density = matAttrib.density / BSParam.DensityScaleFactor; | ||
187 | // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); | ||
143 | } | 188 | } |
144 | 189 | ||
145 | // Stop all physical motion. | 190 | // Stop all physical motion. |
146 | public abstract void ZeroMotion(bool inTaintTime); | 191 | public abstract void ZeroMotion(bool inTaintTime); |
147 | public abstract void ZeroAngularMotion(bool inTaintTime); | 192 | public abstract void ZeroAngularMotion(bool inTaintTime); |
148 | 193 | ||
149 | // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. | ||
150 | public virtual void StepVehicle(float timeStep) { } | ||
151 | |||
152 | // Update the physical location and motion of the object. Called with data from Bullet. | 194 | // Update the physical location and motion of the object. Called with data from Bullet. |
153 | public abstract void UpdateProperties(EntityProperties entprop); | 195 | public abstract void UpdateProperties(EntityProperties entprop); |
154 | 196 | ||
@@ -158,18 +200,16 @@ public abstract class BSPhysObject : PhysicsActor | |||
158 | public abstract OMV.Quaternion RawOrientation { get; set; } | 200 | public abstract OMV.Quaternion RawOrientation { get; set; } |
159 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 201 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
160 | 202 | ||
161 | // The system is telling us the velocity it wants to move at. | 203 | public OMV.Vector3 RawVelocity { get; set; } |
162 | // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor | 204 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
163 | public override OMV.Vector3 TargetVelocity | 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) | ||
164 | { | 209 | { |
165 | get { return m_targetVelocity; } | 210 | AddAngularForce(force, pushforce, false); |
166 | set | ||
167 | { | ||
168 | m_targetVelocity = value; | ||
169 | Velocity = value; | ||
170 | } | ||
171 | } | 211 | } |
172 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 212 | public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime); |
173 | 213 | ||
174 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 214 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
175 | 215 | ||
@@ -177,6 +217,105 @@ public abstract class BSPhysObject : PhysicsActor | |||
177 | 217 | ||
178 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | 218 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } |
179 | 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 | |||
245 | // The current velocity forward | ||
246 | public virtual float ForwardSpeed | ||
247 | { | ||
248 | get | ||
249 | { | ||
250 | OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
251 | return characterOrientedVelocity.X; | ||
252 | } | ||
253 | } | ||
254 | // The forward speed we are trying to achieve (TargetVelocity) | ||
255 | public virtual float TargetVelocitySpeed | ||
256 | { | ||
257 | get | ||
258 | { | ||
259 | OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); | ||
260 | return characterOrientedVelocity.X; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | // The user can optionally set the center of mass. The user's setting will override any | ||
265 | // computed center-of-mass (like in linksets). | ||
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 | } | ||
282 | |||
283 | // 'actors' act on the physical object to change or constrain its motion. These can range from | ||
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 | } | ||
318 | |||
180 | #region Collisions | 319 | #region Collisions |
181 | 320 | ||
182 | // Requested number of milliseconds between collision events. Zero means disabled. | 321 | // Requested number of milliseconds between collision events. Zero means disabled. |
@@ -191,41 +330,56 @@ public abstract class BSPhysObject : PhysicsActor | |||
191 | protected long CollidingObjectStep { get; set; } | 330 | protected long CollidingObjectStep { get; set; } |
192 | // The collision flags we think are set in Bullet | 331 | // The collision flags we think are set in Bullet |
193 | protected CollisionFlags CurrentCollisionFlags { get; set; } | 332 | protected CollisionFlags CurrentCollisionFlags { get; set; } |
333 | // On a collision, check the collider and remember if the last collider was moving | ||
334 | // Used to modify the standing of avatars (avatars on stationary things stand still) | ||
335 | public bool ColliderIsMoving; | ||
336 | // Used by BSCharacter to manage standing (and not slipping) | ||
337 | public bool IsStationary; | ||
338 | |||
339 | // Count of collisions for this object | ||
340 | protected long CollisionAccumulation { get; set; } | ||
194 | 341 | ||
195 | public override bool IsColliding { | 342 | public override bool IsColliding { |
196 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | 343 | get { return (CollidingStep == PhysScene.SimulationStep); } |
197 | set { | 344 | set { |
198 | if (value) | 345 | if (value) |
199 | CollidingStep = PhysicsScene.SimulationStep; | 346 | CollidingStep = PhysScene.SimulationStep; |
200 | else | 347 | else |
201 | CollidingStep = 0; | 348 | CollidingStep = 0; |
202 | } | 349 | } |
203 | } | 350 | } |
204 | public override bool CollidingGround { | 351 | public override bool CollidingGround { |
205 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | 352 | get { return (CollidingGroundStep == PhysScene.SimulationStep); } |
206 | set | 353 | set |
207 | { | 354 | { |
208 | if (value) | 355 | if (value) |
209 | CollidingGroundStep = PhysicsScene.SimulationStep; | 356 | CollidingGroundStep = PhysScene.SimulationStep; |
210 | else | 357 | else |
211 | CollidingGroundStep = 0; | 358 | CollidingGroundStep = 0; |
212 | } | 359 | } |
213 | } | 360 | } |
214 | public override bool CollidingObj { | 361 | public override bool CollidingObj { |
215 | get { return (CollidingObjectStep == PhysicsScene.SimulationStep); } | 362 | get { return (CollidingObjectStep == PhysScene.SimulationStep); } |
216 | set { | 363 | set { |
217 | if (value) | 364 | if (value) |
218 | CollidingObjectStep = PhysicsScene.SimulationStep; | 365 | CollidingObjectStep = PhysScene.SimulationStep; |
219 | else | 366 | else |
220 | CollidingObjectStep = 0; | 367 | CollidingObjectStep = 0; |
221 | } | 368 | } |
222 | } | 369 | } |
223 | 370 | ||
224 | // The collisions that have been collected this tick | 371 | // The collisions that have been collected for the next collision reporting (throttled by subscription) |
225 | protected CollisionEventUpdate CollisionCollection; | 372 | protected CollisionEventUpdate CollisionCollection; |
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 | ||
376 | // (like a BSCharacter walking up stairs). | ||
377 | public CollisionEventUpdate CollisionsLastTick; | ||
378 | private long CollisionsLastTickStep = -1; | ||
226 | 379 | ||
227 | // The simulation step is telling this object about a collision. | 380 | // The simulation step is telling this object about a collision. |
228 | // 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. |
382 | // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. | ||
229 | // Called at taint time from within the Step() function | 383 | // Called at taint time from within the Step() function |
230 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, | 384 | public virtual bool Collide(uint collidingWith, BSPhysObject collidee, |
231 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | 385 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) |
@@ -233,27 +387,35 @@ public abstract class BSPhysObject : PhysicsActor | |||
233 | bool ret = false; | 387 | bool ret = false; |
234 | 388 | ||
235 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work | 389 | // The following lines make IsColliding(), CollidingGround() and CollidingObj work |
236 | CollidingStep = PhysicsScene.SimulationStep; | 390 | CollidingStep = PhysScene.SimulationStep; |
237 | if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) | 391 | if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID) |
238 | { | 392 | { |
239 | CollidingGroundStep = PhysicsScene.SimulationStep; | 393 | CollidingGroundStep = PhysScene.SimulationStep; |
240 | } | 394 | } |
241 | else | 395 | else |
242 | { | 396 | { |
243 | CollidingObjectStep = PhysicsScene.SimulationStep; | 397 | CollidingObjectStep = PhysScene.SimulationStep; |
244 | } | 398 | } |
245 | 399 | ||
246 | // prims in the same linkset cannot collide with each other | 400 | CollisionAccumulation++; |
247 | if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) | 401 | |
402 | // For movement tests, remember if we are colliding with an object that is moving. | ||
403 | ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false; | ||
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) | ||
248 | { | 408 | { |
249 | return ret; | 409 | CollisionsLastTick = new CollisionEventUpdate(); |
410 | CollisionsLastTickStep = PhysScene.SimulationStep; | ||
250 | } | 411 | } |
412 | CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | ||
251 | 413 | ||
252 | // if someone has subscribed for collision events.... | 414 | // If someone has subscribed for collision events log the collision so it will be reported up |
253 | if (SubscribedEvents()) { | 415 | if (SubscribedEvents()) { |
254 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | 416 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); |
255 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", | 417 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}", |
256 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); | 418 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving); |
257 | 419 | ||
258 | ret = true; | 420 | ret = true; |
259 | } | 421 | } |
@@ -267,13 +429,14 @@ public abstract class BSPhysObject : PhysicsActor | |||
267 | public virtual bool SendCollisions() | 429 | public virtual bool SendCollisions() |
268 | { | 430 | { |
269 | bool ret = true; | 431 | bool ret = true; |
432 | |||
270 | // 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 |
271 | bool force = (CollisionCollection.Count == 0); | 434 | bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); |
272 | 435 | ||
273 | // 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 |
274 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 437 | if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) |
275 | { | 438 | { |
276 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; | 439 | NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; |
277 | 440 | ||
278 | // 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 |
279 | // 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. |
@@ -283,12 +446,15 @@ public abstract class BSPhysObject : PhysicsActor | |||
283 | ret = false; | 446 | ret = false; |
284 | } | 447 | } |
285 | 448 | ||
286 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | 449 | DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); |
287 | base.SendCollisionUpdate(CollisionCollection); | 450 | base.SendCollisionUpdate(CollisionCollection); |
288 | 451 | ||
452 | // Remember the collisions from this tick for some collision specific processing. | ||
453 | CollisionsLastReported = CollisionCollection; | ||
454 | |||
289 | // The CollisionCollection instance is passed around in the simulator. | 455 | // The CollisionCollection instance is passed around in the simulator. |
290 | // 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. |
291 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | 457 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, |
292 | // 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. |
293 | CollisionCollection = new CollisionEventUpdate(); | 459 | CollisionCollection = new CollisionEventUpdate(); |
294 | } | 460 | } |
@@ -305,10 +471,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
305 | // make sure first collision happens | 471 | // make sure first collision happens |
306 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); | 472 | NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); |
307 | 473 | ||
308 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 474 | PhysScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
309 | { | 475 | { |
310 | if (PhysBody.HasPhysicalBody) | 476 | if (PhysBody.HasPhysicalBody) |
311 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 477 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
312 | }); | 478 | }); |
313 | } | 479 | } |
314 | else | 480 | else |
@@ -320,66 +486,53 @@ public abstract class BSPhysObject : PhysicsActor | |||
320 | public override void UnSubscribeEvents() { | 486 | public override void UnSubscribeEvents() { |
321 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); | 487 | // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); |
322 | SubscribedEventsMs = 0; | 488 | SubscribedEventsMs = 0; |
323 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 489 | PhysScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
324 | { | 490 | { |
325 | // 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. |
326 | if (PhysBody.HasPhysicalBody) | 492 | if (PhysBody.HasPhysicalBody) |
327 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 493 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
328 | }); | 494 | }); |
329 | } | 495 | } |
330 | // Return 'true' if the simulator wants collision events | 496 | // Return 'true' if the simulator wants collision events |
331 | public override bool SubscribedEvents() { | 497 | public override bool SubscribedEvents() { |
332 | return (SubscribedEventsMs > 0); | 498 | return (SubscribedEventsMs > 0); |
333 | } | 499 | } |
500 | // Because 'CollisionScore' is called many times while sorting, it should not be recomputed | ||
501 | // each time called. So this is built to be light weight for each collision and to do | ||
502 | // all the processing when the user asks for the info. | ||
503 | public void ComputeCollisionScore() | ||
504 | { | ||
505 | // Scale the collision count by the time since the last collision. | ||
506 | // The "+1" prevents dividing by zero. | ||
507 | long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; | ||
508 | CollisionScore = CollisionAccumulation / timeAgo; | ||
509 | } | ||
510 | public override float CollisionScore { get; set; } | ||
334 | 511 | ||
335 | #endregion // Collisions | 512 | #endregion // Collisions |
336 | 513 | ||
337 | #region Per Simulation Step actions | 514 | #region Per Simulation Step actions |
338 | // There are some actions that must be performed for a physical object before each simulation step. | ||
339 | // These actions are optional so, rather than scanning all the physical objects and asking them | ||
340 | // if they have anything to do, a physical object registers for an event call before the step is performed. | ||
341 | // This bookkeeping makes it easy to add, remove and clean up after all these registrations. | ||
342 | private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>(); | ||
343 | protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn) | ||
344 | { | ||
345 | string identifier = op + "-" + id.ToString(); | ||
346 | RegisteredActions[identifier] = actn; | ||
347 | PhysicsScene.BeforeStep += actn; | ||
348 | DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier); | ||
349 | } | ||
350 | 515 | ||
351 | // Unregister a pre step action. Safe to call if the action has not been registered. | 516 | public BSActorCollection PhysicalActors; |
352 | protected void UnRegisterPreStepAction(string op, uint id) | ||
353 | { | ||
354 | string identifier = op + "-" + id.ToString(); | ||
355 | bool removed = false; | ||
356 | if (RegisteredActions.ContainsKey(identifier)) | ||
357 | { | ||
358 | PhysicsScene.BeforeStep -= RegisteredActions[identifier]; | ||
359 | RegisteredActions.Remove(identifier); | ||
360 | removed = true; | ||
361 | } | ||
362 | DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed); | ||
363 | } | ||
364 | 517 | ||
365 | protected void UnRegisterAllPreStepActions() | 518 | // When an update to the physical properties happens, this event is fired to let |
519 | // different actors to modify the update before it is passed around | ||
520 | public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); | ||
521 | public event PreUpdatePropertyAction OnPreUpdateProperty; | ||
522 | protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) | ||
366 | { | 523 | { |
367 | foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions) | 524 | PreUpdatePropertyAction actions = OnPreUpdateProperty; |
368 | { | 525 | if (actions != null) |
369 | PhysicsScene.BeforeStep -= kvp.Value; | 526 | actions(ref entprop); |
370 | } | ||
371 | RegisteredActions.Clear(); | ||
372 | DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID); | ||
373 | } | 527 | } |
374 | 528 | ||
375 | |||
376 | #endregion // Per Simulation Step actions | 529 | #endregion // Per Simulation Step actions |
377 | 530 | ||
378 | // High performance detailed logging routine used by the physical objects. | 531 | // High performance detailed logging routine used by the physical objects. |
379 | protected void DetailLog(string msg, params Object[] args) | 532 | protected void DetailLog(string msg, params Object[] args) |
380 | { | 533 | { |
381 | if (PhysicsScene.PhysicsLogging.Enabled) | 534 | if (PhysScene.PhysicsLogging.Enabled) |
382 | PhysicsScene.DetailLog(msg, args); | 535 | PhysScene.DetailLog(msg, args); |
383 | } | 536 | } |
384 | 537 | ||
385 | } | 538 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs index 65be52a..9442854 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs | |||
@@ -59,7 +59,7 @@ public class BSPlugin : IPhysicsPlugin | |||
59 | { | 59 | { |
60 | if (_mScene == null) | 60 | if (_mScene == null) |
61 | { | 61 | { |
62 | _mScene = new BSScene(sceneIdentifier); | 62 | _mScene = new BSScene(GetName(), sceneIdentifier); |
63 | } | 63 | } |
64 | return (_mScene); | 64 | return (_mScene); |
65 | } | 65 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 826261c..f5b0361 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -39,7 +39,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
39 | { | 39 | { |
40 | 40 | ||
41 | [Serializable] | 41 | [Serializable] |
42 | public sealed class BSPrim : BSPhysObject | 42 | public class BSPrim : BSPhysObject |
43 | { | 43 | { |
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
@@ -50,39 +50,38 @@ public sealed class BSPrim : BSPhysObject | |||
50 | private bool _grabbed; | 50 | private bool _grabbed; |
51 | private bool _isSelected; | 51 | private bool _isSelected; |
52 | private bool _isVolumeDetect; | 52 | private bool _isVolumeDetect; |
53 | |||
54 | // _position is what the simulator thinks the positions of the prim is. | ||
53 | private OMV.Vector3 _position; | 55 | private OMV.Vector3 _position; |
56 | |||
54 | private float _mass; // the mass of this object | 57 | private float _mass; // the mass of this object |
55 | private float _density; | ||
56 | private OMV.Vector3 _force; | ||
57 | private OMV.Vector3 _velocity; | ||
58 | private OMV.Vector3 _torque; | ||
59 | private float _collisionScore; | ||
60 | private OMV.Vector3 _acceleration; | 58 | private OMV.Vector3 _acceleration; |
61 | private OMV.Quaternion _orientation; | 59 | private OMV.Quaternion _orientation; |
62 | private int _physicsActorType; | 60 | private int _physicsActorType; |
63 | private bool _isPhysical; | 61 | private bool _isPhysical; |
64 | private bool _flying; | 62 | private bool _flying; |
65 | private float _friction; | ||
66 | private float _restitution; | ||
67 | private bool _setAlwaysRun; | 63 | private bool _setAlwaysRun; |
68 | private bool _throttleUpdates; | 64 | private bool _throttleUpdates; |
69 | private bool _isColliding; | ||
70 | private bool _collidingGround; | ||
71 | private bool _collidingObj; | ||
72 | private bool _floatOnWater; | 65 | private bool _floatOnWater; |
73 | private OMV.Vector3 _rotationalVelocity; | 66 | private OMV.Vector3 _rotationalVelocity; |
74 | private bool _kinematic; | 67 | private bool _kinematic; |
75 | private float _buoyancy; | 68 | private float _buoyancy; |
76 | 69 | ||
77 | private BSDynamics _vehicle; | 70 | private int CrossingFailures { get; set; } |
78 | 71 | ||
79 | private OMV.Vector3 _PIDTarget; | 72 | // Keep a handle to the vehicle actor so it is easy to set parameters on same. |
80 | private bool _usePID; | 73 | public BSDynamics VehicleActor; |
81 | private float _PIDTau; | 74 | public const string VehicleActorName = "BasicVehicle"; |
82 | private bool _useHoverPID; | 75 | |
83 | private float _PIDHoverHeight; | 76 | // Parameters for the hover actor |
84 | private PIDHoverType _PIDHoverType; | 77 | public const string HoverActorName = "HoverActor"; |
85 | private float _PIDHoverTao; | 78 | // Parameters for the axis lock actor |
79 | public const String LockedAxisActorName = "BSPrim.LockedAxis"; | ||
80 | // Parameters for the move to target actor | ||
81 | public const string MoveToTargetActorName = "MoveToTargetActor"; | ||
82 | // Parameters for the setForce and setTorque actors | ||
83 | public const string SetForceActorName = "SetForceActor"; | ||
84 | public const string SetTorqueActorName = "SetTorqueActor"; | ||
86 | 85 | ||
87 | 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, |
88 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | 87 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) |
@@ -95,32 +94,28 @@ public sealed class BSPrim : BSPhysObject | |||
95 | 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). |
96 | _orientation = rotation; | 95 | _orientation = rotation; |
97 | _buoyancy = 0f; | 96 | _buoyancy = 0f; |
98 | _velocity = OMV.Vector3.Zero; | 97 | RawVelocity = OMV.Vector3.Zero; |
99 | _rotationalVelocity = OMV.Vector3.Zero; | 98 | _rotationalVelocity = OMV.Vector3.Zero; |
100 | BaseShape = pbs; | 99 | BaseShape = pbs; |
101 | _isPhysical = pisPhysical; | 100 | _isPhysical = pisPhysical; |
102 | _isVolumeDetect = false; | 101 | _isVolumeDetect = false; |
103 | 102 | ||
104 | // Someday set default attributes based on the material but, for now, we don't know the prim material yet. | 103 | // We keep a handle to the vehicle actor so we can set vehicle parameters later. |
105 | // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical); | 104 | VehicleActor = new BSDynamics(PhysScene, this, VehicleActorName); |
106 | _density = PhysicsScene.Params.defaultDensity; | 105 | PhysicalActors.Add(VehicleActorName, VehicleActor); |
107 | _friction = PhysicsScene.Params.defaultFriction; | ||
108 | _restitution = PhysicsScene.Params.defaultRestitution; | ||
109 | |||
110 | _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness | ||
111 | 106 | ||
112 | _mass = CalculateMass(); | 107 | _mass = CalculateMass(); |
113 | 108 | ||
114 | // Cause linkset variables to be initialized (like mass) | 109 | // DetailLog("{0},BSPrim.constructor,call", LocalID); |
115 | Linkset.Refresh(this); | ||
116 | |||
117 | DetailLog("{0},BSPrim.constructor,call", LocalID); | ||
118 | // do the actual object creation at taint time | 110 | // do the actual object creation at taint time |
119 | PhysicsScene.TaintedObject("BSPrim.create", delegate() | 111 | PhysScene.TaintedObject("BSPrim.create", delegate() |
120 | { | 112 | { |
113 | // Make sure the object is being created with some sanity. | ||
114 | ExtremeSanityCheck(true /* inTaintTime */); | ||
115 | |||
121 | CreateGeomAndObject(true); | 116 | CreateGeomAndObject(true); |
122 | 117 | ||
123 | CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody); | 118 | CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); |
124 | }); | 119 | }); |
125 | } | 120 | } |
126 | 121 | ||
@@ -130,26 +125,17 @@ public sealed class BSPrim : BSPhysObject | |||
130 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 125 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
131 | base.Destroy(); | 126 | base.Destroy(); |
132 | 127 | ||
133 | // Undo any links between me and any other object | ||
134 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
135 | int childrenBefore = Linkset.NumberOfChildren; | ||
136 | |||
137 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
138 | |||
139 | DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", | ||
140 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
141 | |||
142 | // Undo any vehicle properties | 128 | // Undo any vehicle properties |
143 | this.VehicleType = (int)Vehicle.TYPE_NONE; | 129 | this.VehicleType = (int)Vehicle.TYPE_NONE; |
144 | 130 | ||
145 | PhysicsScene.TaintedObject("BSPrim.destroy", delegate() | 131 | PhysScene.TaintedObject("BSPrim.Destroy", delegate() |
146 | { | 132 | { |
147 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 133 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
148 | // 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. |
149 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 135 | PhysScene.Shapes.DereferenceBody(PhysBody, null); |
150 | PhysBody.Clear(); | 136 | PhysBody.Clear(); |
151 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 137 | PhysShape.Dereference(PhysScene); |
152 | PhysShape.Clear(); | 138 | PhysShape = new BSShapeNull(); |
153 | }); | 139 | }); |
154 | } | 140 | } |
155 | 141 | ||
@@ -171,17 +157,13 @@ public sealed class BSPrim : BSPhysObject | |||
171 | public override PrimitiveBaseShape Shape { | 157 | public override PrimitiveBaseShape Shape { |
172 | set { | 158 | set { |
173 | BaseShape = value; | 159 | BaseShape = value; |
160 | PrimAssetState = PrimAssetCondition.Unknown; | ||
174 | ForceBodyShapeRebuild(false); | 161 | ForceBodyShapeRebuild(false); |
175 | } | 162 | } |
176 | } | 163 | } |
177 | // Whatever the linkset wants is what I want. | ||
178 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
179 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
180 | |||
181 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 164 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
182 | { | 165 | { |
183 | LastAssetBuildFailed = false; | 166 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() |
184 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() | ||
185 | { | 167 | { |
186 | _mass = CalculateMass(); // changing the shape changes the mass | 168 | _mass = CalculateMass(); // changing the shape changes the mass |
187 | CreateGeomAndObject(true); | 169 | CreateGeomAndObject(true); |
@@ -198,7 +180,7 @@ public sealed class BSPrim : BSPhysObject | |||
198 | if (value != _isSelected) | 180 | if (value != _isSelected) |
199 | { | 181 | { |
200 | _isSelected = value; | 182 | _isSelected = value; |
201 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 183 | PhysScene.TaintedObject("BSPrim.setSelected", delegate() |
202 | { | 184 | { |
203 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 185 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
204 | SetObjectDynamic(false); | 186 | SetObjectDynamic(false); |
@@ -206,37 +188,31 @@ public sealed class BSPrim : BSPhysObject | |||
206 | } | 188 | } |
207 | } | 189 | } |
208 | } | 190 | } |
209 | public override void CrossingFailure() { return; } | 191 | public override bool IsSelected |
192 | { | ||
193 | get { return _isSelected; } | ||
194 | } | ||
210 | 195 | ||
211 | // link me to the specified parent | 196 | public override void CrossingFailure() |
212 | public override void link(PhysicsActor obj) { | 197 | { |
213 | BSPrim parent = obj as BSPrim; | 198 | CrossingFailures++; |
214 | if (parent != null) | 199 | if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) |
215 | { | 200 | { |
216 | BSPhysObject parentBefore = Linkset.LinksetRoot; | 201 | base.RaiseOutOfBounds(RawPosition); |
217 | int childrenBefore = Linkset.NumberOfChildren; | 202 | } |
218 | 203 | else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) | |
219 | Linkset = parent.Linkset.AddMeToLinkset(this); | 204 | { |
220 | 205 | m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); | |
221 | DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
222 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
223 | } | 206 | } |
224 | return; | 207 | return; |
225 | } | 208 | } |
226 | 209 | ||
210 | // link me to the specified parent | ||
211 | public override void link(PhysicsActor obj) { | ||
212 | } | ||
213 | |||
227 | // delink me from my linkset | 214 | // delink me from my linkset |
228 | public override void delink() { | 215 | public override void delink() { |
229 | // TODO: decide if this parent checking needs to happen at taint time | ||
230 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
231 | |||
232 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
233 | int childrenBefore = Linkset.NumberOfChildren; | ||
234 | |||
235 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
236 | |||
237 | DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
238 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
239 | return; | ||
240 | } | 216 | } |
241 | 217 | ||
242 | // Set motion values to zero. | 218 | // Set motion values to zero. |
@@ -245,28 +221,28 @@ public sealed class BSPrim : BSPhysObject | |||
245 | // Called at taint time! | 221 | // Called at taint time! |
246 | public override void ZeroMotion(bool inTaintTime) | 222 | public override void ZeroMotion(bool inTaintTime) |
247 | { | 223 | { |
248 | _velocity = OMV.Vector3.Zero; | 224 | RawVelocity = OMV.Vector3.Zero; |
249 | _acceleration = OMV.Vector3.Zero; | 225 | _acceleration = OMV.Vector3.Zero; |
250 | _rotationalVelocity = OMV.Vector3.Zero; | 226 | _rotationalVelocity = OMV.Vector3.Zero; |
251 | 227 | ||
252 | // Zero some other properties in the physics engine | 228 | // Zero some other properties in the physics engine |
253 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 229 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
254 | { | 230 | { |
255 | if (PhysBody.HasPhysicalBody) | 231 | if (PhysBody.HasPhysicalBody) |
256 | PhysicsScene.PE.ClearAllForces(PhysBody); | 232 | PhysScene.PE.ClearAllForces(PhysBody); |
257 | }); | 233 | }); |
258 | } | 234 | } |
259 | public override void ZeroAngularMotion(bool inTaintTime) | 235 | public override void ZeroAngularMotion(bool inTaintTime) |
260 | { | 236 | { |
261 | _rotationalVelocity = OMV.Vector3.Zero; | 237 | _rotationalVelocity = OMV.Vector3.Zero; |
262 | // Zero some other properties in the physics engine | 238 | // Zero some other properties in the physics engine |
263 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 239 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
264 | { | 240 | { |
265 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); | 241 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
266 | if (PhysBody.HasPhysicalBody) | 242 | if (PhysBody.HasPhysicalBody) |
267 | { | 243 | { |
268 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | 244 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); |
269 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 245 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); |
270 | } | 246 | } |
271 | }); | 247 | }); |
272 | } | 248 | } |
@@ -274,6 +250,25 @@ public sealed class BSPrim : BSPhysObject | |||
274 | public override void LockAngularMotion(OMV.Vector3 axis) | 250 | public override void LockAngularMotion(OMV.Vector3 axis) |
275 | { | 251 | { |
276 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); | 252 | DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); |
253 | |||
254 | // "1" means free, "0" means locked | ||
255 | OMV.Vector3 locking = LockedAxisFree; | ||
256 | if (axis.X != 1) locking.X = 0f; | ||
257 | if (axis.Y != 1) locking.Y = 0f; | ||
258 | if (axis.Z != 1) locking.Z = 0f; | ||
259 | LockedAngularAxis = locking; | ||
260 | |||
261 | EnableActor(LockedAngularAxis != LockedAxisFree, LockedAxisActorName, delegate() | ||
262 | { | ||
263 | return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); | ||
264 | }); | ||
265 | |||
266 | // Update parameters so the new actor's Refresh() action is called at the right time. | ||
267 | PhysScene.TaintedObject("BSPrim.LockAngularMotion", delegate() | ||
268 | { | ||
269 | UpdatePhysicalParameters(); | ||
270 | }); | ||
271 | |||
277 | return; | 272 | return; |
278 | } | 273 | } |
279 | 274 | ||
@@ -284,15 +279,8 @@ public sealed class BSPrim : BSPhysObject | |||
284 | } | 279 | } |
285 | public override OMV.Vector3 Position { | 280 | public override OMV.Vector3 Position { |
286 | get { | 281 | get { |
287 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
288 | * and does not fetch this position info for children. Thus this is commented out. | ||
289 | // child prims move around based on their parent. Need to get the latest location | ||
290 | if (!Linkset.IsRoot(this)) | ||
291 | _position = Linkset.PositionGet(this); | ||
292 | */ | ||
293 | |||
294 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | 282 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
295 | // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody); | 283 | // _position = ForcePosition; |
296 | return _position; | 284 | return _position; |
297 | } | 285 | } |
298 | set { | 286 | set { |
@@ -306,26 +294,24 @@ public sealed class BSPrim : BSPhysObject | |||
306 | _position = value; | 294 | _position = value; |
307 | PositionSanityCheck(false); | 295 | PositionSanityCheck(false); |
308 | 296 | ||
309 | // A linkset might need to know if a component information changed. | 297 | PhysScene.TaintedObject("BSPrim.setPosition", delegate() |
310 | Linkset.UpdateProperties(this, false); | ||
311 | |||
312 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | ||
313 | { | 298 | { |
314 | 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); |
315 | ForcePosition = _position; | 300 | ForcePosition = _position; |
316 | }); | 301 | }); |
317 | } | 302 | } |
318 | } | 303 | } |
304 | |||
319 | public override OMV.Vector3 ForcePosition { | 305 | public override OMV.Vector3 ForcePosition { |
320 | get { | 306 | get { |
321 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 307 | _position = PhysScene.PE.GetPosition(PhysBody); |
322 | return _position; | 308 | return _position; |
323 | } | 309 | } |
324 | set { | 310 | set { |
325 | _position = value; | 311 | _position = value; |
326 | if (PhysBody.HasPhysicalBody) | 312 | if (PhysBody.HasPhysicalBody) |
327 | { | 313 | { |
328 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 314 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); |
329 | ActivateIfPhysical(false); | 315 | ActivateIfPhysical(false); |
330 | } | 316 | } |
331 | } | 317 | } |
@@ -338,7 +324,11 @@ public sealed class BSPrim : BSPhysObject | |||
338 | { | 324 | { |
339 | bool ret = false; | 325 | bool ret = false; |
340 | 326 | ||
341 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | 327 | // We don't care where non-physical items are placed |
328 | if (!IsPhysicallyActive) | ||
329 | return ret; | ||
330 | |||
331 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) | ||
342 | { | 332 | { |
343 | // The physical object is out of the known/simulated area. | 333 | // The physical object is out of the known/simulated area. |
344 | // 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 |
@@ -346,39 +336,74 @@ public sealed class BSPrim : BSPhysObject | |||
346 | return ret; | 336 | return ret; |
347 | } | 337 | } |
348 | 338 | ||
349 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 339 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
350 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 340 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
351 | if (RawPosition.Z < terrainHeight) | 341 | float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); |
342 | if ((RawPosition.Z + approxSize / 2f) < terrainHeight) | ||
352 | { | 343 | { |
353 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 344 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); |
354 | float targetHeight = terrainHeight + (Size.Z / 2f); | 345 | float targetHeight = terrainHeight + (Size.Z / 2f); |
355 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | 346 | // If the object is below ground it just has to be moved up because pushing will |
356 | upForce.Z = (terrainHeight - RawPosition.Z) * 1f; | 347 | // not get it through the terrain |
348 | _position.Z = targetHeight; | ||
349 | if (inTaintTime) | ||
350 | { | ||
351 | ForcePosition = _position; | ||
352 | } | ||
353 | // If we are throwing the object around, zero its other forces | ||
354 | ZeroMotion(inTaintTime); | ||
357 | ret = true; | 355 | ret = true; |
358 | } | 356 | } |
359 | 357 | ||
360 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 358 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
361 | { | 359 | { |
362 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 360 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
363 | // TODO: a floating motor so object will bob in the water | 361 | // TODO: a floating motor so object will bob in the water |
364 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) | 362 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
365 | { | 363 | { |
366 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | 364 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
367 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; | 365 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
366 | |||
367 | // Apply upforce and overcome gravity. | ||
368 | OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; | ||
369 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
370 | AddForce(correctionForce, false, inTaintTime); | ||
368 | ret = true; | 371 | ret = true; |
369 | } | 372 | } |
370 | } | 373 | } |
371 | 374 | ||
372 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 375 | return ret; |
373 | // TODO: This should be intergrated with a geneal physics action mechanism. | 376 | } |
374 | // TODO: This should be moderated with PID'ness. | 377 | |
375 | if (ret) | 378 | // Occasionally things will fly off and really get lost. |
379 | // Find the wanderers and bring them back. | ||
380 | // Return 'true' if some parameter need some sanity. | ||
381 | private bool ExtremeSanityCheck(bool inTaintTime) | ||
382 | { | ||
383 | bool ret = false; | ||
384 | |||
385 | uint wayOutThere = Constants.RegionSize * Constants.RegionSize; | ||
386 | // There have been instances of objects getting thrown way out of bounds and crashing | ||
387 | // the border crossing code. | ||
388 | if ( _position.X < -Constants.RegionSize || _position.X > wayOutThere | ||
389 | || _position.Y < -Constants.RegionSize || _position.Y > wayOutThere | ||
390 | || _position.Z < -Constants.RegionSize || _position.Z > wayOutThere) | ||
391 | { | ||
392 | _position = new OMV.Vector3(10, 10, 50); | ||
393 | ZeroMotion(inTaintTime); | ||
394 | ret = true; | ||
395 | } | ||
396 | if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity) | ||
376 | { | 397 | { |
377 | // Apply upforce and overcome gravity. | 398 | RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); |
378 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; | 399 | ret = true; |
379 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
380 | AddForce(correctionForce, false, inTaintTime); | ||
381 | } | 400 | } |
401 | if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) | ||
402 | { | ||
403 | _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
404 | ret = true; | ||
405 | } | ||
406 | |||
382 | return ret; | 407 | return ret; |
383 | } | 408 | } |
384 | 409 | ||
@@ -387,72 +412,69 @@ public sealed class BSPrim : BSPhysObject | |||
387 | // If the simulator cares about the mass of the linkset, it will sum it itself. | 412 | // If the simulator cares about the mass of the linkset, it will sum it itself. |
388 | public override float Mass | 413 | public override float Mass |
389 | { | 414 | { |
390 | get | 415 | get { return _mass; } |
391 | { | 416 | } |
392 | return _mass; | 417 | // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) |
393 | } | 418 | public virtual float TotalMass |
419 | { | ||
420 | get { return _mass; } | ||
394 | } | 421 | } |
395 | |||
396 | // 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 |
397 | public override float RawMass { | 423 | public override float RawMass { |
398 | get { return _mass; } | 424 | get { return _mass; } |
399 | } | 425 | } |
400 | // Set the physical mass to the passed mass. | 426 | // Set the physical mass to the passed mass. |
401 | // Note that this does not change _mass! | 427 | // Note that this does not change _mass! |
402 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 428 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
403 | { | 429 | { |
404 | if (PhysBody.HasPhysicalBody) | 430 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
405 | { | 431 | { |
406 | if (IsStatic) | 432 | if (IsStatic) |
407 | { | 433 | { |
408 | PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity); | 434 | PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); |
409 | Inertia = OMV.Vector3.Zero; | 435 | Inertia = OMV.Vector3.Zero; |
410 | PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia); | 436 | PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); |
411 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 437 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
412 | } | 438 | } |
413 | else | 439 | else |
414 | { | 440 | { |
415 | OMV.Vector3 grav = ComputeGravity(); | ||
416 | |||
417 | if (inWorld) | 441 | if (inWorld) |
418 | { | 442 | { |
419 | // Changing interesting properties doesn't change proxy and collision cache | 443 | // Changing interesting properties doesn't change proxy and collision cache |
420 | // 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 |
421 | // after parameters are changed. | 445 | // after parameters are changed. |
422 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 446 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
423 | } | 447 | } |
424 | 448 | ||
425 | // 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. |
426 | PhysicsScene.PE.SetGravity(PhysBody, grav); | 450 | Gravity = ComputeGravity(Buoyancy); |
451 | PhysScene.PE.SetGravity(PhysBody, Gravity); | ||
427 | 452 | ||
428 | Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 453 | Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
429 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia); | 454 | PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); |
430 | PhysicsScene.PE.UpdateInertiaTensor(PhysBody); | 455 | PhysScene.PE.UpdateInertiaTensor(PhysBody); |
431 | 456 | ||
432 | // center of mass is at the zero of the object | 457 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", |
433 | // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation); | 458 | LocalID, physMass, Inertia, Gravity, inWorld); |
434 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld); | ||
435 | 459 | ||
436 | if (inWorld) | 460 | if (inWorld) |
437 | { | 461 | { |
438 | AddObjectToPhysicalWorld(); | 462 | AddObjectToPhysicalWorld(); |
439 | } | 463 | } |
440 | |||
441 | // Must set gravity after it has been added to the world because, for unknown reasons, | ||
442 | // adding the object resets the object's gravity to world gravity | ||
443 | PhysicsScene.PE.SetGravity(PhysBody, grav); | ||
444 | |||
445 | } | 464 | } |
446 | } | 465 | } |
447 | } | 466 | } |
448 | 467 | ||
449 | // Return what gravity should be set to this very moment | 468 | // Return what gravity should be set to this very moment |
450 | private OMV.Vector3 ComputeGravity() | 469 | public OMV.Vector3 ComputeGravity(float buoyancy) |
451 | { | 470 | { |
452 | OMV.Vector3 ret = PhysicsScene.DefaultGravity; | 471 | OMV.Vector3 ret = PhysScene.DefaultGravity; |
453 | 472 | ||
454 | if (!IsStatic) | 473 | if (!IsStatic) |
455 | ret *= (1f - Buoyancy); | 474 | { |
475 | ret *= (1f - buoyancy); | ||
476 | ret *= GravModifier; | ||
477 | } | ||
456 | 478 | ||
457 | return ret; | 479 | return ret; |
458 | } | 480 | } |
@@ -460,93 +482,70 @@ public sealed class BSPrim : BSPhysObject | |||
460 | // Is this used? | 482 | // Is this used? |
461 | public override OMV.Vector3 CenterOfMass | 483 | public override OMV.Vector3 CenterOfMass |
462 | { | 484 | { |
463 | get { return Linkset.CenterOfMass; } | 485 | get { return RawPosition; } |
464 | } | 486 | } |
465 | 487 | ||
466 | // Is this used? | 488 | // Is this used? |
467 | public override OMV.Vector3 GeometricCenter | 489 | public override OMV.Vector3 GeometricCenter |
468 | { | 490 | { |
469 | get { return Linkset.GeometricCenter; } | 491 | get { return RawPosition; } |
470 | } | 492 | } |
471 | 493 | ||
472 | public override OMV.Vector3 Force { | 494 | public override OMV.Vector3 Force { |
473 | get { return _force; } | 495 | get { return RawForce; } |
474 | set { | 496 | set { |
475 | _force = value; | 497 | RawForce = value; |
476 | if (_force != OMV.Vector3.Zero) | 498 | EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() |
477 | { | 499 | { |
478 | // If the force is non-zero, it must be reapplied each tick because | 500 | return new BSActorSetForce(PhysScene, this, SetForceActorName); |
479 | // Bullet clears the forces applied last frame. | 501 | }); |
480 | RegisterPreStepAction("BSPrim.setForce", LocalID, | ||
481 | delegate(float timeStep) | ||
482 | { | ||
483 | DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force); | ||
484 | if (PhysBody.HasPhysicalBody) | ||
485 | { | ||
486 | PhysicsScene.PE.ApplyCentralForce(PhysBody, _force); | ||
487 | ActivateIfPhysical(false); | ||
488 | } | ||
489 | } | ||
490 | ); | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | UnRegisterPreStepAction("BSPrim.setForce", LocalID); | ||
495 | } | ||
496 | } | 502 | } |
497 | } | 503 | } |
498 | 504 | ||
499 | public override int VehicleType { | 505 | public override int VehicleType { |
500 | get { | 506 | get { |
501 | return (int)_vehicle.Type; // if we are a vehicle, return that type | 507 | return (int)VehicleActor.Type; |
502 | } | 508 | } |
503 | set { | 509 | set { |
504 | Vehicle type = (Vehicle)value; | 510 | Vehicle type = (Vehicle)value; |
505 | 511 | ||
506 | PhysicsScene.TaintedObject("setVehicleType", delegate() | 512 | PhysScene.TaintedObject("setVehicleType", delegate() |
507 | { | 513 | { |
508 | // Done at taint time so we're sure the physics engine is not using the variables | 514 | ZeroMotion(true /* inTaintTime */); |
509 | // Vehicle code changes the parameters for this vehicle type. | 515 | VehicleActor.ProcessTypeChange(type); |
510 | _vehicle.ProcessTypeChange(type); | ||
511 | ActivateIfPhysical(false); | 516 | ActivateIfPhysical(false); |
512 | |||
513 | // If an active vehicle, register the vehicle code to be called before each step | ||
514 | if (_vehicle.Type == Vehicle.TYPE_NONE) | ||
515 | UnRegisterPreStepAction("BSPrim.Vehicle", LocalID); | ||
516 | else | ||
517 | RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step); | ||
518 | }); | 517 | }); |
519 | } | 518 | } |
520 | } | 519 | } |
521 | public override void VehicleFloatParam(int param, float value) | 520 | public override void VehicleFloatParam(int param, float value) |
522 | { | 521 | { |
523 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 522 | PhysScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
524 | { | 523 | { |
525 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 524 | VehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); |
526 | ActivateIfPhysical(false); | 525 | ActivateIfPhysical(false); |
527 | }); | 526 | }); |
528 | } | 527 | } |
529 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 528 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
530 | { | 529 | { |
531 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 530 | PhysScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
532 | { | 531 | { |
533 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 532 | VehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); |
534 | ActivateIfPhysical(false); | 533 | ActivateIfPhysical(false); |
535 | }); | 534 | }); |
536 | } | 535 | } |
537 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 536 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
538 | { | 537 | { |
539 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 538 | PhysScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
540 | { | 539 | { |
541 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 540 | VehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); |
542 | ActivateIfPhysical(false); | 541 | ActivateIfPhysical(false); |
543 | }); | 542 | }); |
544 | } | 543 | } |
545 | public override void VehicleFlags(int param, bool remove) | 544 | public override void VehicleFlags(int param, bool remove) |
546 | { | 545 | { |
547 | PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate() | 546 | PhysScene.TaintedObject("BSPrim.VehicleFlags", delegate() |
548 | { | 547 | { |
549 | _vehicle.ProcessVehicleFlags(param, remove); | 548 | VehicleActor.ProcessVehicleFlags(param, remove); |
550 | }); | 549 | }); |
551 | } | 550 | } |
552 | 551 | ||
@@ -556,7 +555,7 @@ public sealed class BSPrim : BSPhysObject | |||
556 | if (_isVolumeDetect != newValue) | 555 | if (_isVolumeDetect != newValue) |
557 | { | 556 | { |
558 | _isVolumeDetect = newValue; | 557 | _isVolumeDetect = newValue; |
559 | PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() | 558 | PhysScene.TaintedObject("BSPrim.SetVolumeDetect", delegate() |
560 | { | 559 | { |
561 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); | 560 | // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); |
562 | SetObjectDynamic(true); | 561 | SetObjectDynamic(true); |
@@ -564,56 +563,110 @@ public sealed class BSPrim : BSPhysObject | |||
564 | } | 563 | } |
565 | return; | 564 | return; |
566 | } | 565 | } |
566 | public override void SetMaterial(int material) | ||
567 | { | ||
568 | base.SetMaterial(material); | ||
569 | PhysScene.TaintedObject("BSPrim.SetMaterial", delegate() | ||
570 | { | ||
571 | UpdatePhysicalParameters(); | ||
572 | }); | ||
573 | } | ||
574 | public override float Friction | ||
575 | { | ||
576 | get { return base.Friction; } | ||
577 | set | ||
578 | { | ||
579 | if (base.Friction != value) | ||
580 | { | ||
581 | base.Friction = value; | ||
582 | PhysScene.TaintedObject("BSPrim.setFriction", delegate() | ||
583 | { | ||
584 | UpdatePhysicalParameters(); | ||
585 | }); | ||
586 | } | ||
587 | } | ||
588 | } | ||
589 | public override float Restitution | ||
590 | { | ||
591 | get { return base.Restitution; } | ||
592 | set | ||
593 | { | ||
594 | if (base.Restitution != value) | ||
595 | { | ||
596 | base.Restitution = value; | ||
597 | PhysScene.TaintedObject("BSPrim.setRestitution", delegate() | ||
598 | { | ||
599 | UpdatePhysicalParameters(); | ||
600 | }); | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | // The simulator/viewer keep density as 100kg/m3. | ||
605 | // Remember to use BSParam.DensityScaleFactor to create the physical density. | ||
606 | public override float Density | ||
607 | { | ||
608 | get { return base.Density; } | ||
609 | set | ||
610 | { | ||
611 | if (base.Density != value) | ||
612 | { | ||
613 | base.Density = value; | ||
614 | PhysScene.TaintedObject("BSPrim.setDensity", delegate() | ||
615 | { | ||
616 | UpdatePhysicalParameters(); | ||
617 | }); | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | public override float GravModifier | ||
622 | { | ||
623 | get { return base.GravModifier; } | ||
624 | set | ||
625 | { | ||
626 | if (base.GravModifier != value) | ||
627 | { | ||
628 | base.GravModifier = value; | ||
629 | PhysScene.TaintedObject("BSPrim.setGravityModifier", delegate() | ||
630 | { | ||
631 | UpdatePhysicalParameters(); | ||
632 | }); | ||
633 | } | ||
634 | } | ||
635 | } | ||
567 | public override OMV.Vector3 Velocity { | 636 | public override OMV.Vector3 Velocity { |
568 | get { return _velocity; } | 637 | get { return RawVelocity; } |
569 | set { | 638 | set { |
570 | _velocity = value; | 639 | RawVelocity = value; |
571 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 640 | PhysScene.TaintedObject("BSPrim.setVelocity", delegate() |
572 | { | 641 | { |
573 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 642 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity); |
574 | ForceVelocity = _velocity; | 643 | ForceVelocity = RawVelocity; |
575 | }); | 644 | }); |
576 | } | 645 | } |
577 | } | 646 | } |
578 | public override OMV.Vector3 ForceVelocity { | 647 | public override OMV.Vector3 ForceVelocity { |
579 | get { return _velocity; } | 648 | get { return RawVelocity; } |
580 | set { | 649 | set { |
581 | PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); | 650 | PhysScene.AssertInTaintTime("BSPrim.ForceVelocity"); |
582 | 651 | ||
583 | _velocity = value; | 652 | RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); |
584 | if (PhysBody.HasPhysicalBody) | 653 | if (PhysBody.HasPhysicalBody) |
585 | { | 654 | { |
586 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | 655 | DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); |
656 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); | ||
587 | ActivateIfPhysical(false); | 657 | ActivateIfPhysical(false); |
588 | } | 658 | } |
589 | } | 659 | } |
590 | } | 660 | } |
591 | public override OMV.Vector3 Torque { | 661 | public override OMV.Vector3 Torque { |
592 | get { return _torque; } | 662 | get { return RawTorque; } |
593 | set { | 663 | set { |
594 | _torque = value; | 664 | RawTorque = value; |
595 | if (_torque != OMV.Vector3.Zero) | 665 | EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() |
596 | { | 666 | { |
597 | // If the torque is non-zero, it must be reapplied each tick because | 667 | return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); |
598 | // Bullet clears the forces applied last frame. | 668 | }); |
599 | RegisterPreStepAction("BSPrim.setTorque", LocalID, | 669 | DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); |
600 | delegate(float timeStep) | ||
601 | { | ||
602 | if (PhysBody.HasPhysicalBody) | ||
603 | AddAngularForce(_torque, false, true); | ||
604 | } | ||
605 | ); | ||
606 | } | ||
607 | else | ||
608 | { | ||
609 | UnRegisterPreStepAction("BSPrim.setTorque", LocalID); | ||
610 | } | ||
611 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | ||
612 | } | ||
613 | } | ||
614 | public override float CollisionScore { | ||
615 | get { return _collisionScore; } | ||
616 | set { _collisionScore = value; | ||
617 | } | 670 | } |
618 | } | 671 | } |
619 | public override OMV.Vector3 Acceleration { | 672 | public override OMV.Vector3 Acceleration { |
@@ -627,14 +680,6 @@ public sealed class BSPrim : BSPhysObject | |||
627 | } | 680 | } |
628 | public override OMV.Quaternion Orientation { | 681 | public override OMV.Quaternion Orientation { |
629 | get { | 682 | get { |
630 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
631 | * and does not fetch this position info for children. Thus this is commented out. | ||
632 | // Children move around because tied to parent. Get a fresh value. | ||
633 | if (!Linkset.IsRoot(this)) | ||
634 | { | ||
635 | _orientation = Linkset.OrientationGet(this); | ||
636 | } | ||
637 | */ | ||
638 | return _orientation; | 683 | return _orientation; |
639 | } | 684 | } |
640 | set { | 685 | set { |
@@ -642,17 +687,9 @@ public sealed class BSPrim : BSPhysObject | |||
642 | return; | 687 | return; |
643 | _orientation = value; | 688 | _orientation = value; |
644 | 689 | ||
645 | // A linkset might need to know if a component information changed. | 690 | PhysScene.TaintedObject("BSPrim.setOrientation", delegate() |
646 | Linkset.UpdateProperties(this, false); | ||
647 | |||
648 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | ||
649 | { | 691 | { |
650 | if (PhysBody.HasPhysicalBody) | 692 | ForceOrientation = _orientation; |
651 | { | ||
652 | // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody); | ||
653 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
654 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
655 | } | ||
656 | }); | 693 | }); |
657 | } | 694 | } |
658 | } | 695 | } |
@@ -661,13 +698,14 @@ public sealed class BSPrim : BSPhysObject | |||
661 | { | 698 | { |
662 | get | 699 | get |
663 | { | 700 | { |
664 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 701 | _orientation = PhysScene.PE.GetOrientation(PhysBody); |
665 | return _orientation; | 702 | return _orientation; |
666 | } | 703 | } |
667 | set | 704 | set |
668 | { | 705 | { |
669 | _orientation = value; | 706 | _orientation = value; |
670 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 707 | if (PhysBody.HasPhysicalBody) |
708 | PhysScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
671 | } | 709 | } |
672 | } | 710 | } |
673 | public override int PhysicsActorType { | 711 | public override int PhysicsActorType { |
@@ -680,12 +718,13 @@ public sealed class BSPrim : BSPhysObject | |||
680 | if (_isPhysical != value) | 718 | if (_isPhysical != value) |
681 | { | 719 | { |
682 | _isPhysical = value; | 720 | _isPhysical = value; |
683 | PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() | 721 | PhysScene.TaintedObject("BSPrim.setIsPhysical", delegate() |
684 | { | 722 | { |
685 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 723 | DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
686 | SetObjectDynamic(true); | 724 | SetObjectDynamic(true); |
687 | // whether phys-to-static or static-to-phys, the object is not moving. | 725 | // whether phys-to-static or static-to-phys, the object is not moving. |
688 | ZeroMotion(true); | 726 | ZeroMotion(true); |
727 | |||
689 | }); | 728 | }); |
690 | } | 729 | } |
691 | } | 730 | } |
@@ -703,6 +742,12 @@ public sealed class BSPrim : BSPhysObject | |||
703 | get { return !IsPhantom && !_isVolumeDetect; } | 742 | get { return !IsPhantom && !_isVolumeDetect; } |
704 | } | 743 | } |
705 | 744 | ||
745 | // The object is moving and is actively being dynamic in the physical world | ||
746 | public override bool IsPhysicallyActive | ||
747 | { | ||
748 | get { return !_isSelected && IsPhysical; } | ||
749 | } | ||
750 | |||
706 | // Make gravity work if the object is physical and not selected | 751 | // Make gravity work if the object is physical and not selected |
707 | // Called at taint-time!! | 752 | // Called at taint-time!! |
708 | private void SetObjectDynamic(bool forceRebuild) | 753 | private void SetObjectDynamic(bool forceRebuild) |
@@ -717,19 +762,24 @@ public sealed class BSPrim : BSPhysObject | |||
717 | // isSolid: other objects bounce off of this object | 762 | // isSolid: other objects bounce off of this object |
718 | // isVolumeDetect: other objects pass through but can generate collisions | 763 | // isVolumeDetect: other objects pass through but can generate collisions |
719 | // collisionEvents: whether this object returns collision events | 764 | // collisionEvents: whether this object returns collision events |
720 | private void UpdatePhysicalParameters() | 765 | public virtual void UpdatePhysicalParameters() |
721 | { | 766 | { |
722 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape); | 767 | if (!PhysBody.HasPhysicalBody) |
768 | { | ||
769 | // This would only happen if updates are called for during initialization when the body is not set up yet. | ||
770 | // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); | ||
771 | return; | ||
772 | } | ||
723 | 773 | ||
724 | // Mangling all the physical properties requires the object not be in the physical world. | 774 | // Mangling all the physical properties requires the object not be in the physical world. |
725 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | 775 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
726 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 776 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
727 | 777 | ||
728 | // Set up the object physicalness (does gravity and collisions move this object) | 778 | // Set up the object physicalness (does gravity and collisions move this object) |
729 | MakeDynamic(IsStatic); | 779 | MakeDynamic(IsStatic); |
730 | 780 | ||
731 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) | 781 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
732 | _vehicle.Refresh(); | 782 | PhysicalActors.Refresh(); |
733 | 783 | ||
734 | // Arrange for collision events if the simulator wants them | 784 | // Arrange for collision events if the simulator wants them |
735 | EnableCollisions(SubscribedEvents()); | 785 | EnableCollisions(SubscribedEvents()); |
@@ -740,16 +790,11 @@ public sealed class BSPrim : BSPhysObject | |||
740 | AddObjectToPhysicalWorld(); | 790 | AddObjectToPhysicalWorld(); |
741 | 791 | ||
742 | // Rebuild its shape | 792 | // Rebuild its shape |
743 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 793 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
744 | |||
745 | // Recompute any linkset parameters. | ||
746 | // When going from non-physical to physical, this re-enables the constraints that | ||
747 | // had been automatically disabled when the mass was set to zero. | ||
748 | // For compound based linksets, this enables and disables interactions of the children. | ||
749 | Linkset.Refresh(this); | ||
750 | 794 | ||
751 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", | 795 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", |
752 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | 796 | LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), |
797 | CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); | ||
753 | } | 798 | } |
754 | 799 | ||
755 | // "Making dynamic" means changing to and from static. | 800 | // "Making dynamic" means changing to and from static. |
@@ -757,59 +802,55 @@ public sealed class BSPrim : BSPhysObject | |||
757 | // When dynamic, the object can fall and be pushed by others. | 802 | // When dynamic, the object can fall and be pushed by others. |
758 | // This is independent of its 'solidness' which controls what passes through | 803 | // This is independent of its 'solidness' which controls what passes through |
759 | // this object and what interacts with it. | 804 | // this object and what interacts with it. |
760 | private void MakeDynamic(bool makeStatic) | 805 | protected virtual void MakeDynamic(bool makeStatic) |
761 | { | 806 | { |
762 | if (makeStatic) | 807 | if (makeStatic) |
763 | { | 808 | { |
764 | // Become a Bullet 'static' object type | 809 | // Become a Bullet 'static' object type |
765 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 810 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
766 | // Stop all movement | 811 | // Stop all movement |
767 | ZeroMotion(true); | 812 | ZeroMotion(true); |
768 | 813 | ||
769 | // Set various physical properties so other object interact properly | 814 | // Set various physical properties so other object interact properly |
770 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | 815 | PhysScene.PE.SetFriction(PhysBody, Friction); |
771 | PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); | 816 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
772 | PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); | 817 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
773 | 818 | ||
774 | // Mass is zero which disables a bunch of physics stuff in Bullet | 819 | // Mass is zero which disables a bunch of physics stuff in Bullet |
775 | UpdatePhysicalMassProperties(0f, false); | 820 | UpdatePhysicalMassProperties(0f, false); |
776 | // Set collision detection parameters | 821 | // Set collision detection parameters |
777 | if (BSParam.CcdMotionThreshold > 0f) | 822 | if (BSParam.CcdMotionThreshold > 0f) |
778 | { | 823 | { |
779 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 824 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
780 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 825 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
781 | } | 826 | } |
782 | 827 | ||
783 | // The activation state is 'disabled' so Bullet will not try to act on it. | 828 | // The activation state is 'disabled' so Bullet will not try to act on it. |
784 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); | 829 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); |
785 | // Start it out sleeping and physical actions could wake it up. | 830 | // Start it out sleeping and physical actions could wake it up. |
786 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); | 831 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); |
787 | 832 | ||
788 | // This collides like a static object | 833 | // This collides like a static object |
789 | PhysBody.collisionType = CollisionType.Static; | 834 | PhysBody.collisionType = CollisionType.Static; |
790 | |||
791 | // There can be special things needed for implementing linksets | ||
792 | Linkset.MakeStatic(this); | ||
793 | } | 835 | } |
794 | else | 836 | else |
795 | { | 837 | { |
796 | // Not a Bullet static object | 838 | // Not a Bullet static object |
797 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); | 839 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); |
798 | 840 | ||
799 | // Set various physical properties so other object interact properly | 841 | // Set various physical properties so other object interact properly |
800 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); | 842 | PhysScene.PE.SetFriction(PhysBody, Friction); |
801 | PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction); | 843 | PhysScene.PE.SetRestitution(PhysBody, Restitution); |
802 | PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution); | 844 | // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); |
803 | 845 | ||
804 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 846 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
805 | // Since this can be called multiple times, only zero forces when becoming physical | 847 | // Since this can be called multiple times, only zero forces when becoming physical |
806 | // PhysicsScene.PE.ClearAllForces(BSBody); | 848 | // PhysicsScene.PE.ClearAllForces(BSBody); |
807 | 849 | ||
808 | // For good measure, make sure the transform is set through to the motion state | 850 | // For good measure, make sure the transform is set through to the motion state |
809 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 851 | ForcePosition = _position; |
810 | 852 | ForceVelocity = RawVelocity; | |
811 | // Center of mass is at the center of the object | 853 | ForceRotationalVelocity = _rotationalVelocity; |
812 | // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation); | ||
813 | 854 | ||
814 | // A dynamic object has mass | 855 | // A dynamic object has mass |
815 | UpdatePhysicalMassProperties(RawMass, false); | 856 | UpdatePhysicalMassProperties(RawMass, false); |
@@ -817,25 +858,22 @@ public sealed class BSPrim : BSPhysObject | |||
817 | // Set collision detection parameters | 858 | // Set collision detection parameters |
818 | if (BSParam.CcdMotionThreshold > 0f) | 859 | if (BSParam.CcdMotionThreshold > 0f) |
819 | { | 860 | { |
820 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 861 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
821 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 862 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
822 | } | 863 | } |
823 | 864 | ||
824 | // Various values for simulation limits | 865 | // Various values for simulation limits |
825 | PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); | 866 | PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); |
826 | PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); | 867 | PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); |
827 | PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); | 868 | PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); |
828 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 869 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
829 | 870 | ||
830 | // This collides like an object. | 871 | // This collides like an object. |
831 | PhysBody.collisionType = CollisionType.Dynamic; | 872 | PhysBody.collisionType = CollisionType.Dynamic; |
832 | 873 | ||
833 | // Force activation of the object so Bullet will act on it. | 874 | // Force activation of the object so Bullet will act on it. |
834 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 875 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
835 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 876 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
836 | |||
837 | // There might be special things needed for implementing linksets. | ||
838 | Linkset.MakeDynamic(this); | ||
839 | } | 877 | } |
840 | } | 878 | } |
841 | 879 | ||
@@ -845,7 +883,7 @@ public sealed class BSPrim : BSPhysObject | |||
845 | // the functions after this one set up the state of a possibly newly created collision body. | 883 | // the functions after this one set up the state of a possibly newly created collision body. |
846 | private void MakeSolid(bool makeSolid) | 884 | private void MakeSolid(bool makeSolid) |
847 | { | 885 | { |
848 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody); | 886 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); |
849 | if (makeSolid) | 887 | if (makeSolid) |
850 | { | 888 | { |
851 | // Verify the previous code created the correct shape for this type of thing. | 889 | // Verify the previous code created the correct shape for this type of thing. |
@@ -853,7 +891,7 @@ public sealed class BSPrim : BSPhysObject | |||
853 | { | 891 | { |
854 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 892 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
855 | } | 893 | } |
856 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 894 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
857 | } | 895 | } |
858 | else | 896 | else |
859 | { | 897 | { |
@@ -861,32 +899,23 @@ public sealed class BSPrim : BSPhysObject | |||
861 | { | 899 | { |
862 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 900 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
863 | } | 901 | } |
864 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 902 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
865 | 903 | ||
866 | // Change collision info from a static object to a ghosty collision object | 904 | // Change collision info from a static object to a ghosty collision object |
867 | PhysBody.collisionType = CollisionType.VolumeDetect; | 905 | PhysBody.collisionType = CollisionType.VolumeDetect; |
868 | } | 906 | } |
869 | } | 907 | } |
870 | 908 | ||
871 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
872 | // they need waking up when parameters are changed. | ||
873 | // Called in taint-time!! | ||
874 | private void ActivateIfPhysical(bool forceIt) | ||
875 | { | ||
876 | if (IsPhysical && PhysBody.HasPhysicalBody) | ||
877 | PhysicsScene.PE.Activate(PhysBody, forceIt); | ||
878 | } | ||
879 | |||
880 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 909 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
881 | private void EnableCollisions(bool wantsCollisionEvents) | 910 | private void EnableCollisions(bool wantsCollisionEvents) |
882 | { | 911 | { |
883 | if (wantsCollisionEvents) | 912 | if (wantsCollisionEvents) |
884 | { | 913 | { |
885 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 914 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
886 | } | 915 | } |
887 | else | 916 | else |
888 | { | 917 | { |
889 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 918 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
890 | } | 919 | } |
891 | } | 920 | } |
892 | 921 | ||
@@ -897,12 +926,12 @@ public sealed class BSPrim : BSPhysObject | |||
897 | { | 926 | { |
898 | if (PhysBody.HasPhysicalBody) | 927 | if (PhysBody.HasPhysicalBody) |
899 | { | 928 | { |
900 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 929 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); |
901 | } | 930 | } |
902 | else | 931 | else |
903 | { | 932 | { |
904 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); | 933 | m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); |
905 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); | 934 | DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); |
906 | } | 935 | } |
907 | } | 936 | } |
908 | 937 | ||
@@ -932,12 +961,12 @@ public sealed class BSPrim : BSPhysObject | |||
932 | public override bool FloatOnWater { | 961 | public override bool FloatOnWater { |
933 | set { | 962 | set { |
934 | _floatOnWater = value; | 963 | _floatOnWater = value; |
935 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 964 | PhysScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
936 | { | 965 | { |
937 | if (_floatOnWater) | 966 | if (_floatOnWater) |
938 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 967 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
939 | else | 968 | else |
940 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 969 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
941 | }); | 970 | }); |
942 | } | 971 | } |
943 | } | 972 | } |
@@ -947,10 +976,10 @@ public sealed class BSPrim : BSPhysObject | |||
947 | } | 976 | } |
948 | set { | 977 | set { |
949 | _rotationalVelocity = value; | 978 | _rotationalVelocity = value; |
979 | Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity); | ||
950 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 980 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
951 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 981 | PhysScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
952 | { | 982 | { |
953 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
954 | ForceRotationalVelocity = _rotationalVelocity; | 983 | ForceRotationalVelocity = _rotationalVelocity; |
955 | }); | 984 | }); |
956 | } | 985 | } |
@@ -960,10 +989,12 @@ public sealed class BSPrim : BSPhysObject | |||
960 | return _rotationalVelocity; | 989 | return _rotationalVelocity; |
961 | } | 990 | } |
962 | set { | 991 | set { |
963 | _rotationalVelocity = value; | 992 | _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); |
964 | if (PhysBody.HasPhysicalBody) | 993 | if (PhysBody.HasPhysicalBody) |
965 | { | 994 | { |
966 | PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | 995 | DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
996 | PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity); | ||
997 | // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); | ||
967 | ActivateIfPhysical(false); | 998 | ActivateIfPhysical(false); |
968 | } | 999 | } |
969 | } | 1000 | } |
@@ -978,7 +1009,7 @@ public sealed class BSPrim : BSPhysObject | |||
978 | get { return _buoyancy; } | 1009 | get { return _buoyancy; } |
979 | set { | 1010 | set { |
980 | _buoyancy = value; | 1011 | _buoyancy = value; |
981 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 1012 | PhysScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
982 | { | 1013 | { |
983 | ForceBuoyancy = _buoyancy; | 1014 | ForceBuoyancy = _buoyancy; |
984 | }); | 1015 | }); |
@@ -990,96 +1021,113 @@ public sealed class BSPrim : BSPhysObject | |||
990 | _buoyancy = value; | 1021 | _buoyancy = value; |
991 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 1022 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
992 | // Force the recalculation of the various inertia,etc variables in the object | 1023 | // Force the recalculation of the various inertia,etc variables in the object |
993 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass); | 1024 | UpdatePhysicalMassProperties(RawMass, true); |
994 | UpdatePhysicalMassProperties(_mass, true); | 1025 | DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); |
995 | ActivateIfPhysical(false); | 1026 | ActivateIfPhysical(false); |
996 | } | 1027 | } |
997 | } | 1028 | } |
998 | 1029 | ||
999 | // Used for MoveTo | ||
1000 | public override OMV.Vector3 PIDTarget { | ||
1001 | set { _PIDTarget = value; } | ||
1002 | } | ||
1003 | public override float PIDTau { | ||
1004 | set { _PIDTau = value; } | ||
1005 | } | ||
1006 | public override bool PIDActive { | 1030 | public override bool PIDActive { |
1007 | set { _usePID = value; } | 1031 | set { |
1032 | base.MoveToTargetActive = value; | ||
1033 | EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() | ||
1034 | { | ||
1035 | return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); | ||
1036 | }); | ||
1037 | } | ||
1008 | } | 1038 | } |
1009 | 1039 | ||
1010 | // Used for llSetHoverHeight and maybe vehicle height | 1040 | // Used for llSetHoverHeight and maybe vehicle height |
1011 | // Hover Height will override MoveTo target's Z | 1041 | // Hover Height will override MoveTo target's Z |
1012 | public override bool PIDHoverActive { | 1042 | public override bool PIDHoverActive { |
1013 | set { _useHoverPID = value; } | 1043 | set { |
1014 | } | 1044 | base.HoverActive = value; |
1015 | public override float PIDHoverHeight { | 1045 | EnableActor(HoverActive, HoverActorName, delegate() |
1016 | set { _PIDHoverHeight = value; } | 1046 | { |
1017 | } | 1047 | return new BSActorHover(PhysScene, this, HoverActorName); |
1018 | public override PIDHoverType PIDHoverType { | 1048 | }); |
1019 | set { _PIDHoverType = value; } | 1049 | } |
1020 | } | ||
1021 | public override float PIDHoverTau { | ||
1022 | set { _PIDHoverTao = value; } | ||
1023 | } | 1050 | } |
1024 | 1051 | ||
1025 | // For RotLookAt | ||
1026 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
1027 | public override bool APIDActive { set { return; } } | ||
1028 | public override float APIDStrength { set { return; } } | ||
1029 | public override float APIDDamping { set { return; } } | ||
1030 | |||
1031 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 1052 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
1053 | // Per documentation, max force is limited. | ||
1054 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); | ||
1055 | |||
1032 | // Since this force is being applied in only one step, make this a force per second. | 1056 | // Since this force is being applied in only one step, make this a force per second. |
1033 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 1057 | addForce /= PhysScene.LastTimeStep; |
1034 | AddForce(addForce, pushforce, false); | 1058 | AddForce(addForce, pushforce, false /* inTaintTime */); |
1035 | } | 1059 | } |
1060 | |||
1036 | // Applying a force just adds this to the total force on the object. | 1061 | // Applying a force just adds this to the total force on the object. |
1037 | // This added force will only last the next simulation tick. | 1062 | // This added force will only last the next simulation tick. |
1038 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 1063 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
1039 | // for an object, doesn't matter if force is a pushforce or not | 1064 | // for an object, doesn't matter if force is a pushforce or not |
1040 | if (force.IsFinite()) | 1065 | if (IsPhysicallyActive) |
1041 | { | 1066 | { |
1042 | float magnitude = force.Length(); | 1067 | if (force.IsFinite()) |
1043 | if (magnitude > BSParam.MaxAddForceMagnitude) | ||
1044 | { | 1068 | { |
1045 | // Force has a limit | 1069 | // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); |
1046 | force = force / magnitude * BSParam.MaxAddForceMagnitude; | ||
1047 | } | ||
1048 | |||
1049 | OMV.Vector3 addForce = force; | ||
1050 | DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); | ||
1051 | 1070 | ||
1052 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() | 1071 | OMV.Vector3 addForce = force; |
1053 | { | 1072 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
1054 | // Bullet adds this central force to the total force for this tick | ||
1055 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); | ||
1056 | if (PhysBody.HasPhysicalBody) | ||
1057 | { | 1073 | { |
1058 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 1074 | // Bullet adds this central force to the total force for this tick |
1059 | ActivateIfPhysical(false); | 1075 | DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); |
1060 | } | 1076 | if (PhysBody.HasPhysicalBody) |
1061 | }); | 1077 | { |
1078 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
1079 | ActivateIfPhysical(false); | ||
1080 | } | ||
1081 | }); | ||
1082 | } | ||
1083 | else | ||
1084 | { | ||
1085 | m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1086 | return; | ||
1087 | } | ||
1062 | } | 1088 | } |
1063 | else | 1089 | } |
1090 | |||
1091 | public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { | ||
1092 | // for an object, doesn't matter if force is a pushforce or not | ||
1093 | if (!IsPhysicallyActive) | ||
1064 | { | 1094 | { |
1065 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 1095 | if (impulse.IsFinite()) |
1066 | return; | 1096 | { |
1097 | OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); | ||
1098 | // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); | ||
1099 | |||
1100 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddImpulse", delegate() | ||
1101 | { | ||
1102 | // Bullet adds this impulse immediately to the velocity | ||
1103 | DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); | ||
1104 | if (PhysBody.HasPhysicalBody) | ||
1105 | { | ||
1106 | PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); | ||
1107 | ActivateIfPhysical(false); | ||
1108 | } | ||
1109 | }); | ||
1110 | } | ||
1111 | else | ||
1112 | { | ||
1113 | m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
1114 | return; | ||
1115 | } | ||
1067 | } | 1116 | } |
1068 | } | 1117 | } |
1069 | 1118 | ||
1070 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 1119 | // BSPhysObject.AddAngularForce() |
1071 | AddAngularForce(force, pushforce, false); | 1120 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) |
1072 | } | ||
1073 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
1074 | { | 1121 | { |
1075 | if (force.IsFinite()) | 1122 | if (force.IsFinite()) |
1076 | { | 1123 | { |
1077 | OMV.Vector3 angForce = force; | 1124 | OMV.Vector3 angForce = force; |
1078 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | 1125 | PhysScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() |
1079 | { | 1126 | { |
1080 | if (PhysBody.HasPhysicalBody) | 1127 | if (PhysBody.HasPhysicalBody) |
1081 | { | 1128 | { |
1082 | PhysicsScene.PE.ApplyTorque(PhysBody, angForce); | 1129 | DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); |
1130 | PhysScene.PE.ApplyTorque(PhysBody, angForce); | ||
1083 | ActivateIfPhysical(false); | 1131 | ActivateIfPhysical(false); |
1084 | } | 1132 | } |
1085 | }); | 1133 | }); |
@@ -1098,11 +1146,11 @@ public sealed class BSPrim : BSPhysObject | |||
1098 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1146 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1099 | { | 1147 | { |
1100 | OMV.Vector3 applyImpulse = impulse; | 1148 | OMV.Vector3 applyImpulse = impulse; |
1101 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1149 | PhysScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1102 | { | 1150 | { |
1103 | if (PhysBody.HasPhysicalBody) | 1151 | if (PhysBody.HasPhysicalBody) |
1104 | { | 1152 | { |
1105 | PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); | 1153 | PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); |
1106 | ActivateIfPhysical(false); | 1154 | ActivateIfPhysical(false); |
1107 | } | 1155 | } |
1108 | }); | 1156 | }); |
@@ -1387,19 +1435,10 @@ public sealed class BSPrim : BSPhysObject | |||
1387 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; | 1435 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; |
1388 | volume *= (profileEnd - profileBegin); | 1436 | volume *= (profileEnd - profileBegin); |
1389 | 1437 | ||
1390 | returnMass = _density * volume; | 1438 | returnMass = Density * BSParam.DensityScaleFactor * volume; |
1391 | |||
1392 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. | ||
1393 | if (IsRootOfLinkset) | ||
1394 | { | ||
1395 | foreach (BSPrim prim in _childrenPrims) | ||
1396 | { | ||
1397 | returnMass += prim.CalculateMass(); | ||
1398 | } | ||
1399 | } | ||
1400 | */ | ||
1401 | 1439 | ||
1402 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); | 1440 | returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); |
1441 | // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); | ||
1403 | 1442 | ||
1404 | return returnMass; | 1443 | return returnMass; |
1405 | }// end CalculateMass | 1444 | }// end CalculateMass |
@@ -1410,104 +1449,68 @@ public sealed class BSPrim : BSPhysObject | |||
1410 | // Called at taint-time!!! | 1449 | // Called at taint-time!!! |
1411 | public void CreateGeomAndObject(bool forceRebuild) | 1450 | public void CreateGeomAndObject(bool forceRebuild) |
1412 | { | 1451 | { |
1413 | // If this prim is part of a linkset, we must remove and restore the physical | ||
1414 | // links if the body is rebuilt. | ||
1415 | bool needToRestoreLinkset = false; | ||
1416 | bool needToRestoreVehicle = false; | ||
1417 | |||
1418 | // Create the correct physical representation for this type of object. | 1452 | // Create the correct physical representation for this type of object. |
1419 | // Updates PhysBody and PhysShape with the new information. | 1453 | // Updates base.PhysBody and base.PhysShape with the new information. |
1420 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1454 | // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. |
1421 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1455 | PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) |
1422 | { | 1456 | { |
1423 | // Called if the current prim body is about to be destroyed. | 1457 | // Called if the current prim body is about to be destroyed. |
1424 | // Remove all the physical dependencies on the old body. | 1458 | // Remove all the physical dependencies on the old body. |
1425 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) | 1459 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1426 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1460 | // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. |
1427 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | 1461 | RemoveDependencies(); |
1428 | }); | 1462 | }); |
1429 | 1463 | ||
1430 | if (needToRestoreLinkset) | ||
1431 | { | ||
1432 | // If physical body dependencies were removed, restore them | ||
1433 | Linkset.RestoreBodyDependencies(this); | ||
1434 | } | ||
1435 | if (needToRestoreVehicle) | ||
1436 | { | ||
1437 | // If physical body dependencies were removed, restore them | ||
1438 | _vehicle.RestoreBodyDependencies(this); | ||
1439 | } | ||
1440 | |||
1441 | // Make sure the properties are set on the new object | 1464 | // Make sure the properties are set on the new object |
1442 | UpdatePhysicalParameters(); | 1465 | UpdatePhysicalParameters(); |
1443 | return; | 1466 | return; |
1444 | } | 1467 | } |
1445 | 1468 | ||
1446 | // The physics engine says that properties have updated. Update same and inform | 1469 | // Called at taint-time |
1447 | // the world that things have changed. | 1470 | protected virtual void RemoveDependencies() |
1448 | // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate() | 1471 | { |
1449 | enum UpdatedProperties { | 1472 | PhysicalActors.RemoveDependencies(); |
1450 | Position = 1 << 0, | ||
1451 | Rotation = 1 << 1, | ||
1452 | Velocity = 1 << 2, | ||
1453 | Acceleration = 1 << 3, | ||
1454 | RotationalVel = 1 << 4 | ||
1455 | } | 1473 | } |
1456 | 1474 | ||
1457 | const float ROTATION_TOLERANCE = 0.01f; | 1475 | // The physics engine says that properties have updated. Update same and inform |
1458 | const float VELOCITY_TOLERANCE = 0.001f; | 1476 | // the world that things have changed. |
1459 | const float POSITION_TOLERANCE = 0.05f; | ||
1460 | const float ACCELERATION_TOLERANCE = 0.01f; | ||
1461 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | ||
1462 | |||
1463 | public override void UpdateProperties(EntityProperties entprop) | 1477 | public override void UpdateProperties(EntityProperties entprop) |
1464 | { | 1478 | { |
1465 | // Updates only for individual prims and for the root object of a linkset. | 1479 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. |
1466 | if (Linkset.IsRoot(this)) | 1480 | TriggerPreUpdatePropertyAction(ref entprop); |
1467 | { | ||
1468 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet | ||
1469 | // TODO: handle physics introduced by Bullet with computed vehicle physics. | ||
1470 | if (_vehicle.IsActive) | ||
1471 | { | ||
1472 | entprop.RotationalVelocity = OMV.Vector3.Zero; | ||
1473 | } | ||
1474 | 1481 | ||
1475 | // Assign directly to the local variables so the normal set action does not happen | 1482 | // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1476 | _position = entprop.Position; | ||
1477 | _orientation = entprop.Rotation; | ||
1478 | _velocity = entprop.Velocity; | ||
1479 | _acceleration = entprop.Acceleration; | ||
1480 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1481 | 1483 | ||
1482 | // The sanity check can change the velocity and/or position. | 1484 | // Assign directly to the local variables so the normal set actions do not happen |
1483 | if (IsPhysical && PositionSanityCheck(true)) | 1485 | _position = entprop.Position; |
1484 | { | 1486 | _orientation = entprop.Rotation; |
1485 | entprop.Position = _position; | 1487 | // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be |
1486 | entprop.Velocity = _velocity; | 1488 | // very sensitive to velocity changes. |
1487 | } | 1489 | if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) |
1490 | RawVelocity = entprop.Velocity; | ||
1491 | _acceleration = entprop.Acceleration; | ||
1492 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1488 | 1493 | ||
1489 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG | 1494 | // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG |
1490 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | ||
1491 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1492 | 1495 | ||
1493 | // remember the current and last set values | 1496 | // The sanity check can change the velocity and/or position. |
1494 | LastEntityProperties = CurrentEntityProperties; | 1497 | if (PositionSanityCheck(true /* inTaintTime */ )) |
1495 | CurrentEntityProperties = entprop; | ||
1496 | |||
1497 | base.RequestPhysicsterseUpdate(); | ||
1498 | } | ||
1499 | /* | ||
1500 | else | ||
1501 | { | 1498 | { |
1502 | // For debugging, report the movement of children | 1499 | entprop.Position = _position; |
1503 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1500 | entprop.Velocity = RawVelocity; |
1504 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | 1501 | entprop.RotationalVelocity = _rotationalVelocity; |
1505 | entprop.Acceleration, entprop.RotationalVelocity); | 1502 | entprop.Acceleration = _acceleration; |
1506 | } | 1503 | } |
1507 | */ | ||
1508 | 1504 | ||
1509 | // The linkset implimentation might want to know about this. | 1505 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1510 | Linkset.UpdateProperties(this, true); | 1506 | DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); |
1507 | |||
1508 | // remember the current and last set values | ||
1509 | LastEntityProperties = CurrentEntityProperties; | ||
1510 | CurrentEntityProperties = entprop; | ||
1511 | |||
1512 | // Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims. | ||
1513 | base.RequestPhysicsterseUpdate(); | ||
1511 | } | 1514 | } |
1512 | } | 1515 | } |
1513 | } | 1516 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs new file mode 100755 index 0000000..f5ee671 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs | |||
@@ -0,0 +1,165 @@ | |||
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 copyright | ||
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 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | ||
28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license | ||
29 | * of Creative Commons Attribution-Share Alike 3.0 | ||
30 | * (http://creativecommons.org/licenses/by-sa/3.0/). | ||
31 | */ | ||
32 | |||
33 | using System; | ||
34 | using System.Collections.Generic; | ||
35 | using System.Reflection; | ||
36 | using System.Runtime.InteropServices; | ||
37 | using OpenMetaverse; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Physics.Manager; | ||
40 | |||
41 | using OMV = OpenMetaverse; | ||
42 | |||
43 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
44 | { | ||
45 | public class BSPrimDisplaced : BSPrim | ||
46 | { | ||
47 | // The purpose of this module is to do any mapping between what the simulator thinks | ||
48 | // the prim position and orientation is and what the physical position/orientation. | ||
49 | // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> | ||
50 | // of the prim/linkset. The simulator tracks the location of the prim/linkset by | ||
51 | // the location of the root prim. So, if center-of-mass is anywhere but the origin | ||
52 | // of the root prim, the physical origin is displaced from the simulator origin. | ||
53 | // | ||
54 | // This routine works by capturing the Force* setting of position/orientation/... and | ||
55 | // adjusting the simulator values (being set) into the physical values. | ||
56 | // The conversion is also done in the opposite direction (physical origin -> simulator origin). | ||
57 | // | ||
58 | // The updateParameter call is also captured and the values from the physics engine | ||
59 | // are converted into simulator origin values before being passed to the base | ||
60 | // class. | ||
61 | |||
62 | public virtual OMV.Vector3 PositionDisplacement { get; set; } | ||
63 | public virtual OMV.Quaternion OrientationDisplacement { get; set; } | ||
64 | |||
65 | public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
66 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
67 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
68 | { | ||
69 | ClearDisplacement(); | ||
70 | } | ||
71 | |||
72 | public void ClearDisplacement() | ||
73 | { | ||
74 | PositionDisplacement = OMV.Vector3.Zero; | ||
75 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
76 | } | ||
77 | |||
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. | ||
80 | // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). | ||
81 | public virtual void SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) | ||
82 | { | ||
83 | Vector3 comDisp; | ||
84 | if (UserSetCenterOfMassDisplacement.HasValue) | ||
85 | comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; | ||
86 | else | ||
87 | comDisp = centerOfMassDisplacement; | ||
88 | |||
89 | DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", | ||
90 | LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); | ||
91 | if (comDisp == Vector3.Zero) | ||
92 | { | ||
93 | // If there is no diplacement. Things get reset. | ||
94 | PositionDisplacement = OMV.Vector3.Zero; | ||
95 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | // Remember the displacement from root as well as the origional rotation of the | ||
100 | // new center-of-mass. | ||
101 | PositionDisplacement = comDisp; | ||
102 | OrientationDisplacement = OMV.Quaternion.Identity; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | public override Vector3 ForcePosition | ||
107 | { | ||
108 | get { return base.ForcePosition; } | ||
109 | set | ||
110 | { | ||
111 | if (PositionDisplacement != OMV.Vector3.Zero) | ||
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 | } | ||
117 | else | ||
118 | { | ||
119 | base.ForcePosition = value; | ||
120 | } | ||
121 | } | ||
122 | } | ||
123 | |||
124 | public override Quaternion ForceOrientation | ||
125 | { | ||
126 | get { return base.ForceOrientation; } | ||
127 | set | ||
128 | { | ||
129 | // TODO: | ||
130 | base.ForceOrientation = value; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | // TODO: decide if this is the right place for these variables. | ||
135 | // Somehow incorporate the optional settability by the user. | ||
136 | // Is this used? | ||
137 | public override OMV.Vector3 CenterOfMass | ||
138 | { | ||
139 | get { return RawPosition; } | ||
140 | } | ||
141 | |||
142 | // Is this used? | ||
143 | public override OMV.Vector3 GeometricCenter | ||
144 | { | ||
145 | get { return RawPosition; } | ||
146 | } | ||
147 | |||
148 | public override void UpdateProperties(EntityProperties entprop) | ||
149 | { | ||
150 | // Undo any center-of-mass displacement that might have been done. | ||
151 | if (PositionDisplacement != OMV.Vector3.Zero || OrientationDisplacement != OMV.Quaternion.Identity) | ||
152 | { | ||
153 | // Correct for any rotation around the center-of-mass | ||
154 | // TODO!!! | ||
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; | ||
159 | // entprop.Rotation = something; | ||
160 | } | ||
161 | |||
162 | base.UpdateProperties(entprop); | ||
163 | } | ||
164 | } | ||
165 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs new file mode 100755 index 0000000..235da78 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs | |||
@@ -0,0 +1,192 @@ | |||
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.Linq; | ||
30 | using System.Text; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using OMV = OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
37 | { | ||
38 | public class BSPrimLinkable : BSPrimDisplaced | ||
39 | { | ||
40 | public BSLinkset Linkset { get; set; } | ||
41 | // The index of this child prim. | ||
42 | public int LinksetChildIndex { get; set; } | ||
43 | |||
44 | public BSLinksetInfo LinksetInfo { get; set; } | ||
45 | |||
46 | public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, | ||
47 | OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) | ||
48 | : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) | ||
49 | { | ||
50 | Linkset = BSLinkset.Factory(PhysScene, this); | ||
51 | |||
52 | PhysScene.TaintedObject("BSPrimLinksetCompound.Refresh", delegate() | ||
53 | { | ||
54 | Linkset.Refresh(this); | ||
55 | }); | ||
56 | } | ||
57 | |||
58 | public override void Destroy() | ||
59 | { | ||
60 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
61 | base.Destroy(); | ||
62 | } | ||
63 | |||
64 | public override void link(Manager.PhysicsActor obj) | ||
65 | { | ||
66 | BSPrimLinkable parent = obj as BSPrimLinkable; | ||
67 | if (parent != null) | ||
68 | { | ||
69 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
70 | int childrenBefore = Linkset.NumberOfChildren; | ||
71 | |||
72 | Linkset = parent.Linkset.AddMeToLinkset(this); | ||
73 | |||
74 | DetailLog("{0},BSPrimLinkset.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", | ||
75 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
76 | } | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | public override void delink() | ||
81 | { | ||
82 | // TODO: decide if this parent checking needs to happen at taint time | ||
83 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | ||
84 | |||
85 | BSPhysObject parentBefore = Linkset.LinksetRoot; | ||
86 | int childrenBefore = Linkset.NumberOfChildren; | ||
87 | |||
88 | Linkset = Linkset.RemoveMeFromLinkset(this); | ||
89 | |||
90 | DetailLog("{0},BSPrimLinkset.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", | ||
91 | LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); | ||
92 | return; | ||
93 | } | ||
94 | |||
95 | // When simulator changes position, this might be moving a child of the linkset. | ||
96 | public override OMV.Vector3 Position | ||
97 | { | ||
98 | get { return base.Position; } | ||
99 | set | ||
100 | { | ||
101 | base.Position = value; | ||
102 | PhysScene.TaintedObject("BSPrimLinkset.setPosition", delegate() | ||
103 | { | ||
104 | Linkset.UpdateProperties(UpdatedProperties.Position, this); | ||
105 | }); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | // When simulator changes orientation, this might be moving a child of the linkset. | ||
110 | public override OMV.Quaternion Orientation | ||
111 | { | ||
112 | get { return base.Orientation; } | ||
113 | set | ||
114 | { | ||
115 | base.Orientation = value; | ||
116 | PhysScene.TaintedObject("BSPrimLinkset.setOrientation", delegate() | ||
117 | { | ||
118 | Linkset.UpdateProperties(UpdatedProperties.Orientation, this); | ||
119 | }); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | public override float TotalMass | ||
124 | { | ||
125 | get { return Linkset.LinksetMass; } | ||
126 | } | ||
127 | |||
128 | public override void UpdatePhysicalParameters() | ||
129 | { | ||
130 | base.UpdatePhysicalParameters(); | ||
131 | // Recompute any linkset parameters. | ||
132 | // When going from non-physical to physical, this re-enables the constraints that | ||
133 | // had been automatically disabled when the mass was set to zero. | ||
134 | // For compound based linksets, this enables and disables interactions of the children. | ||
135 | if (Linkset != null) // null can happen during initialization | ||
136 | Linkset.Refresh(this); | ||
137 | } | ||
138 | |||
139 | protected override void MakeDynamic(bool makeStatic) | ||
140 | { | ||
141 | base.MakeDynamic(makeStatic); | ||
142 | if (makeStatic) | ||
143 | Linkset.MakeStatic(this); | ||
144 | else | ||
145 | Linkset.MakeDynamic(this); | ||
146 | } | ||
147 | |||
148 | // Body is being taken apart. Remove physical dependencies and schedule a rebuild. | ||
149 | protected override void RemoveDependencies() | ||
150 | { | ||
151 | Linkset.RemoveDependencies(this); | ||
152 | base.RemoveDependencies(); | ||
153 | } | ||
154 | |||
155 | public override void UpdateProperties(EntityProperties entprop) | ||
156 | { | ||
157 | if (Linkset.IsRoot(this)) | ||
158 | { | ||
159 | // Properties are only updated for the roots of a linkset. | ||
160 | // TODO: this will have to change when linksets are articulated. | ||
161 | base.UpdateProperties(entprop); | ||
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 | */ | ||
172 | // The linkset might like to know about changing locations | ||
173 | Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); | ||
174 | } | ||
175 | |||
176 | public override bool Collide(uint collidingWith, BSPhysObject collidee, | ||
177 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
178 | { | ||
179 | // prims in the same linkset cannot collide with each other | ||
180 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; | ||
181 | if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID)) | ||
182 | { | ||
183 | return false; | ||
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 | |||
189 | return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth); | ||
190 | } | ||
191 | } | ||
192 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 7017194..a4a8794 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.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.Linq; | ||
29 | using System.Reflection; | 30 | using System.Reflection; |
30 | using System.Runtime.InteropServices; | 31 | using System.Runtime.InteropServices; |
31 | using System.Text; | 32 | using System.Text; |
@@ -81,14 +82,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
81 | internal long m_simulationStep = 0; | 82 | internal long m_simulationStep = 0; |
82 | internal float NominalFrameRate { get; set; } | 83 | internal float NominalFrameRate { get; set; } |
83 | public long SimulationStep { get { return m_simulationStep; } } | 84 | public long SimulationStep { get { return m_simulationStep; } } |
84 | internal int m_taintsToProcessPerStep; | ||
85 | internal float LastTimeStep { get; private set; } | 85 | internal float LastTimeStep { get; private set; } |
86 | 86 | ||
87 | // Physical objects can register for prestep or poststep events | 87 | // Physical objects can register for prestep or poststep events |
88 | public delegate void PreStepAction(float timeStep); | 88 | public delegate void PreStepAction(float timeStep); |
89 | public delegate void PostStepAction(float timeStep); | 89 | public delegate void PostStepAction(float timeStep); |
90 | public event PreStepAction BeforeStep; | 90 | public event PreStepAction BeforeStep; |
91 | public event PreStepAction AfterStep; | 91 | public event PostStepAction AfterStep; |
92 | 92 | ||
93 | // A value of the time now so all the collision and update routines do not have to get their own | 93 | // 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 | 94 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -161,17 +161,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
161 | private int m_physicsLoggingFileMinutes; | 161 | private int m_physicsLoggingFileMinutes; |
162 | private bool m_physicsLoggingDoFlush; | 162 | private bool m_physicsLoggingDoFlush; |
163 | private bool m_physicsPhysicalDumpEnabled; | 163 | private bool m_physicsPhysicalDumpEnabled; |
164 | public float PhysicsMetricDumpFrames { get; set; } | 164 | public int PhysicsMetricDumpFrames { get; set; } |
165 | // 'true' of the vehicle code is to log lots of details | 165 | // 'true' of the vehicle code is to log lots of details |
166 | public bool VehicleLoggingEnabled { get; private set; } | 166 | public bool VehicleLoggingEnabled { get; private set; } |
167 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | 167 | public bool VehiclePhysicalLoggingEnabled { get; private set; } |
168 | 168 | ||
169 | #region Construction and Initialization | 169 | #region Construction and Initialization |
170 | public BSScene(string identifier) | 170 | public BSScene(string engineType, string identifier) |
171 | { | 171 | { |
172 | m_initialized = false; | 172 | m_initialized = false; |
173 | // we are passed the name of the region we're working for. | 173 | |
174 | // The name of the region we're working for is passed to us. Keep for identification. | ||
174 | RegionName = identifier; | 175 | RegionName = identifier; |
176 | |||
177 | // Set identifying variables in the PhysicsScene interface. | ||
178 | EngineType = engineType; | ||
179 | Name = EngineType + "/" + RegionName; | ||
175 | } | 180 | } |
176 | 181 | ||
177 | public override void Initialise(IMesher meshmerizer, IConfigSource config) | 182 | public override void Initialise(IMesher meshmerizer, IConfigSource config) |
@@ -311,6 +316,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
311 | break; | 316 | break; |
312 | case "bulletxna": | 317 | case "bulletxna": |
313 | ret = new BSAPIXNA(engineName, this); | 318 | ret = new BSAPIXNA(engineName, this); |
319 | // Disable some features that are not implemented in BulletXNA | ||
320 | m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader); | ||
321 | BSParam.ShouldUseBulletHACD = false; | ||
322 | BSParam.ShouldUseSingleConvexHullForPrims = false; | ||
314 | break; | 323 | break; |
315 | } | 324 | } |
316 | 325 | ||
@@ -382,12 +391,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
382 | if (!m_initialized) return null; | 391 | if (!m_initialized) return null; |
383 | 392 | ||
384 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); | 393 | BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); |
385 | lock (PhysObjects) PhysObjects.Add(localID, actor); | 394 | lock (PhysObjects) |
395 | PhysObjects.Add(localID, actor); | ||
386 | 396 | ||
387 | // TODO: Remove kludge someday. | 397 | // TODO: Remove kludge someday. |
388 | // We must generate a collision for avatars whether they collide or not. | 398 | // We must generate a collision for avatars whether they collide or not. |
389 | // This is required by OpenSim to update avatar animations, etc. | 399 | // This is required by OpenSim to update avatar animations, etc. |
390 | lock (m_avatars) m_avatars.Add(actor); | 400 | lock (m_avatars) |
401 | m_avatars.Add(actor); | ||
391 | 402 | ||
392 | return actor; | 403 | return actor; |
393 | } | 404 | } |
@@ -403,9 +414,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
403 | { | 414 | { |
404 | try | 415 | try |
405 | { | 416 | { |
406 | lock (PhysObjects) PhysObjects.Remove(actor.LocalID); | 417 | lock (PhysObjects) |
418 | PhysObjects.Remove(bsactor.LocalID); | ||
407 | // Remove kludge someday | 419 | // Remove kludge someday |
408 | lock (m_avatars) m_avatars.Remove(bsactor); | 420 | lock (m_avatars) |
421 | m_avatars.Remove(bsactor); | ||
409 | } | 422 | } |
410 | catch (Exception e) | 423 | catch (Exception e) |
411 | { | 424 | { |
@@ -414,13 +427,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
414 | bsactor.Destroy(); | 427 | bsactor.Destroy(); |
415 | // bsactor.dispose(); | 428 | // bsactor.dispose(); |
416 | } | 429 | } |
430 | else | ||
431 | { | ||
432 | m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}", | ||
433 | LogHeader, actor.LocalID, actor.GetType().Name); | ||
434 | } | ||
417 | } | 435 | } |
418 | 436 | ||
419 | public override void RemovePrim(PhysicsActor prim) | 437 | public override void RemovePrim(PhysicsActor prim) |
420 | { | 438 | { |
421 | if (!m_initialized) return; | 439 | if (!m_initialized) return; |
422 | 440 | ||
423 | BSPrim bsprim = prim as BSPrim; | 441 | BSPhysObject bsprim = prim as BSPhysObject; |
424 | if (bsprim != null) | 442 | if (bsprim != null) |
425 | { | 443 | { |
426 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); | 444 | DetailLog("{0},RemovePrim,call", bsprim.LocalID); |
@@ -449,9 +467,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
449 | 467 | ||
450 | if (!m_initialized) return null; | 468 | if (!m_initialized) return null; |
451 | 469 | ||
452 | DetailLog("{0},AddPrimShape,call", localID); | 470 | // DetailLog("{0},BSScene.AddPrimShape,call", localID); |
453 | 471 | ||
454 | BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); | 472 | BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical); |
455 | lock (PhysObjects) PhysObjects.Add(localID, prim); | 473 | lock (PhysObjects) PhysObjects.Add(localID, prim); |
456 | return prim; | 474 | return prim; |
457 | } | 475 | } |
@@ -486,6 +504,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
486 | ProcessTaints(); | 504 | ProcessTaints(); |
487 | 505 | ||
488 | // Some of the physical objects requre individual, pre-step calls | 506 | // Some of the physical objects requre individual, pre-step calls |
507 | // (vehicles and avatar movement, in particular) | ||
489 | TriggerPreStepEvent(timeStep); | 508 | TriggerPreStepEvent(timeStep); |
490 | 509 | ||
491 | // the prestep actions might have added taints | 510 | // the prestep actions might have added taints |
@@ -527,7 +546,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
527 | collidersCount = 0; | 546 | collidersCount = 0; |
528 | } | 547 | } |
529 | 548 | ||
530 | if ((m_simulationStep % PhysicsMetricDumpFrames) == 0) | 549 | if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0)) |
531 | PE.DumpPhysicsStatistics(World); | 550 | PE.DumpPhysicsStatistics(World); |
532 | 551 | ||
533 | // Get a value for 'now' so all the collision and update routines don't have to get their own. | 552 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
@@ -543,8 +562,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
543 | uint cB = m_collisionArray[ii].bID; | 562 | uint cB = m_collisionArray[ii].bID; |
544 | Vector3 point = m_collisionArray[ii].point; | 563 | Vector3 point = m_collisionArray[ii].point; |
545 | Vector3 normal = m_collisionArray[ii].normal; | 564 | Vector3 normal = m_collisionArray[ii].normal; |
546 | SendCollision(cA, cB, point, normal, 0.01f); | 565 | float penetration = m_collisionArray[ii].penetration; |
547 | SendCollision(cB, cA, point, -normal, 0.01f); | 566 | SendCollision(cA, cB, point, normal, penetration); |
567 | SendCollision(cB, cA, point, -normal, penetration); | ||
548 | } | 568 | } |
549 | } | 569 | } |
550 | 570 | ||
@@ -682,7 +702,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
682 | 702 | ||
683 | public override Dictionary<uint, float> GetTopColliders() | 703 | public override Dictionary<uint, float> GetTopColliders() |
684 | { | 704 | { |
685 | return new Dictionary<uint, float>(); | 705 | Dictionary<uint, float> topColliders; |
706 | |||
707 | lock (PhysObjects) | ||
708 | { | ||
709 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | ||
710 | { | ||
711 | kvp.Value.ComputeCollisionScore(); | ||
712 | } | ||
713 | |||
714 | List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values); | ||
715 | orderedPrims.OrderByDescending(p => p.CollisionScore); | ||
716 | topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore); | ||
717 | } | ||
718 | |||
719 | return topColliders; | ||
686 | } | 720 | } |
687 | 721 | ||
688 | public override bool IsThreaded { get { return false; } } | 722 | public override bool IsThreaded { get { return false; } } |
@@ -694,8 +728,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
694 | // TriggerPreStepEvent | 728 | // TriggerPreStepEvent |
695 | // DoOneTimeTaints | 729 | // DoOneTimeTaints |
696 | // Step() | 730 | // Step() |
697 | // ProcessAndForwardCollisions | 731 | // ProcessAndSendToSimulatorCollisions |
698 | // ProcessAndForwardPropertyUpdates | 732 | // ProcessAndSendToSimulatorPropertyUpdates |
699 | // TriggerPostStepEvent | 733 | // TriggerPostStepEvent |
700 | 734 | ||
701 | // Calls to the PhysicsActors can't directly call into the physics engine | 735 | // Calls to the PhysicsActors can't directly call into the physics engine |
@@ -733,7 +767,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
733 | 767 | ||
734 | private void TriggerPostStepEvent(float timeStep) | 768 | private void TriggerPostStepEvent(float timeStep) |
735 | { | 769 | { |
736 | PreStepAction actions = AfterStep; | 770 | PostStepAction actions = AfterStep; |
737 | if (actions != null) | 771 | if (actions != null) |
738 | actions(timeStep); | 772 | actions(timeStep); |
739 | 773 | ||
@@ -825,15 +859,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
825 | { | 859 | { |
826 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | 860 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); |
827 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | 861 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); |
828 | Util.PrintCallStack(DetailLog); | 862 | // Util.PrintCallStack(DetailLog); |
829 | } | 863 | } |
830 | return InTaintTime; | 864 | return InTaintTime; |
831 | } | 865 | } |
832 | 866 | ||
833 | #endregion // Taints | 867 | #endregion // Taints |
834 | 868 | ||
835 | #region INI and command line parameter processing | ||
836 | |||
837 | #region IPhysicsParameters | 869 | #region IPhysicsParameters |
838 | // Get the list of parameters this physics engine supports | 870 | // Get the list of parameters this physics engine supports |
839 | public PhysParameterEntry[] GetParameterList() | 871 | public PhysParameterEntry[] GetParameterList() |
@@ -848,64 +880,65 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
848 | // will use the next time since it's pinned and shared memory. | 880 | // will use the next time since it's pinned and shared memory. |
849 | // Some of the values require calling into the physics engine to get the new | 881 | // Some of the values require calling into the physics engine to get the new |
850 | // value activated ('terrainFriction' for instance). | 882 | // value activated ('terrainFriction' for instance). |
851 | public bool SetPhysicsParameter(string parm, float val, uint localID) | 883 | public bool SetPhysicsParameter(string parm, string val, uint localID) |
852 | { | 884 | { |
853 | bool ret = false; | 885 | bool ret = false; |
854 | BSParam.ParameterDefn theParam; | 886 | |
887 | BSParam.ParameterDefnBase theParam; | ||
855 | if (BSParam.TryGetParameter(parm, out theParam)) | 888 | if (BSParam.TryGetParameter(parm, out theParam)) |
856 | { | 889 | { |
857 | theParam.setter(this, parm, localID, val); | 890 | // Set the value in the C# code |
891 | theParam.SetValue(this, val); | ||
892 | |||
893 | // Optionally set the parameter in the unmanaged code | ||
894 | if (theParam.HasSetOnObject) | ||
895 | { | ||
896 | // update all the localIDs specified | ||
897 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
898 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
899 | // If the localID is a specific object, apply the parameter change to only that object | ||
900 | List<uint> objectIDs = new List<uint>(); | ||
901 | switch (localID) | ||
902 | { | ||
903 | case PhysParameterEntry.APPLY_TO_NONE: | ||
904 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
905 | objectIDs.Add(TERRAIN_ID); | ||
906 | TaintedUpdateParameter(parm, objectIDs, val); | ||
907 | break; | ||
908 | case PhysParameterEntry.APPLY_TO_ALL: | ||
909 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
910 | TaintedUpdateParameter(parm, objectIDs, val); | ||
911 | break; | ||
912 | default: | ||
913 | // setting only one localID | ||
914 | objectIDs.Add(localID); | ||
915 | TaintedUpdateParameter(parm, objectIDs, val); | ||
916 | break; | ||
917 | } | ||
918 | } | ||
919 | |||
858 | ret = true; | 920 | ret = true; |
859 | } | 921 | } |
860 | return ret; | 922 | return ret; |
861 | } | 923 | } |
862 | 924 | ||
863 | // update all the localIDs specified | ||
864 | // If the local ID is APPLY_TO_NONE, just change the default value | ||
865 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | ||
866 | // If the localID is a specific object, apply the parameter change to only that object | ||
867 | internal delegate void AssignVal(float x); | ||
868 | internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val) | ||
869 | { | ||
870 | List<uint> objectIDs = new List<uint>(); | ||
871 | switch (localID) | ||
872 | { | ||
873 | case PhysParameterEntry.APPLY_TO_NONE: | ||
874 | setDefault(val); // setting only the default value | ||
875 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
876 | objectIDs.Add(TERRAIN_ID); | ||
877 | TaintedUpdateParameter(parm, objectIDs, val); | ||
878 | break; | ||
879 | case PhysParameterEntry.APPLY_TO_ALL: | ||
880 | setDefault(val); // setting ALL also sets the default value | ||
881 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); | ||
882 | TaintedUpdateParameter(parm, objectIDs, val); | ||
883 | break; | ||
884 | default: | ||
885 | // setting only one localID | ||
886 | objectIDs.Add(localID); | ||
887 | TaintedUpdateParameter(parm, objectIDs, val); | ||
888 | break; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | // schedule the actual updating of the paramter to when the phys engine is not busy | 925 | // schedule the actual updating of the paramter to when the phys engine is not busy |
893 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) | 926 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val) |
894 | { | 927 | { |
895 | float xval = val; | 928 | string xval = val; |
896 | List<uint> xlIDs = lIDs; | 929 | List<uint> xlIDs = lIDs; |
897 | string xparm = parm; | 930 | string xparm = parm; |
898 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | 931 | TaintedObject("BSScene.UpdateParameterSet", delegate() { |
899 | BSParam.ParameterDefn thisParam; | 932 | BSParam.ParameterDefnBase thisParam; |
900 | if (BSParam.TryGetParameter(xparm, out thisParam)) | 933 | if (BSParam.TryGetParameter(xparm, out thisParam)) |
901 | { | 934 | { |
902 | if (thisParam.onObject != null) | 935 | if (thisParam.HasSetOnObject) |
903 | { | 936 | { |
904 | foreach (uint lID in xlIDs) | 937 | foreach (uint lID in xlIDs) |
905 | { | 938 | { |
906 | BSPhysObject theObject = null; | 939 | BSPhysObject theObject = null; |
907 | PhysObjects.TryGetValue(lID, out theObject); | 940 | if (PhysObjects.TryGetValue(lID, out theObject)) |
908 | thisParam.onObject(this, theObject, xval); | 941 | thisParam.SetOnObject(this, theObject); |
909 | } | 942 | } |
910 | } | 943 | } |
911 | } | 944 | } |
@@ -914,14 +947,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
914 | 947 | ||
915 | // Get parameter. | 948 | // Get parameter. |
916 | // Return 'false' if not able to get the parameter. | 949 | // Return 'false' if not able to get the parameter. |
917 | public bool GetPhysicsParameter(string parm, out float value) | 950 | public bool GetPhysicsParameter(string parm, out string value) |
918 | { | 951 | { |
919 | float val = 0f; | 952 | string val = String.Empty; |
920 | bool ret = false; | 953 | bool ret = false; |
921 | BSParam.ParameterDefn theParam; | 954 | BSParam.ParameterDefnBase theParam; |
922 | if (BSParam.TryGetParameter(parm, out theParam)) | 955 | if (BSParam.TryGetParameter(parm, out theParam)) |
923 | { | 956 | { |
924 | val = theParam.getter(this); | 957 | val = theParam.GetValue(this); |
925 | ret = true; | 958 | ret = true; |
926 | } | 959 | } |
927 | value = val; | 960 | value = val; |
@@ -930,8 +963,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
930 | 963 | ||
931 | #endregion IPhysicsParameters | 964 | #endregion IPhysicsParameters |
932 | 965 | ||
933 | #endregion Runtime settable parameters | ||
934 | |||
935 | // Invoke the detailed logger and output something if it's enabled. | 966 | // Invoke the detailed logger and output something if it's enabled. |
936 | public void DetailLog(string msg, params Object[] args) | 967 | public void DetailLog(string msg, params Object[] args) |
937 | { | 968 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index d361f18..64aaa15 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,13 +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, | 92 | bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); |
120 | prim.PhysShape, bodyCallback); | ||
121 | ret = newGeom || newBody; | 93 | ret = newGeom || newBody; |
122 | } | 94 | } |
123 | 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}", |
@@ -128,279 +100,20 @@ public sealed class BSShapeCollection : IDisposable | |||
128 | 100 | ||
129 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) | 101 | public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) |
130 | { | 102 | { |
131 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | 103 | return GetBodyAndShape(forceRebuild, sim, prim, null); |
132 | } | ||
133 | |||
134 | // Track another user of a body. | ||
135 | // We presume the caller has allocated the body. | ||
136 | // Bodies only have one user so the body is just put into the world if not already there. | ||
137 | public void ReferenceBody(BulletBody body, bool inTaintTime) | ||
138 | { | ||
139 | lock (m_collectionActivityLock) | ||
140 | { | ||
141 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | ||
142 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | ||
143 | { | ||
144 | if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) | ||
145 | { | ||
146 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body); | ||
147 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
148 | } | ||
149 | }); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // Release the usage of a body. | ||
154 | // Called when releasing use of a BSBody. BSShape is handled separately. | ||
155 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | ||
156 | { | ||
157 | if (!body.HasPhysicalBody) | ||
158 | return; | ||
159 | |||
160 | lock (m_collectionActivityLock) | ||
161 | { | ||
162 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | ||
163 | { | ||
164 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | ||
165 | body.ID, body, inTaintTime); | ||
166 | // If the caller needs to know the old body is going away, pass the event up. | ||
167 | if (bodyCallback != null) bodyCallback(body); | ||
168 | |||
169 | if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body)) | ||
170 | { | ||
171 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body); | ||
172 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | ||
173 | } | ||
174 | |||
175 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
176 | PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null); | ||
177 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, body); | ||
178 | }); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // Track the datastructures and use count for a shape. | ||
183 | // When creating a hull, this is called first to reference the mesh | ||
184 | // and then again to reference the hull. | ||
185 | // Meshes and hulls for the same shape have the same hash key. | ||
186 | // NOTE that native shapes are not added to the mesh list or removed. | ||
187 | // Returns 'true' if this is the initial reference to the shape. Otherwise reused. | ||
188 | public bool ReferenceShape(BulletShape shape) | ||
189 | { | ||
190 | bool ret = false; | ||
191 | switch (shape.type) | ||
192 | { | ||
193 | case BSPhysicsShapeType.SHAPE_MESH: | ||
194 | MeshDesc meshDesc; | ||
195 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
196 | { | ||
197 | // There is an existing instance of this mesh. | ||
198 | meshDesc.referenceCount++; | ||
199 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | ||
200 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | // This is a new reference to a mesh | ||
205 | meshDesc.shape = shape.Clone(); | ||
206 | meshDesc.shapeKey = shape.shapeKey; | ||
207 | // We keep a reference to the underlying IMesh data so a hull can be built | ||
208 | meshDesc.referenceCount = 1; | ||
209 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | ||
210 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | ||
211 | ret = true; | ||
212 | } | ||
213 | meshDesc.lastReferenced = System.DateTime.Now; | ||
214 | Meshes[shape.shapeKey] = meshDesc; | ||
215 | break; | ||
216 | case BSPhysicsShapeType.SHAPE_HULL: | ||
217 | HullDesc hullDesc; | ||
218 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
219 | { | ||
220 | // There is an existing instance of this hull. | ||
221 | hullDesc.referenceCount++; | ||
222 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | ||
223 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | // This is a new reference to a hull | ||
228 | hullDesc.shape = shape.Clone(); | ||
229 | hullDesc.shapeKey = shape.shapeKey; | ||
230 | hullDesc.referenceCount = 1; | ||
231 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | ||
232 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | ||
233 | ret = true; | ||
234 | |||
235 | } | ||
236 | hullDesc.lastReferenced = System.DateTime.Now; | ||
237 | Hulls[shape.shapeKey] = hullDesc; | ||
238 | break; | ||
239 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
240 | break; | ||
241 | default: | ||
242 | // Native shapes are not tracked and they don't go into any list | ||
243 | break; | ||
244 | } | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | // Release the usage of a shape. | ||
249 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | ||
250 | { | ||
251 | if (!shape.HasPhysicalShape) | ||
252 | return; | ||
253 | |||
254 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | ||
255 | { | ||
256 | if (shape.HasPhysicalShape) | ||
257 | { | ||
258 | if (shape.isNativeShape) | ||
259 | { | ||
260 | // Native shapes are not tracked and are released immediately | ||
261 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | ||
262 | BSScene.DetailLogZero, shape.AddrString, inTaintTime); | ||
263 | if (shapeCallback != null) shapeCallback(shape); | ||
264 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | switch (shape.type) | ||
269 | { | ||
270 | case BSPhysicsShapeType.SHAPE_HULL: | ||
271 | DereferenceHull(shape, shapeCallback); | ||
272 | break; | ||
273 | case BSPhysicsShapeType.SHAPE_MESH: | ||
274 | DereferenceMesh(shape, shapeCallback); | ||
275 | break; | ||
276 | case BSPhysicsShapeType.SHAPE_COMPOUND: | ||
277 | DereferenceCompound(shape, shapeCallback); | ||
278 | break; | ||
279 | case BSPhysicsShapeType.SHAPE_UNKNOWN: | ||
280 | break; | ||
281 | default: | ||
282 | break; | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | }); | ||
287 | } | ||
288 | |||
289 | // Count down the reference count for a mesh shape | ||
290 | // Called at taint-time. | ||
291 | private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
292 | { | ||
293 | MeshDesc meshDesc; | ||
294 | if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) | ||
295 | { | ||
296 | meshDesc.referenceCount--; | ||
297 | // TODO: release the Bullet storage | ||
298 | if (shapeCallback != null) shapeCallback(shape); | ||
299 | meshDesc.lastReferenced = System.DateTime.Now; | ||
300 | Meshes[shape.shapeKey] = meshDesc; | ||
301 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | ||
302 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | ||
303 | |||
304 | } | ||
305 | } | ||
306 | |||
307 | // Count down the reference count for a hull shape | ||
308 | // Called at taint-time. | ||
309 | private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
310 | { | ||
311 | HullDesc hullDesc; | ||
312 | if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) | ||
313 | { | ||
314 | hullDesc.referenceCount--; | ||
315 | // TODO: release the Bullet storage (aging old entries?) | ||
316 | |||
317 | // Tell upper layers that, if they have dependencies on this shape, this link is going away | ||
318 | if (shapeCallback != null) shapeCallback(shape); | ||
319 | |||
320 | hullDesc.lastReferenced = System.DateTime.Now; | ||
321 | Hulls[shape.shapeKey] = hullDesc; | ||
322 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | ||
323 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | // Remove a reference to a compound shape. | ||
328 | // Taking a compound shape apart is a little tricky because if you just delete the | ||
329 | // physical shape, it will free all the underlying children. We can't do that because | ||
330 | // they could be shared. So, this removes each of the children from the compound and | ||
331 | // dereferences them separately before destroying the compound collision object itself. | ||
332 | // Called at taint-time. | ||
333 | private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) | ||
334 | { | ||
335 | if (!PhysicsScene.PE.IsCompound(shape)) | ||
336 | { | ||
337 | // Failed the sanity check!! | ||
338 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
339 | LogHeader, shape.type, shape.AddrString); | ||
340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
341 | BSScene.DetailLogZero, shape.type, shape.AddrString); | ||
342 | return; | ||
343 | } | ||
344 | |||
345 | int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape); | ||
346 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | ||
347 | |||
348 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
349 | { | ||
350 | BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii); | ||
351 | DereferenceAnonCollisionShape(childShape); | ||
352 | } | ||
353 | PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape); | ||
354 | } | 104 | } |
355 | 105 | ||
356 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | 106 | // If the existing prim's shape is to be replaced, remove the tie to the existing shape |
357 | // Figure out type and call the correct dereference routine. | 107 | // before replacing it. |
358 | // Called at taint-time. | 108 | private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) |
359 | private void DereferenceAnonCollisionShape(BulletShape shapeInfo) | ||
360 | { | 109 | { |
361 | MeshDesc meshDesc; | 110 | if (prim.PhysShape.HasPhysicalShape) |
362 | HullDesc hullDesc; | ||
363 | |||
364 | if (TryGetMeshByPtr(shapeInfo, out meshDesc)) | ||
365 | { | ||
366 | shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; | ||
367 | shapeInfo.shapeKey = meshDesc.shapeKey; | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | if (TryGetHullByPtr(shapeInfo, out hullDesc)) | ||
372 | { | ||
373 | shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; | ||
374 | shapeInfo.shapeKey = hullDesc.shapeKey; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | if (PhysicsScene.PE.IsCompound(shapeInfo)) | ||
379 | { | ||
380 | shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
381 | } | ||
382 | else | ||
383 | { | ||
384 | if (PhysicsScene.PE.IsNativeShape(shapeInfo)) | ||
385 | { | ||
386 | shapeInfo.isNativeShape = true; | ||
387 | shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | |||
393 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | ||
394 | |||
395 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
396 | { | 111 | { |
397 | DereferenceShape(shapeInfo, true, null); | 112 | if (shapeCallback != null) |
398 | } | 113 | shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); |
399 | else | 114 | prim.PhysShape.Dereference(m_physicsScene); |
400 | { | ||
401 | PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", | ||
402 | LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString); | ||
403 | } | 115 | } |
116 | prim.PhysShape = new BSShapeNull(); | ||
404 | } | 117 | } |
405 | 118 | ||
406 | // Create the geometry information in Bullet for later use. | 119 | // Create the geometry information in Bullet for later use. |
@@ -411,95 +124,75 @@ public sealed class BSShapeCollection : IDisposable | |||
411 | // Info in prim.BSShape is updated to the new shape. | 124 | // Info in prim.BSShape is updated to the new shape. |
412 | // Returns 'true' if the geometry was rebuilt. | 125 | // Returns 'true' if the geometry was rebuilt. |
413 | // Called at taint-time! | 126 | // Called at taint-time! |
414 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 127 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) |
415 | { | 128 | { |
416 | bool ret = false; | 129 | bool ret = false; |
417 | bool haveShape = false; | 130 | bool haveShape = false; |
131 | bool nativeShapePossible = true; | ||
132 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
418 | 133 | ||
419 | 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) | ||
420 | { | 138 | { |
421 | // an avatar capsule is close to a native shape (it is not shared) | 139 | DereferenceExistingShape(prim, shapeCallback); |
422 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback); | 140 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
423 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 141 | BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); |
424 | ret = true; | 142 | ret = true; |
425 | haveShape = true; | 143 | haveShape = true; |
426 | } | 144 | } |
427 | 145 | ||
428 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
429 | // This isn't too great a hardship since most of the child shapes will have already been created. | ||
430 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
431 | { | ||
432 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | ||
433 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | ||
434 | haveShape = true; | ||
435 | } | ||
436 | |||
437 | if (!haveShape) | ||
438 | { | ||
439 | ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback); | ||
440 | } | ||
441 | |||
442 | return ret; | ||
443 | } | ||
444 | |||
445 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | ||
446 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
447 | { | ||
448 | bool ret = false; | ||
449 | bool haveShape = false; | ||
450 | bool nativeShapePossible = true; | ||
451 | PrimitiveBaseShape pbs = prim.BaseShape; | ||
452 | |||
453 | // 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. | ||
454 | if (!haveShape | 148 | if (!haveShape |
455 | && pbs != null | ||
456 | && nativeShapePossible | 149 | && nativeShapePossible |
457 | && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) | 150 | && pbs != null |
458 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 151 | && PrimHasNoCuts(pbs) |
459 | && pbs.ProfileHollow == 0 | 152 | && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) |
460 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | 153 | ) |
461 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
462 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
463 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
464 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | ||
465 | { | 154 | { |
466 | // 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. |
467 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | 156 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; |
468 | if (prim.PhysShape.HasPhysicalShape) | 157 | if (prim.PhysShape.HasPhysicalShape) |
469 | scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape); | 158 | scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); |
470 | 159 | ||
471 | 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}", |
472 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | 161 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); |
473 | 162 | ||
474 | // It doesn't look like Bullet scales 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 |
475 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 164 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
476 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 165 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
477 | { | 166 | { |
478 | haveShape = true; | 167 | haveShape = true; |
479 | if (forceRebuild | 168 | if (forceRebuild |
480 | || prim.Scale != scaleOfExistingShape | 169 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE |
481 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 170 | ) |
482 | ) | ||
483 | { | 171 | { |
484 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 172 | DereferenceExistingShape(prim, shapeCallback); |
485 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 173 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
486 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 174 | BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); |
487 | prim.LocalID, forceRebuild, prim.PhysShape); | 175 | ret = true; |
488 | } | 176 | } |
177 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", | ||
178 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
489 | } | 179 | } |
180 | // If we didn't make a sphere, maybe a box will work. | ||
490 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 181 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
491 | { | 182 | { |
492 | haveShape = true; | 183 | haveShape = true; |
493 | if (forceRebuild | 184 | if (forceRebuild |
494 | || prim.Scale != scaleOfExistingShape | 185 | || prim.Scale != scaleOfExistingShape |
495 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 186 | || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX |
496 | ) | 187 | ) |
497 | { | 188 | { |
498 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 189 | DereferenceExistingShape(prim, shapeCallback); |
499 | FixedShapeKey.KEY_BOX, shapeCallback); | 190 | prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, |
500 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 191 | BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); |
501 | prim.LocalID, forceRebuild, prim.PhysShape); | 192 | ret = true; |
502 | } | 193 | } |
194 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", | ||
195 | prim.LocalID, forceRebuild, ret, prim.PhysShape); | ||
503 | } | 196 | } |
504 | } | 197 | } |
505 | 198 | ||
@@ -512,7 +205,20 @@ public sealed class BSShapeCollection : IDisposable | |||
512 | return ret; | 205 | return ret; |
513 | } | 206 | } |
514 | 207 | ||
515 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 208 | // return 'true' if this shape description does not include any cutting or twisting. |
209 | public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) | ||
210 | { | ||
211 | return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | ||
212 | && pbs.ProfileHollow == 0 | ||
213 | && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 | ||
214 | && pbs.PathBegin == 0 && pbs.PathEnd == 0 | ||
215 | && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 | ||
216 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | ||
217 | && pbs.PathShearX == 0 && pbs.PathShearY == 0; | ||
218 | } | ||
219 | |||
220 | // return 'true' if the prim's shape was changed. | ||
221 | private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) | ||
516 | { | 222 | { |
517 | 223 | ||
518 | bool ret = false; | 224 | bool ret = false; |
@@ -520,404 +226,110 @@ public sealed class BSShapeCollection : IDisposable | |||
520 | // made. Native shapes work in either case. | 226 | // made. Native shapes work in either case. |
521 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) | 227 | if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) |
522 | { | 228 | { |
523 | // 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 |
524 | ret = GetReferenceToHull(prim,shapeCallback); | 230 | BSShape potentialHull = null; |
525 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | ||
526 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | ret = GetReferenceToMesh(prim, shapeCallback); | ||
531 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | ||
532 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | ||
533 | } | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | // Creates a native shape and assignes it to prim.BSShape. | ||
538 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). | ||
539 | private bool GetReferenceToNativeShape(BSPhysObject prim, | ||
540 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey, | ||
541 | ShapeDestructionCallback shapeCallback) | ||
542 | { | ||
543 | // release any previous shape | ||
544 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
545 | |||
546 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | ||
547 | |||
548 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | ||
549 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | ||
550 | prim.LocalID, newShape, prim.Scale); | ||
551 | |||
552 | // native shapes are scaled by Bullet | ||
553 | prim.PhysShape = newShape; | ||
554 | return true; | ||
555 | } | ||
556 | |||
557 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType, | ||
558 | FixedShapeKey shapeKey) | ||
559 | { | ||
560 | BulletShape newShape; | ||
561 | // Need to make sure the passed shape information is for the native type. | ||
562 | ShapeData nativeShapeData = new ShapeData(); | ||
563 | nativeShapeData.Type = shapeType; | ||
564 | nativeShapeData.ID = prim.LocalID; | ||
565 | nativeShapeData.Scale = prim.Scale; | ||
566 | nativeShapeData.Size = prim.Scale; // unneeded, I think. | ||
567 | nativeShapeData.MeshKey = (ulong)shapeKey; | ||
568 | nativeShapeData.HullKey = (ulong)shapeKey; | ||
569 | |||
570 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | ||
571 | { | ||
572 | |||
573 | newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale); | ||
574 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | // Native shapes are scaled in Bullet so set the scaling to the size | ||
579 | newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData); | ||
580 | |||
581 | } | ||
582 | if (!newShape.HasPhysicalShape) | ||
583 | { | ||
584 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | ||
585 | LogHeader, prim.LocalID, shapeType); | ||
586 | } | ||
587 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
588 | newShape.isNativeShape = true; | ||
589 | |||
590 | return newShape; | ||
591 | } | ||
592 | |||
593 | // Builds a mesh shape in the physical world and updates prim.BSShape. | ||
594 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | ||
595 | // Returns 'true' of a mesh was actually built. Otherwise . | ||
596 | // Called at taint-time! | ||
597 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
598 | { | ||
599 | BulletShape newShape = new BulletShape(); | ||
600 | |||
601 | float lod; | ||
602 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
603 | |||
604 | // if this new shape is the same as last time, don't recreate the mesh | ||
605 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | ||
606 | return false; | ||
607 | 231 | ||
608 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 232 | PrimitiveBaseShape pbs = prim.BaseShape; |
609 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 233 | if (BSParam.ShouldUseSingleConvexHullForPrims |
610 | 234 | && pbs != null | |
611 | // Since we're recreating new, get rid of the reference to the previous shape | 235 | && !pbs.SculptEntry |
612 | DereferenceShape(prim.PhysShape, true, shapeCallback); | 236 | && PrimHasNoCuts(pbs) |
613 | 237 | ) | |
614 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); | 238 | { |
615 | // Take evasive action if the mesh was not constructed. | 239 | potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); |
616 | newShape = VerifyMeshCreated(newShape, prim); | 240 | } |
617 | 241 | else | |
618 | ReferenceShape(newShape); | 242 | { |
619 | 243 | potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); | |
620 | prim.PhysShape = newShape; | 244 | } |
621 | |||
622 | return true; // 'true' means a new shape has been added to this prim | ||
623 | } | ||
624 | |||
625 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
626 | { | ||
627 | BulletShape newShape = new BulletShape(); | ||
628 | IMesh meshData = null; | ||
629 | 245 | ||
630 | MeshDesc meshDesc; | 246 | // If the current shape is not what is on the prim at the moment, time to change. |
631 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 247 | if (!prim.PhysShape.HasPhysicalShape |
632 | { | 248 | || potentialHull.ShapeType != prim.PhysShape.ShapeType |
633 | // If the mesh has already been built just use it. | 249 | || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) |
634 | newShape = meshDesc.shape.Clone(); | 250 | { |
251 | DereferenceExistingShape(prim, shapeCallback); | ||
252 | prim.PhysShape = potentialHull; | ||
253 | ret = true; | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | // The current shape on the prim is the correct one. We don't need the potential reference. | ||
258 | potentialHull.Dereference(m_physicsScene); | ||
259 | } | ||
260 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); | ||
635 | } | 261 | } |
636 | else | 262 | else |
637 | { | 263 | { |
638 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); | 264 | // Update prim.BSShape to reference a mesh of this shape. |
639 | 265 | BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); | |
640 | if (meshData != null) | 266 | // If the current shape is not what is on the prim at the moment, time to change. |
267 | if (!prim.PhysShape.HasPhysicalShape | ||
268 | || potentialMesh.ShapeType != prim.PhysShape.ShapeType | ||
269 | || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) | ||
641 | { | 270 | { |
642 | int[] indices = meshData.getIndexListAsInt(); | 271 | DereferenceExistingShape(prim, shapeCallback); |
643 | List<OMV.Vector3> vertices = meshData.getVertexList(); | 272 | prim.PhysShape = potentialMesh; |
644 | 273 | ret = true; | |
645 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
646 | int vi = 0; | ||
647 | foreach (OMV.Vector3 vv in vertices) | ||
648 | { | ||
649 | verticesAsFloats[vi++] = vv.X; | ||
650 | verticesAsFloats[vi++] = vv.Y; | ||
651 | verticesAsFloats[vi++] = vv.Z; | ||
652 | } | ||
653 | |||
654 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | ||
655 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | ||
656 | |||
657 | newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, | ||
658 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | ||
659 | } | 274 | } |
275 | else | ||
276 | { | ||
277 | // We don't need this reference to the mesh that is already being using. | ||
278 | potentialMesh.Dereference(m_physicsScene); | ||
279 | } | ||
280 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); | ||
660 | } | 281 | } |
661 | newShape.shapeKey = newMeshKey; | 282 | return ret; |
662 | |||
663 | return newShape; | ||
664 | } | ||
665 | |||
666 | // See that hull shape exists in the physical world and update prim.BSShape. | ||
667 | // We could be creating the hull because scale changed or whatever. | ||
668 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
669 | { | ||
670 | BulletShape newShape; | ||
671 | |||
672 | float lod; | ||
673 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
674 | |||
675 | // if the hull hasn't changed, don't rebuild it | ||
676 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | ||
677 | return false; | ||
678 | |||
679 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | ||
680 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | ||
681 | |||
682 | // Remove usage of the previous shape. | ||
683 | DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
684 | |||
685 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); | ||
686 | newShape = VerifyMeshCreated(newShape, prim); | ||
687 | |||
688 | ReferenceShape(newShape); | ||
689 | |||
690 | prim.PhysShape = newShape; | ||
691 | return true; // 'true' means a new shape has been added to this prim | ||
692 | } | 283 | } |
693 | 284 | ||
694 | List<ConvexResult> m_hulls; | 285 | // Track another user of a body. |
695 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 286 | // We presume the caller has allocated the body. |
287 | // Bodies only have one user so the body is just put into the world if not already there. | ||
288 | private void ReferenceBody(BulletBody body) | ||
696 | { | 289 | { |
697 | 290 | lock (m_collectionActivityLock) | |
698 | BulletShape newShape = new BulletShape(); | ||
699 | IntPtr hullPtr = IntPtr.Zero; | ||
700 | |||
701 | HullDesc hullDesc; | ||
702 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | ||
703 | { | ||
704 | // If the hull shape already is created, just use it. | ||
705 | newShape = hullDesc.shape.Clone(); | ||
706 | } | ||
707 | else | ||
708 | { | 291 | { |
709 | // Build a new hull in the physical world | 292 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
710 | // Pass true for physicalness as this creates some sort of bounding box which we don't need | 293 | if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) |
711 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); | ||
712 | if (meshData != null) | ||
713 | { | 294 | { |
714 | 295 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); | |
715 | int[] indices = meshData.getIndexListAsInt(); | 296 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
716 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
717 | |||
718 | //format conversion from IMesh format to DecompDesc format | ||
719 | List<int> convIndices = new List<int>(); | ||
720 | List<float3> convVertices = new List<float3>(); | ||
721 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
722 | { | ||
723 | convIndices.Add(indices[ii]); | ||
724 | } | ||
725 | foreach (OMV.Vector3 vv in vertices) | ||
726 | { | ||
727 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
728 | } | ||
729 | |||
730 | // setup and do convex hull conversion | ||
731 | m_hulls = new List<ConvexResult>(); | ||
732 | DecompDesc dcomp = new DecompDesc(); | ||
733 | dcomp.mIndices = convIndices; | ||
734 | dcomp.mVertices = convVertices; | ||
735 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
736 | // create the hull into the _hulls variable | ||
737 | convexBuilder.process(dcomp); | ||
738 | |||
739 | // Convert the vertices and indices for passing to unmanaged. | ||
740 | // The hull information is passed as a large floating point array. | ||
741 | // The format is: | ||
742 | // convHulls[0] = number of hulls | ||
743 | // convHulls[1] = number of vertices in first hull | ||
744 | // convHulls[2] = hull centroid X coordinate | ||
745 | // convHulls[3] = hull centroid Y coordinate | ||
746 | // convHulls[4] = hull centroid Z coordinate | ||
747 | // convHulls[5] = first hull vertex X | ||
748 | // convHulls[6] = first hull vertex Y | ||
749 | // convHulls[7] = first hull vertex Z | ||
750 | // convHulls[8] = second hull vertex X | ||
751 | // ... | ||
752 | // convHulls[n] = number of vertices in second hull | ||
753 | // convHulls[n+1] = second hull centroid X coordinate | ||
754 | // ... | ||
755 | // | ||
756 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
757 | // data structures that do not need to be converted in order to pass to Bullet. | ||
758 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
759 | int hullCount = m_hulls.Count; | ||
760 | int totalVertices = 1; // include one for the count of the hulls | ||
761 | foreach (ConvexResult cr in m_hulls) | ||
762 | { | ||
763 | totalVertices += 4; // add four for the vertex count and centroid | ||
764 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
765 | } | ||
766 | float[] convHulls = new float[totalVertices]; | ||
767 | |||
768 | convHulls[0] = (float)hullCount; | ||
769 | int jj = 1; | ||
770 | foreach (ConvexResult cr in m_hulls) | ||
771 | { | ||
772 | // copy vertices for index access | ||
773 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
774 | int kk = 0; | ||
775 | foreach (float3 ff in cr.HullVertices) | ||
776 | { | ||
777 | verts[kk++] = ff; | ||
778 | } | ||
779 | |||
780 | // add to the array one hull's worth of data | ||
781 | convHulls[jj++] = cr.HullIndices.Count; | ||
782 | convHulls[jj++] = 0f; // centroid x,y,z | ||
783 | convHulls[jj++] = 0f; | ||
784 | convHulls[jj++] = 0f; | ||
785 | foreach (int ind in cr.HullIndices) | ||
786 | { | ||
787 | convHulls[jj++] = verts[ind].x; | ||
788 | convHulls[jj++] = verts[ind].y; | ||
789 | convHulls[jj++] = verts[ind].z; | ||
790 | } | ||
791 | } | ||
792 | // create the hull data structure in Bullet | ||
793 | newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls); | ||
794 | } | 297 | } |
795 | } | 298 | } |
796 | |||
797 | newShape.shapeKey = newHullKey; | ||
798 | |||
799 | return newShape; | ||
800 | } | 299 | } |
801 | 300 | ||
802 | // Callback from convex hull creater with a newly created hull. | 301 | // Release the usage of a body. |
803 | // Just add it to our collection of hulls for this shape. | 302 | // Called when releasing use of a BSBody. BSShape is handled separately. |
804 | private void HullReturn(ConvexResult result) | 303 | // Called in taint time. |
805 | { | 304 | public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) |
806 | m_hulls.Add(result); | ||
807 | return; | ||
808 | } | ||
809 | |||
810 | // Compound shapes are always built from scratch. | ||
811 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | ||
812 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
813 | { | 305 | { |
814 | // Remove reference to the old shape | 306 | if (!body.HasPhysicalBody) |
815 | // Don't need to do this as the shape is freed when the new root shape is created below. | 307 | return; |
816 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
817 | 308 | ||
309 | m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody"); | ||
818 | 310 | ||
819 | BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false); | 311 | lock (m_collectionActivityLock) |
312 | { | ||
313 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); | ||
314 | // If the caller needs to know the old body is going away, pass the event up. | ||
315 | if (bodyCallback != null) | ||
316 | bodyCallback(body, null); | ||
820 | 317 | ||
821 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 318 | // Removing an object not in the world is a NOOP |
822 | CreateGeomMeshOrHull(prim, shapeCallback); | 319 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); |
823 | PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity); | ||
824 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | ||
825 | prim.LocalID, cShape, prim.PhysShape); | ||
826 | 320 | ||
827 | prim.PhysShape = cShape; | 321 | // Zero any reference to the shape so it is not freed when the body is deleted. |
322 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); | ||
828 | 323 | ||
829 | return true; | 324 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); |
830 | } | ||
831 | |||
832 | // Create a hash of all the shape parameters to be used as a key | ||
833 | // for this particular shape. | ||
834 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
835 | { | ||
836 | // level of detail based on size and type of the object | ||
837 | float lod = BSParam.MeshLOD; | ||
838 | if (pbs.SculptEntry) | ||
839 | lod = BSParam.SculptLOD; | ||
840 | |||
841 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
842 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
843 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
844 | lod = BSParam.MeshMegaPrimLOD; | ||
845 | |||
846 | retLod = lod; | ||
847 | return pbs.GetMeshKey(size, lod); | ||
848 | } | ||
849 | // For those who don't want the LOD | ||
850 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) | ||
851 | { | ||
852 | float lod; | ||
853 | return ComputeShapeKey(size, pbs, out lod); | ||
854 | } | ||
855 | |||
856 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
857 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
858 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
859 | // The first case causes the asset to be fetched. The second case requires | ||
860 | // us to not loop forever. | ||
861 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
862 | // just return. | ||
863 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | ||
864 | { | ||
865 | // If the shape was successfully created, nothing more to do | ||
866 | if (newShape.HasPhysicalShape) | ||
867 | return newShape; | ||
868 | |||
869 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
870 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) | ||
871 | { | ||
872 | prim.LastAssetBuildFailed = true; | ||
873 | BSPhysObject xprim = prim; | ||
874 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | ||
875 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); | ||
876 | Util.FireAndForget(delegate | ||
877 | { | ||
878 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
879 | if (assetProvider != null) | ||
880 | { | ||
881 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
882 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
883 | { | ||
884 | if (!yprim.BaseShape.SculptEntry) | ||
885 | return; | ||
886 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
887 | return; | ||
888 | |||
889 | yprim.BaseShape.SculptData = asset.Data; | ||
890 | // This will cause the prim to see that the filler shape is not the right | ||
891 | // one and try again to build the object. | ||
892 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
893 | yprim.ForceBodyShapeRebuild(false); | ||
894 | |||
895 | }); | ||
896 | } | ||
897 | }); | ||
898 | } | ||
899 | else | ||
900 | { | ||
901 | if (prim.LastAssetBuildFailed) | ||
902 | { | ||
903 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", | ||
904 | LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); | ||
905 | } | ||
906 | } | 325 | } |
907 | |||
908 | // While we figure out the real problem, stick a simple native shape on the object. | ||
909 | BulletShape fillinShape = | ||
910 | BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
911 | |||
912 | return fillinShape; | ||
913 | } | 326 | } |
914 | 327 | ||
915 | // Create a body object in Bullet. | 328 | // Create a body object in Bullet. |
916 | // Updates prim.BSBody with the information about the new body if one is created. | 329 | // Updates prim.BSBody with the information about the new body if one is created. |
917 | // Returns 'true' if an object was actually created. | 330 | // Returns 'true' if an object was actually created. |
918 | // Called at taint-time. | 331 | // Called at taint-time. |
919 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape, | 332 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) |
920 | BodyDestructionCallback bodyCallback) | ||
921 | { | 333 | { |
922 | bool ret = false; | 334 | bool ret = false; |
923 | 335 | ||
@@ -928,33 +340,34 @@ public sealed class BSShapeCollection : IDisposable | |||
928 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 340 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
929 | if (!mustRebuild) | 341 | if (!mustRebuild) |
930 | { | 342 | { |
931 | CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody); | 343 | CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); |
932 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 344 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
933 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 345 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
934 | { | 346 | { |
935 | // If the collisionObject is not the correct type for solidness, rebuild what's there | 347 | // If the collisionObject is not the correct type for solidness, rebuild what's there |
936 | mustRebuild = true; | 348 | mustRebuild = true; |
349 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); | ||
937 | } | 350 | } |
938 | } | 351 | } |
939 | 352 | ||
940 | if (mustRebuild || forceRebuild) | 353 | if (mustRebuild || forceRebuild) |
941 | { | 354 | { |
942 | // Free any old body | 355 | // Free any old body |
943 | DereferenceBody(prim.PhysBody, true, bodyCallback); | 356 | DereferenceBody(prim.PhysBody, bodyCallback); |
944 | 357 | ||
945 | BulletBody aBody; | 358 | BulletBody aBody; |
946 | if (prim.IsSolid) | 359 | if (prim.IsSolid) |
947 | { | 360 | { |
948 | aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 361 | aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
949 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody); | 362 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); |
950 | } | 363 | } |
951 | else | 364 | else |
952 | { | 365 | { |
953 | aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation); | 366 | aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); |
954 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); | 367 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); |
955 | } | 368 | } |
956 | 369 | ||
957 | ReferenceBody(aBody, true); | 370 | ReferenceBody(aBody); |
958 | 371 | ||
959 | prim.PhysBody = aBody; | 372 | prim.PhysBody = aBody; |
960 | 373 | ||
@@ -964,46 +377,10 @@ public sealed class BSShapeCollection : IDisposable | |||
964 | return ret; | 377 | return ret; |
965 | } | 378 | } |
966 | 379 | ||
967 | private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc) | ||
968 | { | ||
969 | bool ret = false; | ||
970 | MeshDesc foundDesc = new MeshDesc(); | ||
971 | foreach (MeshDesc md in Meshes.Values) | ||
972 | { | ||
973 | if (md.shape.ReferenceSame(shape)) | ||
974 | { | ||
975 | foundDesc = md; | ||
976 | ret = true; | ||
977 | break; | ||
978 | } | ||
979 | |||
980 | } | ||
981 | outDesc = foundDesc; | ||
982 | return ret; | ||
983 | } | ||
984 | |||
985 | private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc) | ||
986 | { | ||
987 | bool ret = false; | ||
988 | HullDesc foundDesc = new HullDesc(); | ||
989 | foreach (HullDesc hd in Hulls.Values) | ||
990 | { | ||
991 | if (hd.shape.ReferenceSame(shape)) | ||
992 | { | ||
993 | foundDesc = hd; | ||
994 | ret = true; | ||
995 | break; | ||
996 | } | ||
997 | |||
998 | } | ||
999 | outDesc = foundDesc; | ||
1000 | return ret; | ||
1001 | } | ||
1002 | |||
1003 | private void DetailLog(string msg, params Object[] args) | 380 | private void DetailLog(string msg, params Object[] args) |
1004 | { | 381 | { |
1005 | if (PhysicsScene.PhysicsLogging.Enabled) | 382 | if (m_physicsScene.PhysicsLogging.Enabled) |
1006 | PhysicsScene.DetailLog(msg, args); | 383 | m_physicsScene.DetailLog(msg, args); |
1007 | } | 384 | } |
1008 | } | 385 | } |
1009 | } | 386 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs index c75eb9b..9d47657 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs | |||
@@ -27,118 +27,287 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Text; | 30 | using System.Text; |
32 | 31 | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | using OpenSim.Region.Physics.ConvexDecompositionDotNet; | ||
35 | |||
36 | using OMV = OpenMetaverse; | ||
37 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 38 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 39 | { |
35 | public abstract class BSShape | 40 | public abstract class BSShape |
36 | { | 41 | { |
37 | public IntPtr ptr { get; set; } | 42 | private static string LogHeader = "[BULLETSIM SHAPE]"; |
38 | public BSPhysicsShapeType type { get; set; } | 43 | |
39 | public System.UInt64 key { get; set; } | ||
40 | public int referenceCount { get; set; } | 44 | public int referenceCount { get; set; } |
41 | public DateTime lastReferenced { get; set; } | 45 | public DateTime lastReferenced { get; set; } |
46 | public BulletShape physShapeInfo { get; set; } | ||
42 | 47 | ||
43 | public BSShape() | 48 | public BSShape() |
44 | { | 49 | { |
45 | ptr = IntPtr.Zero; | 50 | referenceCount = 1; |
46 | type = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
47 | key = 0; | ||
48 | referenceCount = 0; | ||
49 | lastReferenced = DateTime.Now; | 51 | lastReferenced = DateTime.Now; |
52 | physShapeInfo = new BulletShape(); | ||
50 | } | 53 | } |
51 | 54 | public BSShape(BulletShape pShape) | |
52 | // Get a reference to a physical shape. Create if it doesn't exist | ||
53 | public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
54 | { | 55 | { |
55 | BSShape ret = null; | 56 | referenceCount = 1; |
56 | 57 | lastReferenced = DateTime.Now; | |
57 | if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 58 | physShapeInfo = pShape; |
58 | { | 59 | } |
59 | // an avatar capsule is close to a native shape (it is not shared) | ||
60 | ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE, | ||
61 | FixedShapeKey.KEY_CAPSULE); | ||
62 | physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret); | ||
63 | } | ||
64 | |||
65 | // Compound shapes are handled special as they are rebuilt from scratch. | ||
66 | // This isn't too great a hardship since most of the child shapes will already been created. | ||
67 | if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | ||
68 | { | ||
69 | // Getting a reference to a compound shape gets you the compound shape with the root prim shape added | ||
70 | ret = BSShapeCompound.GetReference(prim); | ||
71 | physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret); | ||
72 | } | ||
73 | 60 | ||
74 | if (ret == null) | 61 | // Get another reference to this shape. |
75 | ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim); | 62 | public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); |
76 | 63 | ||
77 | return ret; | 64 | // Called when this shape is being used again. |
78 | } | 65 | // Used internally. External callers should call instance.GetReference() to properly copy/reference |
79 | public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 66 | // the shape. |
67 | protected virtual void IncrementReference() | ||
80 | { | 68 | { |
81 | return null; | 69 | referenceCount++; |
70 | lastReferenced = DateTime.Now; | ||
82 | } | 71 | } |
83 | public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | 72 | |
73 | // Called when this shape is being used again. | ||
74 | protected virtual void DecrementReference() | ||
84 | { | 75 | { |
85 | return null; | 76 | referenceCount--; |
77 | lastReferenced = DateTime.Now; | ||
86 | } | 78 | } |
87 | 79 | ||
88 | // Release the use of a physical shape. | 80 | // Release the use of a physical shape. |
89 | public abstract void Dereference(BSScene physicsScene); | 81 | public abstract void Dereference(BSScene physicsScene); |
90 | 82 | ||
91 | // All shapes have a static call to get a reference to the physical shape | 83 | // Return 'true' if there is an allocated physics physical shape under this class instance. |
92 | // protected abstract static BSShape GetReference(); | 84 | public virtual bool HasPhysicalShape |
85 | { | ||
86 | get | ||
87 | { | ||
88 | if (physShapeInfo != null) | ||
89 | return physShapeInfo.HasPhysicalShape; | ||
90 | return false; | ||
91 | } | ||
92 | } | ||
93 | public virtual BSPhysicsShapeType ShapeType | ||
94 | { | ||
95 | get | ||
96 | { | ||
97 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
98 | if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) | ||
99 | ret = physShapeInfo.shapeType; | ||
100 | return ret; | ||
101 | } | ||
102 | } | ||
93 | 103 | ||
94 | // Returns a string for debugging that uniquily identifies the memory used by this instance | 104 | // Returns a string for debugging that uniquily identifies the memory used by this instance |
95 | public string AddrString | 105 | public virtual string AddrString |
96 | { | 106 | { |
97 | get { return ptr.ToString("X"); } | 107 | get |
108 | { | ||
109 | if (physShapeInfo != null) | ||
110 | return physShapeInfo.AddrString; | ||
111 | return "unknown"; | ||
112 | } | ||
98 | } | 113 | } |
99 | 114 | ||
100 | public override string ToString() | 115 | public override string ToString() |
101 | { | 116 | { |
102 | StringBuilder buff = new StringBuilder(); | 117 | StringBuilder buff = new StringBuilder(); |
103 | buff.Append("<p="); | 118 | if (physShapeInfo == null) |
104 | buff.Append(AddrString); | 119 | { |
105 | buff.Append(",s="); | 120 | buff.Append("<noPhys"); |
106 | buff.Append(type.ToString()); | 121 | } |
107 | buff.Append(",k="); | 122 | else |
108 | buff.Append(key.ToString("X")); | 123 | { |
124 | buff.Append("<phy="); | ||
125 | buff.Append(physShapeInfo.ToString()); | ||
126 | } | ||
109 | buff.Append(",c="); | 127 | buff.Append(",c="); |
110 | buff.Append(referenceCount.ToString()); | 128 | buff.Append(referenceCount.ToString()); |
111 | buff.Append(">"); | 129 | buff.Append(">"); |
112 | return buff.ToString(); | 130 | return buff.ToString(); |
113 | } | 131 | } |
132 | |||
133 | #region Common shape routines | ||
134 | // Create a hash of all the shape parameters to be used as a key for this particular shape. | ||
135 | public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) | ||
136 | { | ||
137 | // level of detail based on size and type of the object | ||
138 | float lod = BSParam.MeshLOD; | ||
139 | if (pbs.SculptEntry) | ||
140 | lod = BSParam.SculptLOD; | ||
141 | |||
142 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
143 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); | ||
144 | if (maxAxis > BSParam.MeshMegaPrimThreshold) | ||
145 | lod = BSParam.MeshMegaPrimLOD; | ||
146 | |||
147 | retLod = lod; | ||
148 | return pbs.GetMeshKey(size, lod); | ||
149 | } | ||
150 | |||
151 | // The creation of a mesh or hull can fail if an underlying asset is not available. | ||
152 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | ||
153 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). | ||
154 | // The first case causes the asset to be fetched. The second case requires | ||
155 | // us to not loop forever. | ||
156 | // Called after creating a physical mesh or hull. If the physical shape was created, | ||
157 | // just return. | ||
158 | public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) | ||
159 | { | ||
160 | // If the shape was successfully created, nothing more to do | ||
161 | if (newShape.HasPhysicalShape) | ||
162 | return newShape; | ||
163 | |||
164 | // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been | ||
165 | // fetched but we end up here again, the meshing of the asset must have failed. | ||
166 | // Prevent trying to keep fetching the mesh by declaring failure. | ||
167 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
168 | { | ||
169 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
170 | physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}", | ||
171 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
172 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}", | ||
173 | prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
178 | if (prim.BaseShape.SculptEntry | ||
179 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed | ||
180 | && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting | ||
181 | && prim.BaseShape.SculptTexture != OMV.UUID.Zero | ||
182 | ) | ||
183 | { | ||
184 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", | ||
185 | prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
186 | // Multiple requestors will know we're waiting for this asset | ||
187 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; | ||
188 | |||
189 | BSPhysObject xprim = prim; | ||
190 | Util.FireAndForget(delegate | ||
191 | { | ||
192 | // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID); | ||
193 | RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; | ||
194 | if (assetProvider != null) | ||
195 | { | ||
196 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
197 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
198 | { | ||
199 | // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); | ||
200 | bool assetFound = false; | ||
201 | string mismatchIDs = String.Empty; // DEBUG DEBUG | ||
202 | if (asset != null && yprim.BaseShape.SculptEntry) | ||
203 | { | ||
204 | if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) | ||
205 | { | ||
206 | yprim.BaseShape.SculptData = asset.Data; | ||
207 | // This will cause the prim to see that the filler shape is not the right | ||
208 | // one and try again to build the object. | ||
209 | // No race condition with the normal shape setting since the rebuild is at taint time. | ||
210 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; | ||
211 | yprim.ForceBodyShapeRebuild(false /* inTaintTime */); | ||
212 | assetFound = true; | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; | ||
217 | } | ||
218 | } | ||
219 | if (!assetFound) | ||
220 | { | ||
221 | yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
222 | } | ||
223 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", | ||
224 | yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); | ||
225 | }); | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed; | ||
230 | physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", | ||
231 | LogHeader, physicsScene.Name); | ||
232 | } | ||
233 | }); | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed) | ||
238 | { | ||
239 | physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}", | ||
240 | LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
241 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}", | ||
242 | prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. | ||
248 | BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); | ||
249 | physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); | ||
250 | |||
251 | return fillShape.physShapeInfo; | ||
252 | } | ||
253 | |||
254 | #endregion // Common shape routines | ||
114 | } | 255 | } |
115 | 256 | ||
257 | // ============================================================================================================ | ||
116 | public class BSShapeNull : BSShape | 258 | public class BSShapeNull : BSShape |
117 | { | 259 | { |
118 | public BSShapeNull() : base() | 260 | public BSShapeNull() : base() |
119 | { | 261 | { |
120 | } | 262 | } |
121 | public static BSShape GetReference() { return new BSShapeNull(); } | 263 | public static BSShape GetReference() { return new BSShapeNull(); } |
264 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } | ||
122 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } | 265 | public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } |
123 | } | 266 | } |
124 | 267 | ||
268 | // ============================================================================================================ | ||
125 | public class BSShapeNative : BSShape | 269 | public class BSShapeNative : BSShape |
126 | { | 270 | { |
127 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; | 271 | private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; |
128 | public BSShapeNative() : base() | 272 | public BSShapeNative(BulletShape pShape) : base(pShape) |
129 | { | 273 | { |
130 | } | 274 | } |
131 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, | 275 | |
132 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 276 | public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, |
277 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
133 | { | 278 | { |
134 | // Native shapes are not shared and are always built anew. | 279 | // Native shapes are not shared and are always built anew. |
135 | //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); | 280 | return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); |
136 | return null; | 281 | } |
282 | |||
283 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
284 | { | ||
285 | // Native shapes are not shared so we return a new shape. | ||
286 | return new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, | ||
287 | physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey) ); | ||
137 | } | 288 | } |
138 | 289 | ||
139 | private BSShapeNative(BSScene physicsScene, BSPhysObject prim, | 290 | // Make this reference to the physical shape go away since native shapes are not shared. |
140 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | 291 | public override void Dereference(BSScene physicsScene) |
141 | { | 292 | { |
293 | // Native shapes are not tracked and are released immediately | ||
294 | lock (physShapeInfo) | ||
295 | { | ||
296 | if (physShapeInfo.HasPhysicalShape) | ||
297 | { | ||
298 | physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
299 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
300 | } | ||
301 | physShapeInfo.Clear(); | ||
302 | // Garbage collection will free up this instance. | ||
303 | } | ||
304 | } | ||
305 | |||
306 | private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, | ||
307 | BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) | ||
308 | { | ||
309 | BulletShape newShape; | ||
310 | |||
142 | ShapeData nativeShapeData = new ShapeData(); | 311 | ShapeData nativeShapeData = new ShapeData(); |
143 | nativeShapeData.Type = shapeType; | 312 | nativeShapeData.Type = shapeType; |
144 | nativeShapeData.ID = prim.LocalID; | 313 | nativeShapeData.ID = prim.LocalID; |
@@ -147,86 +316,760 @@ public class BSShapeNative : BSShape | |||
147 | nativeShapeData.MeshKey = (ulong)shapeKey; | 316 | nativeShapeData.MeshKey = (ulong)shapeKey; |
148 | nativeShapeData.HullKey = (ulong)shapeKey; | 317 | nativeShapeData.HullKey = (ulong)shapeKey; |
149 | 318 | ||
150 | |||
151 | /* | ||
152 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) | 319 | if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) |
153 | { | 320 | { |
154 | ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); | 321 | newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); |
155 | physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 322 | physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); |
156 | } | 323 | } |
157 | else | 324 | else |
158 | { | 325 | { |
159 | ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); | 326 | newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); |
160 | } | 327 | } |
161 | if (ptr == IntPtr.Zero) | 328 | if (!newShape.HasPhysicalShape) |
162 | { | 329 | { |
163 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 330 | physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
164 | LogHeader, prim.LocalID, shapeType); | 331 | LogHeader, prim.LocalID, shapeType); |
165 | } | 332 | } |
166 | type = shapeType; | 333 | newShape.shapeType = shapeType; |
167 | key = (UInt64)shapeKey; | 334 | newShape.isNativeShape = true; |
168 | */ | 335 | newShape.shapeKey = (UInt64)shapeKey; |
169 | } | 336 | return newShape; |
170 | // Make this reference to the physical shape go away since native shapes are not shared. | ||
171 | public override void Dereference(BSScene physicsScene) | ||
172 | { | ||
173 | /* | ||
174 | // Native shapes are not tracked and are released immediately | ||
175 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); | ||
176 | PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this); | ||
177 | ptr = IntPtr.Zero; | ||
178 | // Garbage collection will free up this instance. | ||
179 | */ | ||
180 | } | 337 | } |
338 | |||
181 | } | 339 | } |
182 | 340 | ||
341 | // ============================================================================================================ | ||
183 | public class BSShapeMesh : BSShape | 342 | public class BSShapeMesh : BSShape |
184 | { | 343 | { |
185 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; | 344 | private static string LogHeader = "[BULLETSIM SHAPE MESH]"; |
186 | private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); | 345 | public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>(); |
187 | 346 | ||
188 | public BSShapeMesh() : base() | 347 | public BSShapeMesh(BulletShape pShape) : base(pShape) |
189 | { | 348 | { |
190 | } | 349 | } |
191 | public static BSShape GetReference() { return new BSShapeNull(); } | 350 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
192 | public override void Dereference(BSScene physicsScene) { } | 351 | { |
352 | float lod; | ||
353 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
354 | |||
355 | BSShapeMesh retMesh = null; | ||
356 | lock (Meshes) | ||
357 | { | ||
358 | if (Meshes.TryGetValue(newMeshKey, out retMesh)) | ||
359 | { | ||
360 | // The mesh has already been created. Return a new reference to same. | ||
361 | retMesh.IncrementReference(); | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | retMesh = new BSShapeMesh(new BulletShape()); | ||
366 | // An instance of this mesh has not been created. Build and remember same. | ||
367 | BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); | ||
368 | |||
369 | // Check to see if mesh was created (might require an asset). | ||
370 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
371 | if (!newShape.isNativeShape) | ||
372 | { | ||
373 | // If a mesh was what was created, remember the built shape for later sharing. | ||
374 | Meshes.Add(newMeshKey, retMesh); | ||
375 | } | ||
376 | |||
377 | retMesh.physShapeInfo = newShape; | ||
378 | } | ||
379 | } | ||
380 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); | ||
381 | return retMesh; | ||
382 | } | ||
383 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
384 | { | ||
385 | // Another reference to this shape is just counted. | ||
386 | IncrementReference(); | ||
387 | return this; | ||
388 | } | ||
389 | public override void Dereference(BSScene physicsScene) | ||
390 | { | ||
391 | lock (Meshes) | ||
392 | { | ||
393 | this.DecrementReference(); | ||
394 | physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
395 | // TODO: schedule aging and destruction of unused meshes. | ||
396 | } | ||
397 | } | ||
398 | // Loop through all the known meshes and return the description based on the physical address. | ||
399 | public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) | ||
400 | { | ||
401 | bool ret = false; | ||
402 | BSShapeMesh foundDesc = null; | ||
403 | lock (Meshes) | ||
404 | { | ||
405 | foreach (BSShapeMesh sm in Meshes.Values) | ||
406 | { | ||
407 | if (sm.physShapeInfo.ReferenceSame(pShape)) | ||
408 | { | ||
409 | foundDesc = sm; | ||
410 | ret = true; | ||
411 | break; | ||
412 | } | ||
413 | |||
414 | } | ||
415 | } | ||
416 | outMesh = foundDesc; | ||
417 | return ret; | ||
418 | } | ||
419 | private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, | ||
420 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
421 | { | ||
422 | BulletShape newShape = new BulletShape(); | ||
423 | |||
424 | IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, | ||
425 | false, // say it is not physical so a bounding box is not built | ||
426 | false // do not cache the mesh and do not use previously built versions | ||
427 | ); | ||
428 | |||
429 | if (meshData != null) | ||
430 | { | ||
431 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
432 | { | ||
433 | // Release the fetched asset data once it has been used. | ||
434 | pbs.SculptData = new byte[0]; | ||
435 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
436 | } | ||
437 | |||
438 | int[] indices = meshData.getIndexListAsInt(); | ||
439 | int realIndicesIndex = indices.Length; | ||
440 | float[] verticesAsFloats = meshData.getVertexListAsFloat(); | ||
441 | |||
442 | if (BSParam.ShouldRemoveZeroWidthTriangles) | ||
443 | { | ||
444 | // Remove degenerate triangles. These are triangles with two of the vertices | ||
445 | // are the same. This is complicated by the problem that vertices are not | ||
446 | // made unique in sculpties so we have to compare the values in the vertex. | ||
447 | realIndicesIndex = 0; | ||
448 | for (int tri = 0; tri < indices.Length; tri += 3) | ||
449 | { | ||
450 | // Compute displacements into vertex array for each vertex of the triangle | ||
451 | int v1 = indices[tri + 0] * 3; | ||
452 | int v2 = indices[tri + 1] * 3; | ||
453 | int v3 = indices[tri + 2] * 3; | ||
454 | // Check to see if any two of the vertices are the same | ||
455 | if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] | ||
456 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] | ||
457 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) | ||
458 | || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] | ||
459 | && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] | ||
460 | && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) | ||
461 | || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] | ||
462 | && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] | ||
463 | && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) | ||
464 | ) | ||
465 | { | ||
466 | // None of the vertices of the triangles are the same. This is a good triangle; | ||
467 | indices[realIndicesIndex + 0] = indices[tri + 0]; | ||
468 | indices[realIndicesIndex + 1] = indices[tri + 1]; | ||
469 | indices[realIndicesIndex + 2] = indices[tri + 2]; | ||
470 | realIndicesIndex += 3; | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", | ||
475 | BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); | ||
476 | |||
477 | if (realIndicesIndex != 0) | ||
478 | { | ||
479 | newShape = physicsScene.PE.CreateMeshShape(physicsScene.World, | ||
480 | realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim {1} at {2} in {3}", | ||
485 | LogHeader, prim.PhysObjectName, prim.RawPosition, physicsScene.Name); | ||
486 | } | ||
487 | } | ||
488 | newShape.shapeKey = newMeshKey; | ||
489 | |||
490 | return newShape; | ||
491 | } | ||
193 | } | 492 | } |
194 | 493 | ||
494 | // ============================================================================================================ | ||
195 | public class BSShapeHull : BSShape | 495 | public class BSShapeHull : BSShape |
196 | { | 496 | { |
197 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; | 497 | private static string LogHeader = "[BULLETSIM SHAPE HULL]"; |
198 | private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); | 498 | public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>(); |
199 | 499 | ||
200 | public BSShapeHull() : base() | 500 | public BSShapeHull(BulletShape pShape) : base(pShape) |
201 | { | 501 | { |
202 | } | 502 | } |
203 | public static BSShape GetReference() { return new BSShapeNull(); } | 503 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) |
204 | public override void Dereference(BSScene physicsScene) { } | 504 | { |
505 | float lod; | ||
506 | System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
507 | |||
508 | BSShapeHull retHull = null; | ||
509 | lock (Hulls) | ||
510 | { | ||
511 | if (Hulls.TryGetValue(newHullKey, out retHull)) | ||
512 | { | ||
513 | // The mesh has already been created. Return a new reference to same. | ||
514 | retHull.IncrementReference(); | ||
515 | } | ||
516 | else | ||
517 | { | ||
518 | retHull = new BSShapeHull(new BulletShape()); | ||
519 | // An instance of this mesh has not been created. Build and remember same. | ||
520 | BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); | ||
521 | |||
522 | // Check to see if hull was created (might require an asset). | ||
523 | newShape = VerifyMeshCreated(physicsScene, newShape, prim); | ||
524 | if (!newShape.isNativeShape) | ||
525 | { | ||
526 | // If a mesh was what was created, remember the built shape for later sharing. | ||
527 | Hulls.Add(newHullKey, retHull); | ||
528 | } | ||
529 | retHull.physShapeInfo = newShape; | ||
530 | } | ||
531 | } | ||
532 | physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); | ||
533 | return retHull; | ||
534 | } | ||
535 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
536 | { | ||
537 | // Another reference to this shape is just counted. | ||
538 | IncrementReference(); | ||
539 | return this; | ||
540 | } | ||
541 | public override void Dereference(BSScene physicsScene) | ||
542 | { | ||
543 | lock (Hulls) | ||
544 | { | ||
545 | this.DecrementReference(); | ||
546 | physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
547 | // TODO: schedule aging and destruction of unused meshes. | ||
548 | } | ||
549 | } | ||
550 | List<ConvexResult> m_hulls; | ||
551 | private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, | ||
552 | PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | ||
553 | { | ||
554 | BulletShape newShape = new BulletShape(); | ||
555 | IntPtr hullPtr = IntPtr.Zero; | ||
556 | |||
557 | if (BSParam.ShouldUseBulletHACD) | ||
558 | { | ||
559 | // Build the hull shape from an existing mesh shape. | ||
560 | // The mesh should have already been created in Bullet. | ||
561 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,entry", prim.LocalID); | ||
562 | BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); | ||
563 | |||
564 | if (meshShape.physShapeInfo.HasPhysicalShape) | ||
565 | { | ||
566 | HACDParams parms; | ||
567 | parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; | ||
568 | parms.minClusters = BSParam.BHullMinClusters; | ||
569 | parms.compacityWeight = BSParam.BHullCompacityWeight; | ||
570 | parms.volumeWeight = BSParam.BHullVolumeWeight; | ||
571 | parms.concavity = BSParam.BHullConcavity; | ||
572 | parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); | ||
573 | parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); | ||
574 | parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); | ||
575 | parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); | ||
576 | |||
577 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); | ||
578 | newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); | ||
579 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
580 | |||
581 | // Now done with the mesh shape. | ||
582 | meshShape.Dereference(physicsScene); | ||
583 | } | ||
584 | physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,shouldUseBulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); | ||
585 | } | ||
586 | if (!newShape.HasPhysicalShape) | ||
587 | { | ||
588 | // Build a new hull in the physical world using the C# HACD algorigthm. | ||
589 | // Pass true for physicalness as this prevents the creation of bounding box which is not needed | ||
590 | IMesh meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */); | ||
591 | if (meshData != null) | ||
592 | { | ||
593 | if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) | ||
594 | { | ||
595 | // Release the fetched asset data once it has been used. | ||
596 | pbs.SculptData = new byte[0]; | ||
597 | prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; | ||
598 | } | ||
599 | |||
600 | int[] indices = meshData.getIndexListAsInt(); | ||
601 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
602 | |||
603 | //format conversion from IMesh format to DecompDesc format | ||
604 | List<int> convIndices = new List<int>(); | ||
605 | List<float3> convVertices = new List<float3>(); | ||
606 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
607 | { | ||
608 | convIndices.Add(indices[ii]); | ||
609 | } | ||
610 | foreach (OMV.Vector3 vv in vertices) | ||
611 | { | ||
612 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
613 | } | ||
614 | |||
615 | uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; | ||
616 | if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) | ||
617 | { | ||
618 | // Simple primitive shapes we know are convex so they are better implemented with | ||
619 | // fewer hulls. | ||
620 | // Check for simple shape (prim without cuts) and reduce split parameter if so. | ||
621 | if (BSShapeCollection.PrimHasNoCuts(pbs)) | ||
622 | { | ||
623 | maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | // setup and do convex hull conversion | ||
628 | m_hulls = new List<ConvexResult>(); | ||
629 | DecompDesc dcomp = new DecompDesc(); | ||
630 | dcomp.mIndices = convIndices; | ||
631 | dcomp.mVertices = convVertices; | ||
632 | dcomp.mDepth = maxDepthSplit; | ||
633 | dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; | ||
634 | dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; | ||
635 | dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; | ||
636 | dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; | ||
637 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
638 | // create the hull into the _hulls variable | ||
639 | convexBuilder.process(dcomp); | ||
640 | |||
641 | physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", | ||
642 | BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); | ||
643 | |||
644 | // Convert the vertices and indices for passing to unmanaged. | ||
645 | // The hull information is passed as a large floating point array. | ||
646 | // The format is: | ||
647 | // convHulls[0] = number of hulls | ||
648 | // convHulls[1] = number of vertices in first hull | ||
649 | // convHulls[2] = hull centroid X coordinate | ||
650 | // convHulls[3] = hull centroid Y coordinate | ||
651 | // convHulls[4] = hull centroid Z coordinate | ||
652 | // convHulls[5] = first hull vertex X | ||
653 | // convHulls[6] = first hull vertex Y | ||
654 | // convHulls[7] = first hull vertex Z | ||
655 | // convHulls[8] = second hull vertex X | ||
656 | // ... | ||
657 | // convHulls[n] = number of vertices in second hull | ||
658 | // convHulls[n+1] = second hull centroid X coordinate | ||
659 | // ... | ||
660 | // | ||
661 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
662 | // data structures that do not need to be converted in order to pass to Bullet. | ||
663 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
664 | int hullCount = m_hulls.Count; | ||
665 | int totalVertices = 1; // include one for the count of the hulls | ||
666 | foreach (ConvexResult cr in m_hulls) | ||
667 | { | ||
668 | totalVertices += 4; // add four for the vertex count and centroid | ||
669 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
670 | } | ||
671 | float[] convHulls = new float[totalVertices]; | ||
672 | |||
673 | convHulls[0] = (float)hullCount; | ||
674 | int jj = 1; | ||
675 | foreach (ConvexResult cr in m_hulls) | ||
676 | { | ||
677 | // copy vertices for index access | ||
678 | float3[] verts = new float3[cr.HullVertices.Count]; | ||
679 | int kk = 0; | ||
680 | foreach (float3 ff in cr.HullVertices) | ||
681 | { | ||
682 | verts[kk++] = ff; | ||
683 | } | ||
684 | |||
685 | // add to the array one hull's worth of data | ||
686 | convHulls[jj++] = cr.HullIndices.Count; | ||
687 | convHulls[jj++] = 0f; // centroid x,y,z | ||
688 | convHulls[jj++] = 0f; | ||
689 | convHulls[jj++] = 0f; | ||
690 | foreach (int ind in cr.HullIndices) | ||
691 | { | ||
692 | convHulls[jj++] = verts[ind].x; | ||
693 | convHulls[jj++] = verts[ind].y; | ||
694 | convHulls[jj++] = verts[ind].z; | ||
695 | } | ||
696 | } | ||
697 | // create the hull data structure in Bullet | ||
698 | newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); | ||
699 | } | ||
700 | newShape.shapeKey = newHullKey; | ||
701 | } | ||
702 | return newShape; | ||
703 | } | ||
704 | // Callback from convex hull creater with a newly created hull. | ||
705 | // Just add it to our collection of hulls for this shape. | ||
706 | private void HullReturn(ConvexResult result) | ||
707 | { | ||
708 | m_hulls.Add(result); | ||
709 | return; | ||
710 | } | ||
711 | // Loop through all the known hulls and return the description based on the physical address. | ||
712 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) | ||
713 | { | ||
714 | bool ret = false; | ||
715 | BSShapeHull foundDesc = null; | ||
716 | lock (Hulls) | ||
717 | { | ||
718 | foreach (BSShapeHull sh in Hulls.Values) | ||
719 | { | ||
720 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
721 | { | ||
722 | foundDesc = sh; | ||
723 | ret = true; | ||
724 | break; | ||
725 | } | ||
726 | |||
727 | } | ||
728 | } | ||
729 | outHull = foundDesc; | ||
730 | return ret; | ||
731 | } | ||
205 | } | 732 | } |
206 | 733 | ||
734 | // ============================================================================================================ | ||
207 | public class BSShapeCompound : BSShape | 735 | public class BSShapeCompound : BSShape |
208 | { | 736 | { |
209 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; | 737 | private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; |
210 | public BSShapeCompound() : base() | 738 | public BSShapeCompound(BulletShape pShape) : base(pShape) |
211 | { | 739 | { |
212 | } | 740 | } |
213 | public static BSShape GetReference(BSPhysObject prim) | 741 | public static BSShape GetReference(BSScene physicsScene) |
214 | { | 742 | { |
215 | return new BSShapeNull(); | 743 | // Base compound shapes are not shared so this returns a raw shape. |
744 | // A built compound shape can be reused in linksets. | ||
745 | return new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); | ||
746 | } | ||
747 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
748 | { | ||
749 | // Calling this reference means we want another handle to an existing compound shape | ||
750 | // (usually linksets) so return this copy. | ||
751 | IncrementReference(); | ||
752 | return this; | ||
753 | } | ||
754 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
755 | public override void Dereference(BSScene physicsScene) | ||
756 | { | ||
757 | lock (physShapeInfo) | ||
758 | { | ||
759 | this.DecrementReference(); | ||
760 | physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
761 | if (referenceCount <= 0) | ||
762 | { | ||
763 | if (!physicsScene.PE.IsCompound(physShapeInfo)) | ||
764 | { | ||
765 | // Failed the sanity check!! | ||
766 | physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | ||
767 | LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
768 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | ||
769 | BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); | ||
770 | return; | ||
771 | } | ||
772 | |||
773 | int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); | ||
774 | physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", | ||
775 | BSScene.DetailLogZero, physShapeInfo, numChildren); | ||
776 | |||
777 | // Loop through all the children dereferencing each. | ||
778 | for (int ii = numChildren - 1; ii >= 0; ii--) | ||
779 | { | ||
780 | BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); | ||
781 | DereferenceAnonCollisionShape(physicsScene, childShape); | ||
782 | } | ||
783 | physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) | ||
788 | { | ||
789 | BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); | ||
790 | return cShape; | ||
791 | } | ||
792 | // Sometimes we have a pointer to a collision shape but don't know what type it is. | ||
793 | // Figure out type and call the correct dereference routine. | ||
794 | // Called at taint-time. | ||
795 | private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) | ||
796 | { | ||
797 | BSShapeMesh meshDesc; | ||
798 | if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) | ||
799 | { | ||
800 | meshDesc.Dereference(physicsScene); | ||
801 | } | ||
802 | else | ||
803 | { | ||
804 | BSShapeHull hullDesc; | ||
805 | if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) | ||
806 | { | ||
807 | hullDesc.Dereference(physicsScene); | ||
808 | } | ||
809 | else | ||
810 | { | ||
811 | BSShapeConvexHull chullDesc; | ||
812 | if (BSShapeConvexHull.TryGetHullByPtr(pShape, out chullDesc)) | ||
813 | { | ||
814 | chullDesc.Dereference(physicsScene); | ||
815 | } | ||
816 | else | ||
817 | { | ||
818 | if (physicsScene.PE.IsCompound(pShape)) | ||
819 | { | ||
820 | BSShapeCompound recursiveCompound = new BSShapeCompound(pShape); | ||
821 | recursiveCompound.Dereference(physicsScene); | ||
822 | } | ||
823 | else | ||
824 | { | ||
825 | if (physicsScene.PE.IsNativeShape(pShape)) | ||
826 | { | ||
827 | BSShapeNative nativeShape = new BSShapeNative(pShape); | ||
828 | nativeShape.Dereference(physicsScene); | ||
829 | } | ||
830 | } | ||
831 | } | ||
832 | } | ||
833 | } | ||
216 | } | 834 | } |
217 | public override void Dereference(BSScene physicsScene) { } | ||
218 | } | 835 | } |
219 | 836 | ||
837 | // ============================================================================================================ | ||
838 | public class BSShapeConvexHull : BSShape | ||
839 | { | ||
840 | private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; | ||
841 | public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>(); | ||
842 | |||
843 | public BSShapeConvexHull(BulletShape pShape) : base(pShape) | ||
844 | { | ||
845 | } | ||
846 | public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) | ||
847 | { | ||
848 | float lod; | ||
849 | System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | ||
850 | |||
851 | physicsScene.DetailLog("{0},BSShapeMesh,getReference,newKey={1},size={2},lod={3}", | ||
852 | prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); | ||
853 | |||
854 | BSShapeConvexHull retConvexHull = null; | ||
855 | lock (ConvexHulls) | ||
856 | { | ||
857 | if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) | ||
858 | { | ||
859 | // The mesh has already been created. Return a new reference to same. | ||
860 | retConvexHull.IncrementReference(); | ||
861 | } | ||
862 | else | ||
863 | { | ||
864 | retConvexHull = new BSShapeConvexHull(new BulletShape()); | ||
865 | BulletShape convexShape = null; | ||
866 | |||
867 | // Get a handle to a mesh to build the hull from | ||
868 | BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); | ||
869 | if (baseMesh.physShapeInfo.isNativeShape) | ||
870 | { | ||
871 | // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. | ||
872 | // In the short term, we return the native shape and a later ForceBodyShapeRebuild should | ||
873 | // get back to this code with a buildable mesh. | ||
874 | // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? | ||
875 | convexShape = baseMesh.physShapeInfo; | ||
876 | } | ||
877 | else | ||
878 | { | ||
879 | convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); | ||
880 | convexShape.shapeKey = newMeshKey; | ||
881 | ConvexHulls.Add(convexShape.shapeKey, retConvexHull); | ||
882 | } | ||
883 | |||
884 | // Done with the base mesh | ||
885 | baseMesh.Dereference(physicsScene); | ||
886 | |||
887 | retConvexHull.physShapeInfo = convexShape; | ||
888 | } | ||
889 | } | ||
890 | return retConvexHull; | ||
891 | } | ||
892 | public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) | ||
893 | { | ||
894 | // Calling this reference means we want another handle to an existing shape | ||
895 | // (usually linksets) so return this copy. | ||
896 | IncrementReference(); | ||
897 | return this; | ||
898 | } | ||
899 | // Dereferencing a compound shape releases the hold on all the child shapes. | ||
900 | public override void Dereference(BSScene physicsScene) | ||
901 | { | ||
902 | lock (ConvexHulls) | ||
903 | { | ||
904 | this.DecrementReference(); | ||
905 | physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); | ||
906 | // TODO: schedule aging and destruction of unused meshes. | ||
907 | } | ||
908 | } | ||
909 | // Loop through all the known hulls and return the description based on the physical address. | ||
910 | public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) | ||
911 | { | ||
912 | bool ret = false; | ||
913 | BSShapeConvexHull foundDesc = null; | ||
914 | lock (ConvexHulls) | ||
915 | { | ||
916 | foreach (BSShapeConvexHull sh in ConvexHulls.Values) | ||
917 | { | ||
918 | if (sh.physShapeInfo.ReferenceSame(pShape)) | ||
919 | { | ||
920 | foundDesc = sh; | ||
921 | ret = true; | ||
922 | break; | ||
923 | } | ||
924 | |||
925 | } | ||
926 | } | ||
927 | outHull = foundDesc; | ||
928 | return ret; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | // ============================================================================================================ | ||
220 | public class BSShapeAvatar : BSShape | 933 | public class BSShapeAvatar : BSShape |
221 | { | 934 | { |
222 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; | 935 | private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; |
223 | public BSShapeAvatar() : base() | 936 | public BSShapeAvatar() : base() |
224 | { | 937 | { |
225 | } | 938 | } |
226 | public static BSShape GetReference(BSPhysObject prim) | 939 | public static BSShape GetReference(BSPhysObject prim) |
227 | { | 940 | { |
941 | return new BSShapeNull(); | ||
942 | } | ||
943 | public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) | ||
944 | { | ||
228 | return new BSShapeNull(); | 945 | return new BSShapeNull(); |
229 | } | 946 | } |
230 | public override void Dereference(BSScene physicsScene) { } | 947 | public override void Dereference(BSScene physicsScene) { } |
948 | |||
949 | // From the front: | ||
950 | // A---A | ||
951 | // / \ | ||
952 | // B-------B | ||
953 | // / \ +Z | ||
954 | // C-----------C | | ||
955 | // \ / -Y --+-- +Y | ||
956 | // \ / | | ||
957 | // \ / -Z | ||
958 | // D-----D | ||
959 | // \ / | ||
960 | // E-E | ||
961 | |||
962 | // From the top A and E are just lines. | ||
963 | // B, C and D are hexagons: | ||
964 | // | ||
965 | // C1--C2 +X | ||
966 | // / \ | | ||
967 | // C0 C3 -Y --+-- +Y | ||
968 | // \ / | | ||
969 | // C5--C4 -X | ||
970 | |||
971 | // Zero goes directly through the middle so the offsets are from that middle axis | ||
972 | // and up and down from a middle horizon (A and E are the same distance from the zero). | ||
973 | // The height, width and depth is one. All scaling is done by the simulator. | ||
974 | |||
975 | // Z component -- how far the level is from the middle zero | ||
976 | private const float Aup = 0.5f; | ||
977 | private const float Bup = 0.4f; | ||
978 | private const float Cup = 0.3f; | ||
979 | private const float Dup = -0.4f; | ||
980 | private const float Eup = -0.5f; | ||
981 | |||
982 | // Y component -- distance from center to x0 and x3 | ||
983 | private const float Awid = 0.25f; | ||
984 | private const float Bwid = 0.3f; | ||
985 | private const float Cwid = 0.5f; | ||
986 | private const float Dwid = 0.3f; | ||
987 | private const float Ewid = 0.2f; | ||
988 | |||
989 | // Y component -- distance from center to x1, x2, x4 and x5 | ||
990 | private const float Afwid = 0.0f; | ||
991 | private const float Bfwid = 0.2f; | ||
992 | private const float Cfwid = 0.4f; | ||
993 | private const float Dfwid = 0.2f; | ||
994 | private const float Efwid = 0.0f; | ||
995 | |||
996 | // X component -- distance from zero to the front or back of a level | ||
997 | private const float Adep = 0f; | ||
998 | private const float Bdep = 0.3f; | ||
999 | private const float Cdep = 0.5f; | ||
1000 | private const float Ddep = 0.2f; | ||
1001 | private const float Edep = 0f; | ||
1002 | |||
1003 | private OMV.Vector3[] avatarVertices = { | ||
1004 | new OMV.Vector3( 0.0f, -Awid, Aup), // A0 | ||
1005 | new OMV.Vector3( 0.0f, +Awid, Aup), // A3 | ||
1006 | |||
1007 | new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 | ||
1008 | new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 | ||
1009 | new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 | ||
1010 | new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 | ||
1011 | new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 | ||
1012 | new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 | ||
1013 | |||
1014 | new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 | ||
1015 | new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 | ||
1016 | new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 | ||
1017 | new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 | ||
1018 | new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 | ||
1019 | new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 | ||
1020 | |||
1021 | new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 | ||
1022 | new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 | ||
1023 | new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 | ||
1024 | new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 | ||
1025 | new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 | ||
1026 | new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 | ||
1027 | |||
1028 | new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 | ||
1029 | new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 | ||
1030 | }; | ||
1031 | |||
1032 | // Offsets of the vertices in the vertices array | ||
1033 | private enum Ind : int | ||
1034 | { | ||
1035 | A0, A3, | ||
1036 | B0, B1, B2, B3, B4, B5, | ||
1037 | C0, C1, C2, C3, C4, C5, | ||
1038 | D0, D1, D2, D3, D4, D5, | ||
1039 | E0, E3 | ||
1040 | } | ||
1041 | |||
1042 | // Comments specify trianges and quads in clockwise direction | ||
1043 | private Ind[] avatarIndices = { | ||
1044 | Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 | ||
1045 | Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 | ||
1046 | Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 | ||
1047 | Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 | ||
1048 | Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 | ||
1049 | Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 | ||
1050 | |||
1051 | Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 | ||
1052 | Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 | ||
1053 | Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 | ||
1054 | Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 | ||
1055 | Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 | ||
1056 | Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 | ||
1057 | |||
1058 | Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 | ||
1059 | Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 | ||
1060 | Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 | ||
1061 | Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 | ||
1062 | Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 | ||
1063 | Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 | ||
1064 | |||
1065 | Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 | ||
1066 | Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 | ||
1067 | Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 | ||
1068 | Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 | ||
1069 | Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 | ||
1070 | Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 | ||
1071 | |||
1072 | }; | ||
1073 | |||
231 | } | 1074 | } |
232 | } | 1075 | } |
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 2e9db39..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,32 +132,37 @@ 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, m_physicsScene.RegionName); | ||
135 | // 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 |
136 | BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); | 137 | BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); |
137 | m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, | 138 | m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, |
138 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); | 139 | BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); |
139 | 140 | ||
140 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane); | 141 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); |
141 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane); | 142 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); |
142 | // Ground plane does not move | 143 | // Ground plane does not move |
143 | PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); | 144 | m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); |
144 | // Everything collides with the ground plane. | 145 | // Everything collides with the ground plane. |
145 | m_groundPlane.collisionType = CollisionType.Groundplane; | 146 | m_groundPlane.collisionType = CollisionType.Groundplane; |
146 | m_groundPlane.ApplyCollisionMask(PhysicsScene); | 147 | m_groundPlane.ApplyCollisionMask(m_physicsScene); |
147 | 148 | ||
148 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
149 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 150 | lock (m_terrains) |
150 | m_terrains.Add(Vector3.Zero, initialTerrain); | 151 | { |
152 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | ||
153 | m_terrains.Add(Vector3.Zero, initialTerrain); | ||
154 | } | ||
151 | } | 155 | } |
152 | 156 | ||
153 | // Release all the terrain structures we might have allocated | 157 | // Release all the terrain structures we might have allocated |
154 | public void ReleaseGroundPlaneAndTerrain() | 158 | public void ReleaseGroundPlaneAndTerrain() |
155 | { | 159 | { |
160 | DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); | ||
156 | if (m_groundPlane.HasPhysicalBody) | 161 | if (m_groundPlane.HasPhysicalBody) |
157 | { | 162 | { |
158 | if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) | 163 | if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) |
159 | { | 164 | { |
160 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); | 165 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); |
161 | } | 166 | } |
162 | m_groundPlane.Clear(); | 167 | m_groundPlane.Clear(); |
163 | } | 168 | } |
@@ -183,7 +188,7 @@ public sealed class BSTerrainManager : IDisposable | |||
183 | float[] localHeightMap = heightMap; | 188 | float[] localHeightMap = heightMap; |
184 | // 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, |
185 | // only do that last one. | 190 | // only do that last one. |
186 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | 191 | m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() |
187 | { | 192 | { |
188 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 193 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
189 | { | 194 | { |
@@ -193,11 +198,9 @@ public sealed class BSTerrainManager : IDisposable | |||
193 | // the terrain is added to our parent | 198 | // the terrain is added to our parent |
194 | if (MegaRegionParentPhysicsScene is BSScene) | 199 | if (MegaRegionParentPhysicsScene is BSScene) |
195 | { | 200 | { |
196 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", | 201 | DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); |
197 | BSScene.DetailLogZero, m_worldOffset, m_worldMax); | 202 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( |
198 | ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( | 203 | BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
199 | BSScene.CHILDTERRAIN_ID, localHeightMap, | ||
200 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
201 | } | 204 | } |
202 | } | 205 | } |
203 | else | 206 | else |
@@ -205,26 +208,36 @@ public sealed class BSTerrainManager : IDisposable | |||
205 | // If not doing the mega-prim thing, just change the terrain | 208 | // If not doing the mega-prim thing, just change the terrain |
206 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); | 209 | DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); |
207 | 210 | ||
208 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, | 211 | UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); |
209 | m_worldOffset, m_worldOffset + DefaultRegionSize, true); | ||
210 | } | 212 | } |
211 | }); | 213 | }); |
212 | } | 214 | } |
213 | 215 | ||
214 | // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain | 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 | |||
228 | // If called for terrain has has not been previously allocated, a new terrain will be built | ||
215 | // 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 |
216 | // 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. |
217 | // The latter feature is for creating child terrains for mega-regions. | 231 | // The latter feature is for creating child terrains for mega-regions. |
218 | // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new | 232 | // If there is an existing terrain body, a new |
219 | // terrain shape is created and added to the body. | 233 | // terrain shape is created and added to the body. |
220 | // 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. |
221 | // (The above does suggest that some simplification/refactoring is in order.) | 235 | // (The above does suggest that some simplification/refactoring is in order.) |
222 | // Called during taint-time. | 236 | // Called during taint-time. |
223 | private void UpdateTerrain(uint id, float[] heightMap, | 237 | private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) |
224 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | ||
225 | { | 238 | { |
226 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}", | 239 | DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", |
227 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); | 240 | BSScene.DetailLogZero, id, minCoords, maxCoords); |
228 | 241 | ||
229 | // Find high and low points of passed heightmap. | 242 | // Find high and low points of passed heightmap. |
230 | // 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 |
@@ -253,7 +266,7 @@ public sealed class BSTerrainManager : IDisposable | |||
253 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | 266 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
254 | { | 267 | { |
255 | // There is already a terrain in this spot. Free the old and build the new. | 268 | // There is already a terrain in this spot. Free the old and build the new. |
256 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 269 | DetailLog("{0},BSTErrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", |
257 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | 270 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); |
258 | 271 | ||
259 | // Remove old terrain from the collection | 272 | // Remove old terrain from the collection |
@@ -263,6 +276,7 @@ public sealed class BSTerrainManager : IDisposable | |||
263 | 276 | ||
264 | if (MegaRegionParentPhysicsScene == null) | 277 | if (MegaRegionParentPhysicsScene == null) |
265 | { | 278 | { |
279 | // This terrain is not part of the mega-region scheme. Create vanilla terrain. | ||
266 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 280 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
267 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 281 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
268 | 282 | ||
@@ -291,8 +305,8 @@ public sealed class BSTerrainManager : IDisposable | |||
291 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | 305 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) |
292 | newTerrainID = ++m_terrainCount; | 306 | newTerrainID = ++m_terrainCount; |
293 | 307 | ||
294 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", | 308 | DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
295 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 309 | BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); |
296 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 310 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
297 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 311 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
298 | 312 | ||
@@ -304,26 +318,26 @@ public sealed class BSTerrainManager : IDisposable | |||
304 | // 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. |
305 | 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) |
306 | { | 320 | { |
307 | PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", | 321 | m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", |
308 | LogHeader, PhysicsScene.RegionName, terrainRegionBase, | 322 | LogHeader, m_physicsScene.RegionName, terrainRegionBase, |
309 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); | 323 | (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); |
310 | BSTerrainPhys newTerrainPhys = null; | 324 | BSTerrainPhys newTerrainPhys = null; |
311 | switch ((int)BSParam.TerrainImplementation) | 325 | switch ((int)BSParam.TerrainImplementation) |
312 | { | 326 | { |
313 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: | 327 | case (int)BSTerrainPhys.TerrainImplementation.Heightmap: |
314 | newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, | 328 | newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, |
315 | heightMap, minCoords, maxCoords); | 329 | heightMap, minCoords, maxCoords); |
316 | break; | 330 | break; |
317 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: | 331 | case (int)BSTerrainPhys.TerrainImplementation.Mesh: |
318 | newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, | 332 | newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, |
319 | heightMap, minCoords, maxCoords); | 333 | heightMap, minCoords, maxCoords); |
320 | break; | 334 | break; |
321 | default: | 335 | default: |
322 | 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}", |
323 | LogHeader, | 337 | LogHeader, |
324 | (int)BSParam.TerrainImplementation, | 338 | (int)BSParam.TerrainImplementation, |
325 | BSParam.TerrainImplementation, | 339 | BSParam.TerrainImplementation, |
326 | PhysicsScene.RegionName, terrainRegionBase); | 340 | m_physicsScene.RegionName, terrainRegionBase); |
327 | break; | 341 | break; |
328 | } | 342 | } |
329 | return newTerrainPhys; | 343 | return newTerrainPhys; |
@@ -337,6 +351,53 @@ public sealed class BSTerrainManager : IDisposable | |||
337 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | 351 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); |
338 | } | 352 | } |
339 | 353 | ||
354 | // Return a new position that is over known terrain if the position is outside our terrain. | ||
355 | public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) | ||
356 | { | ||
357 | Vector3 ret = pPos; | ||
358 | |||
359 | // First, base addresses are never negative so correct for that possible problem. | ||
360 | if (ret.X < 0f || ret.Y < 0f) | ||
361 | { | ||
362 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
363 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
364 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", | ||
365 | BSScene.DetailLogZero, pPos, ret); | ||
366 | } | ||
367 | |||
368 | // Can't do this function if we don't know about any terrain. | ||
369 | if (m_terrains.Count == 0) | ||
370 | return ret; | ||
371 | |||
372 | int loopPrevention = 10; | ||
373 | Vector3 terrainBaseXYZ; | ||
374 | BSTerrainPhys physTerrain; | ||
375 | while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) | ||
376 | { | ||
377 | // The passed position is not within a known terrain area. | ||
378 | // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. | ||
379 | |||
380 | // Must be off the top of a region. Find an adjacent region to move into. | ||
381 | Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); | ||
382 | |||
383 | ret.X = Math.Min(ret.X, adjacentTerrainBase.X + (ret.X % DefaultRegionSize.X)); | ||
384 | ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + (ret.X % DefaultRegionSize.Y)); | ||
385 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", | ||
386 | BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); | ||
387 | |||
388 | if (loopPrevention-- < 0f) | ||
389 | { | ||
390 | // The 'while' is a little dangerous so this prevents looping forever if the | ||
391 | // mapping of the terrains ever gets messed up (like nothing at <0,0>) or | ||
392 | // the list of terrains is in transition. | ||
393 | DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); | ||
394 | break; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | return ret; | ||
399 | } | ||
400 | |||
340 | // Given an X and Y, find the height of the terrain. | 401 | // Given an X and Y, find the height of the terrain. |
341 | // Since we could be handling multiple terrains for a mega-region, | 402 | // Since we could be handling multiple terrains for a mega-region, |
342 | // the base of the region is calcuated assuming all regions are | 403 | // the base of the region is calcuated assuming all regions are |
@@ -368,8 +429,8 @@ public sealed class BSTerrainManager : IDisposable | |||
368 | } | 429 | } |
369 | else | 430 | else |
370 | { | 431 | { |
371 | 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}", |
372 | LogHeader, PhysicsScene.RegionName, tX, tY); | 433 | LogHeader, m_physicsScene.RegionName, tX, tY); |
373 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | 434 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", |
374 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | 435 | BSScene.DetailLogZero, pos, terrainBaseXYZ); |
375 | } | 436 | } |
@@ -390,8 +451,8 @@ public sealed class BSTerrainManager : IDisposable | |||
390 | } | 451 | } |
391 | else | 452 | else |
392 | { | 453 | { |
393 | 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}", |
394 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | 455 | LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); |
395 | } | 456 | } |
396 | return ret; | 457 | return ret; |
397 | } | 458 | } |
@@ -400,18 +461,69 @@ public sealed class BSTerrainManager : IDisposable | |||
400 | // the descriptor class and the 'base' fo the addresses therein. | 461 | // the descriptor class and the 'base' fo the addresses therein. |
401 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | 462 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) |
402 | { | 463 | { |
403 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 464 | bool ret = false; |
404 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | 465 | |
405 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | 466 | Vector3 terrainBaseXYZ = Vector3.Zero; |
467 | if (pos.X < 0f || pos.Y < 0f) | ||
468 | { | ||
469 | // We don't handle negative addresses so just make up a base that will not be found. | ||
470 | terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
475 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
476 | terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
477 | } | ||
406 | 478 | ||
407 | BSTerrainPhys physTerrain = null; | 479 | BSTerrainPhys physTerrain = null; |
408 | lock (m_terrains) | 480 | lock (m_terrains) |
409 | { | 481 | { |
410 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | 482 | ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); |
411 | } | 483 | } |
412 | outTerrainBase = terrainBaseXYZ; | 484 | outTerrainBase = terrainBaseXYZ; |
413 | outPhysTerrain = physTerrain; | 485 | outPhysTerrain = physTerrain; |
414 | return (physTerrain != null); | 486 | return ret; |
487 | } | ||
488 | |||
489 | // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than | ||
490 | // this one. Usually used to return an out of bounds object to a known place. | ||
491 | private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) | ||
492 | { | ||
493 | Vector3 ret = pTerrainBase; | ||
494 | |||
495 | // Can't do this function if we don't know about any terrain. | ||
496 | if (m_terrains.Count == 0) | ||
497 | return ret; | ||
498 | |||
499 | // Just some sanity | ||
500 | ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f); | ||
501 | ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f); | ||
502 | ret.Z = 0f; | ||
503 | |||
504 | lock (m_terrains) | ||
505 | { | ||
506 | // Once down to the <0,0> region, we have to be done. | ||
507 | while (ret.X > 0f || ret.Y > 0f) | ||
508 | { | ||
509 | if (ret.X > 0f) | ||
510 | { | ||
511 | ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); | ||
512 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
513 | if (m_terrains.ContainsKey(ret)) | ||
514 | break; | ||
515 | } | ||
516 | if (ret.Y > 0f) | ||
517 | { | ||
518 | ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); | ||
519 | DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); | ||
520 | if (m_terrains.ContainsKey(ret)) | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | return ret; | ||
415 | } | 527 | } |
416 | 528 | ||
417 | // Although no one seems to check this, I do support combining. | 529 | // Although no one seems to check this, I do support combining. |
@@ -452,7 +564,7 @@ public sealed class BSTerrainManager : IDisposable | |||
452 | 564 | ||
453 | private void DetailLog(string msg, params Object[] args) | 565 | private void DetailLog(string msg, params Object[] args) |
454 | { | 566 | { |
455 | PhysicsScene.PhysicsLogging.Write(msg, args); | 567 | m_physicsScene.PhysicsLogging.Write(msg, args); |
456 | } | 568 | } |
457 | } | 569 | } |
458 | } | 570 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index 1d55ce3..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 | { |
@@ -76,27 +76,43 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
76 | m_sizeX = (int)(maxCoords.X - minCoords.X); | 76 | m_sizeX = (int)(maxCoords.X - minCoords.X); |
77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); | 77 | m_sizeY = (int)(maxCoords.Y - minCoords.Y); |
78 | 78 | ||
79 | if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap, | 79 | bool meshCreationSuccess = false; |
80 | m_sizeX, m_sizeY, | 80 | if (BSParam.TerrainMeshMagnification == 1) |
81 | (float)m_sizeX, (float)m_sizeY, | 81 | { |
82 | Vector3.Zero, 1.0f, | 82 | // If a magnification of one, use the old routine that is tried and true. |
83 | out indicesCount, out indices, out verticesCount, out vertices)) | 83 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, |
84 | initialMap, m_sizeX, m_sizeY, // input size | ||
85 | Vector3.Zero, // base for mesh | ||
86 | out indicesCount, out indices, out verticesCount, out vertices); | ||
87 | } | ||
88 | else | ||
89 | { | ||
90 | // Other magnifications use the newer routine | ||
91 | meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, | ||
92 | initialMap, m_sizeX, m_sizeY, // input size | ||
93 | BSParam.TerrainMeshMagnification, | ||
94 | physicsScene.TerrainManager.DefaultRegionSize, | ||
95 | Vector3.Zero, // base for mesh | ||
96 | out indicesCount, out indices, out verticesCount, out vertices); | ||
97 | } | ||
98 | if (!meshCreationSuccess) | ||
84 | { | 99 | { |
85 | // DISASTER!! | 100 | // DISASTER!! |
86 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID); | 101 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); |
87 | 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); |
88 | // 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. |
89 | return; | 104 | return; |
90 | } | 105 | } |
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
93 | 106 | ||
94 | m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices); | 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); | ||
109 | |||
110 | m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); | ||
95 | if (!m_terrainShape.HasPhysicalShape) | 111 | if (!m_terrainShape.HasPhysicalShape) |
96 | { | 112 | { |
97 | // DISASTER!! | 113 | // DISASTER!! |
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | 114 | m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); |
99 | 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); |
100 | // 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. |
101 | return; | 117 | return; |
102 | } | 118 | } |
@@ -104,44 +120,54 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
104 | Vector3 pos = regionBase; | 120 | Vector3 pos = regionBase; |
105 | Quaternion rot = Quaternion.Identity; | 121 | Quaternion rot = Quaternion.Identity; |
106 | 122 | ||
107 | m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); | 123 | m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); |
108 | if (!m_terrainBody.HasPhysicalBody) | 124 | if (!m_terrainBody.HasPhysicalBody) |
109 | { | 125 | { |
110 | // DISASTER!! | 126 | // DISASTER!! |
111 | 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); |
112 | // 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. |
113 | return; | 129 | return; |
114 | } | 130 | } |
131 | physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); | ||
115 | 132 | ||
116 | // Set current terrain attributes | 133 | // Set current terrain attributes |
117 | PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); | 134 | m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); |
118 | PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); | 135 | m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); |
119 | PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); | 136 | m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); |
120 | PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); | 137 | m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); |
138 | m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); | ||
121 | 139 | ||
122 | // Static objects are not very massive. | 140 | // Static objects are not very massive. |
123 | PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); | 141 | m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); |
124 | 142 | ||
125 | // Put the new terrain to the world of physical objects | 143 | // Put the new terrain to the world of physical objects |
126 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody); | 144 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); |
127 | 145 | ||
128 | // Redo its bounding box now that it is in the world | 146 | // Redo its bounding box now that it is in the world |
129 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody); | 147 | m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); |
130 | 148 | ||
131 | m_terrainBody.collisionType = CollisionType.Terrain; | 149 | m_terrainBody.collisionType = CollisionType.Terrain; |
132 | m_terrainBody.ApplyCollisionMask(PhysicsScene); | 150 | m_terrainBody.ApplyCollisionMask(m_physicsScene); |
151 | |||
152 | if (BSParam.UseSingleSidedMeshes) | ||
153 | { | ||
154 | m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); | ||
155 | m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); | ||
156 | } | ||
133 | 157 | ||
134 | // 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. |
135 | PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); | 159 | m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); |
136 | } | 160 | } |
137 | 161 | ||
138 | public override void Dispose() | 162 | public override void Dispose() |
139 | { | 163 | { |
140 | if (m_terrainBody.HasPhysicalBody) | 164 | if (m_terrainBody.HasPhysicalBody) |
141 | { | 165 | { |
142 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody); | 166 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); |
143 | // Frees both the body and the shape. | 167 | // Frees both the body and the shape. |
144 | PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody); | 168 | m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); |
169 | m_terrainBody.Clear(); | ||
170 | m_terrainShape.Clear(); | ||
145 | } | 171 | } |
146 | } | 172 | } |
147 | 173 | ||
@@ -159,7 +185,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
159 | catch | 185 | catch |
160 | { | 186 | { |
161 | // 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. |
162 | 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}", |
163 | LogHeader, TerrainBase, pos); | 189 | LogHeader, TerrainBase, pos); |
164 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 190 | ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
165 | } | 191 | } |
@@ -169,17 +195,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
169 | // The passed position is relative to the base of the region. | 195 | // The passed position is relative to the base of the region. |
170 | public override float GetWaterLevelAtXYZ(Vector3 pos) | 196 | public override float GetWaterLevelAtXYZ(Vector3 pos) |
171 | { | 197 | { |
172 | return PhysicsScene.SimpleWaterLevel; | 198 | return m_physicsScene.SimpleWaterLevel; |
173 | } | 199 | } |
174 | 200 | ||
175 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 201 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
176 | // Return 'true' if successfully created. | 202 | // Return 'true' if successfully created. |
177 | public static bool ConvertHeightmapToMesh( | 203 | public static bool ConvertHeightmapToMesh( BSScene physicsScene, |
178 | BSScene physicsScene, | ||
179 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | 204 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap |
180 | float extentX, float extentY, // zero based range for output vertices | ||
181 | Vector3 extentBase, // base to be added to all vertices | 205 | Vector3 extentBase, // base to be added to all vertices |
182 | float magnification, // number of vertices to create between heightMap coords | ||
183 | out int indicesCountO, out int[] indicesO, | 206 | out int indicesCountO, out int[] indicesO, |
184 | out int verticesCountO, out float[] verticesO) | 207 | out int verticesCountO, out float[] verticesO) |
185 | { | 208 | { |
@@ -200,16 +223,15 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | // of the heightmap. | 223 | // of the heightmap. |
201 | try | 224 | try |
202 | { | 225 | { |
203 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 226 | // One vertice per heightmap value plus the vertices off the side and bottom edge. |
204 | int totalVertices = (sizeX + 1) * (sizeY + 1); | 227 | int totalVertices = (sizeX + 1) * (sizeY + 1); |
205 | vertices = new float[totalVertices * 3]; | 228 | vertices = new float[totalVertices * 3]; |
206 | int totalIndices = sizeX * sizeY * 6; | 229 | int totalIndices = sizeX * sizeY * 6; |
207 | indices = new int[totalIndices]; | 230 | indices = new int[totalIndices]; |
208 | 231 | ||
209 | float magX = (float)sizeX / extentX; | 232 | if (physicsScene != null) |
210 | float magY = (float)sizeY / extentY; | 233 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", |
211 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 234 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); |
212 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | ||
213 | float minHeight = float.MaxValue; | 235 | float minHeight = float.MaxValue; |
214 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 236 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
215 | for (int yy = 0; yy <= sizeY; yy++) | 237 | for (int yy = 0; yy <= sizeY; yy++) |
@@ -222,8 +244,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
222 | if (xx == sizeX) offset -= 1; | 244 | if (xx == sizeX) offset -= 1; |
223 | float height = heightMap[offset]; | 245 | float height = heightMap[offset]; |
224 | minHeight = Math.Min(minHeight, height); | 246 | minHeight = Math.Min(minHeight, height); |
225 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 247 | vertices[verticesCount + 0] = (float)xx + extentBase.X; |
226 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 248 | vertices[verticesCount + 1] = (float)yy + extentBase.Y; |
227 | vertices[verticesCount + 2] = height + extentBase.Z; | 249 | vertices[verticesCount + 2] = height + extentBase.Z; |
228 | verticesCount += 3; | 250 | verticesCount += 3; |
229 | } | 251 | } |
@@ -250,7 +272,161 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
250 | } | 272 | } |
251 | catch (Exception e) | 273 | catch (Exception e) |
252 | { | 274 | { |
253 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | 275 | if (physicsScene != null) |
276 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
277 | LogHeader, physicsScene.RegionName, extentBase, e); | ||
278 | } | ||
279 | |||
280 | indicesCountO = indicesCount; | ||
281 | indicesO = indices; | ||
282 | verticesCountO = verticesCount; | ||
283 | verticesO = vertices; | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | private class HeightMapGetter | ||
289 | { | ||
290 | private float[] m_heightMap; | ||
291 | private int m_sizeX; | ||
292 | private int m_sizeY; | ||
293 | public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) | ||
294 | { | ||
295 | m_heightMap = pHeightMap; | ||
296 | m_sizeX = pSizeX; | ||
297 | m_sizeY = pSizeY; | ||
298 | } | ||
299 | // The heightmap is extended as an infinite plane at the last height | ||
300 | public float GetHeight(int xx, int yy) | ||
301 | { | ||
302 | int offset = 0; | ||
303 | // Extend the height with the height from the last row or column | ||
304 | if (yy >= m_sizeY) | ||
305 | if (xx >= m_sizeX) | ||
306 | offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); | ||
307 | else | ||
308 | offset = (m_sizeY - 1) * m_sizeX + xx; | ||
309 | else | ||
310 | if (xx >= m_sizeX) | ||
311 | offset = yy * m_sizeX + (m_sizeX - 1); | ||
312 | else | ||
313 | offset = yy * m_sizeX + xx; | ||
314 | |||
315 | return m_heightMap[offset]; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | ||
320 | // Version that handles magnification. | ||
321 | // Return 'true' if successfully created. | ||
322 | public static bool ConvertHeightmapToMesh2( BSScene physicsScene, | ||
323 | float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap | ||
324 | int magnification, // number of vertices per heighmap step | ||
325 | Vector3 extent, // dimensions of the output mesh | ||
326 | Vector3 extentBase, // base to be added to all vertices | ||
327 | out int indicesCountO, out int[] indicesO, | ||
328 | out int verticesCountO, out float[] verticesO) | ||
329 | { | ||
330 | bool ret = false; | ||
331 | |||
332 | int indicesCount = 0; | ||
333 | int verticesCount = 0; | ||
334 | int[] indices = new int[0]; | ||
335 | float[] vertices = new float[0]; | ||
336 | |||
337 | HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); | ||
338 | |||
339 | // The vertices dimension of the output mesh | ||
340 | int meshX = sizeX * magnification; | ||
341 | int meshY = sizeY * magnification; | ||
342 | // The output size of one mesh step | ||
343 | float meshXStep = extent.X / meshX; | ||
344 | float meshYStep = extent.Y / meshY; | ||
345 | |||
346 | // Create an array of vertices that is meshX+1 by meshY+1 (note the loop | ||
347 | // from zero to <= meshX). The triangle indices are then generated as two triangles | ||
348 | // per heightmap point. There are meshX by meshY of these squares. The extra row and | ||
349 | // column of vertices are used to complete the triangles of the last row and column | ||
350 | // of the heightmap. | ||
351 | try | ||
352 | { | ||
353 | // Vertices for the output heightmap plus one on the side and bottom to complete triangles | ||
354 | int totalVertices = (meshX + 1) * (meshY + 1); | ||
355 | vertices = new float[totalVertices * 3]; | ||
356 | int totalIndices = meshX * meshY * 6; | ||
357 | indices = new int[totalIndices]; | ||
358 | |||
359 | if (physicsScene != null) | ||
360 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", | ||
361 | BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), | ||
362 | totalVertices, totalIndices, extentBase); | ||
363 | |||
364 | float minHeight = float.MaxValue; | ||
365 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | ||
366 | // Loop through the output vertices and compute the mediun height in between the input vertices | ||
367 | for (int yy = 0; yy <= meshY; yy++) | ||
368 | { | ||
369 | for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times | ||
370 | { | ||
371 | float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point | ||
372 | int stepY = (int)offsetY; | ||
373 | float fractionalY = offsetY - (float)stepY; | ||
374 | float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point | ||
375 | int stepX = (int)offsetX; | ||
376 | float fractionalX = offsetX - (float)stepX; | ||
377 | |||
378 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", | ||
379 | // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); | ||
380 | |||
381 | // get the four corners of the heightmap square the mesh point is in | ||
382 | float heightUL = hmap.GetHeight(stepX , stepY ); | ||
383 | float heightUR = hmap.GetHeight(stepX + 1, stepY ); | ||
384 | float heightLL = hmap.GetHeight(stepX , stepY + 1); | ||
385 | float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); | ||
386 | |||
387 | // bilinear interplolation | ||
388 | float height = heightUL * (1 - fractionalX) * (1 - fractionalY) | ||
389 | + heightUR * fractionalX * (1 - fractionalY) | ||
390 | + heightLL * (1 - fractionalX) * fractionalY | ||
391 | + heightLR * fractionalX * fractionalY; | ||
392 | |||
393 | // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", | ||
394 | // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); | ||
395 | |||
396 | minHeight = Math.Min(minHeight, height); | ||
397 | |||
398 | vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; | ||
399 | vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; | ||
400 | vertices[verticesCount + 2] = height + extentBase.Z; | ||
401 | verticesCount += 3; | ||
402 | } | ||
403 | } | ||
404 | // The number of vertices generated | ||
405 | verticesCount /= 3; | ||
406 | |||
407 | // Loop through all the heightmap squares and create indices for the two triangles for that square | ||
408 | for (int yy = 0; yy < meshY; yy++) | ||
409 | { | ||
410 | for (int xx = 0; xx < meshX; xx++) | ||
411 | { | ||
412 | int offset = yy * (meshX + 1) + xx; | ||
413 | // Each vertices is presumed to be the upper left corner of a box of two triangles | ||
414 | indices[indicesCount + 0] = offset; | ||
415 | indices[indicesCount + 1] = offset + 1; | ||
416 | indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column | ||
417 | indices[indicesCount + 3] = offset + 1; | ||
418 | indices[indicesCount + 4] = offset + meshX + 2; | ||
419 | indices[indicesCount + 5] = offset + meshX + 1; | ||
420 | indicesCount += 6; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | ret = true; | ||
425 | } | ||
426 | catch (Exception e) | ||
427 | { | ||
428 | if (physicsScene != null) | ||
429 | physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", | ||
254 | LogHeader, physicsScene.RegionName, extentBase, e); | 430 | LogHeader, physicsScene.RegionName, extentBase, e); |
255 | } | 431 | } |
256 | 432 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs index 662dd68..d5060e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -104,18 +104,20 @@ 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 | ||
115 | public virtual void Clear() { } | 115 | public virtual void Clear() { } |
116 | public virtual bool HasPhysicalShape { get { return false; } } | 116 | public virtual bool HasPhysicalShape { get { return false; } } |
117 | |||
117 | // Make another reference to this physical object. | 118 | // Make another reference to this physical object. |
118 | public virtual BulletShape Clone() { return new BulletShape(); } | 119 | public virtual BulletShape Clone() { return new BulletShape(); } |
120 | |||
119 | // Return 'true' if this and other refer to the same physical object | 121 | // Return 'true' if this and other refer to the same physical object |
120 | public virtual bool ReferenceSame(BulletShape xx) { return false; } | 122 | public virtual bool ReferenceSame(BulletShape xx) { return false; } |
121 | 123 | ||
@@ -131,7 +133,7 @@ public class BulletShape | |||
131 | buff.Append("<p="); | 133 | buff.Append("<p="); |
132 | buff.Append(AddrString); | 134 | buff.Append(AddrString); |
133 | buff.Append(",s="); | 135 | buff.Append(",s="); |
134 | buff.Append(type.ToString()); | 136 | buff.Append(shapeType.ToString()); |
135 | buff.Append(",k="); | 137 | buff.Append(",k="); |
136 | buff.Append(shapeKey.ToString("X")); | 138 | buff.Append(shapeKey.ToString("X")); |
137 | buff.Append(",n="); | 139 | buff.Append(",n="); |
@@ -215,45 +217,49 @@ public static class BulletSimData | |||
215 | { | 217 | { |
216 | 218 | ||
217 | // Map of collisionTypes to flags for collision groups and masks. | 219 | // Map of collisionTypes to flags for collision groups and masks. |
220 | // An object's 'group' is the collison groups this object belongs to | ||
221 | // An object's 'filter' is the groups another object has to belong to in order to collide with me | ||
222 | // A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) | ||
223 | // | ||
218 | // 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 |
219 | // but, instead, use references to this dictionary. Finding and debugging | 225 | // but, instead, use references to this dictionary. Finding and debugging |
220 | // collision flag problems will be made easier. | 226 | // collision flag problems will be made easier. |
221 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | 227 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks |
222 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | 228 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() |
223 | { | 229 | { |
224 | { CollisionType.Avatar, | 230 | { CollisionType.Avatar, |
225 | new CollisionTypeFilterGroup(CollisionType.Avatar, | 231 | new CollisionTypeFilterGroup(CollisionType.Avatar, |
226 | (uint)CollisionFilterGroups.BCharacterGroup, | 232 | (uint)CollisionFilterGroups.BCharacterGroup, |
227 | (uint)CollisionFilterGroups.BAllGroup) | 233 | (uint)CollisionFilterGroups.BAllGroup) |
228 | }, | 234 | }, |
229 | { CollisionType.Groundplane, | 235 | { CollisionType.Groundplane, |
230 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | 236 | new CollisionTypeFilterGroup(CollisionType.Groundplane, |
231 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | 237 | (uint)CollisionFilterGroups.BGroundPlaneGroup, |
232 | (uint)CollisionFilterGroups.BAllGroup) | 238 | (uint)CollisionFilterGroups.BAllGroup) |
233 | }, | 239 | }, |
234 | { CollisionType.Terrain, | 240 | { CollisionType.Terrain, |
235 | new CollisionTypeFilterGroup(CollisionType.Terrain, | 241 | new CollisionTypeFilterGroup(CollisionType.Terrain, |
236 | (uint)CollisionFilterGroups.BTerrainGroup, | 242 | (uint)CollisionFilterGroups.BTerrainGroup, |
237 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | 243 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) |
238 | }, | 244 | }, |
239 | { CollisionType.Static, | 245 | { CollisionType.Static, |
240 | new CollisionTypeFilterGroup(CollisionType.Static, | 246 | new CollisionTypeFilterGroup(CollisionType.Static, |
241 | (uint)CollisionFilterGroups.BStaticGroup, | 247 | (uint)CollisionFilterGroups.BStaticGroup, |
242 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 248 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
243 | }, | 249 | }, |
244 | { CollisionType.Dynamic, | 250 | { CollisionType.Dynamic, |
245 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | 251 | new CollisionTypeFilterGroup(CollisionType.Dynamic, |
246 | (uint)CollisionFilterGroups.BSolidGroup, | 252 | (uint)CollisionFilterGroups.BSolidGroup, |
247 | (uint)(CollisionFilterGroups.BAllGroup)) | 253 | (uint)(CollisionFilterGroups.BAllGroup)) |
248 | }, | 254 | }, |
249 | { CollisionType.VolumeDetect, | 255 | { CollisionType.VolumeDetect, |
250 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | 256 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, |
251 | (uint)CollisionFilterGroups.BSensorTrigger, | 257 | (uint)CollisionFilterGroups.BSensorTrigger, |
252 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | 258 | (uint)(~CollisionFilterGroups.BSensorTrigger)) |
253 | }, | 259 | }, |
254 | { CollisionType.LinksetChild, | 260 | { CollisionType.LinksetChild, |
255 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | 261 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, |
256 | (uint)CollisionFilterGroups.BLinksetChildGroup, | 262 | (uint)CollisionFilterGroups.BLinksetChildGroup, |
257 | (uint)(CollisionFilterGroups.BNoneGroup)) | 263 | (uint)(CollisionFilterGroups.BNoneGroup)) |
258 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | 264 | // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) |
259 | }, | 265 | }, |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt index a8a4ff5..5792ae6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -1,68 +1,113 @@ | |||
1 | PROBLEMS TO LOOK INTO | ||
2 | ================================================= | ||
3 | Nebadon vehicle ride, get up, ride again. Second time vehicle does not act correctly. | ||
4 | Have to rez new vehicle and delete the old to fix situation. | ||
5 | Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd | ||
6 | position state where it will not settle onto ground properly, etc | ||
7 | Two of Nebadon vehicles in a sim max the CPU. This is new. | ||
8 | A sitting, active vehicle bobs up and down a small amount. | ||
9 | |||
1 | CURRENT PRIORITIES | 10 | CURRENT PRIORITIES |
2 | ================================================= | 11 | ================================================= |
3 | Redo BulletSimAPI to allow native C# implementation of Bullet option. | 12 | Use the HACD convex hull routine in Bullet rather than the C# version. |
4 | Avatar movement | 13 | Speed up hullifying large meshes. |
5 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle | ||
6 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) | ||
7 | avatar capsule rotation completed | ||
8 | llMoveToTarget | ||
9 | Enable vehicle border crossings (at least as poorly as ODE) | 14 | Enable vehicle border crossings (at least as poorly as ODE) |
10 | Terrain skirts | 15 | Terrain skirts |
11 | Avatar created in previous region and not new region when crossing border | 16 | Avatar created in previous region and not new region when crossing border |
12 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | 17 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) |
13 | Vehicle movement on terrain smoothness | 18 | Deleting a linkset while standing on the root will leave the physical shape of the root behind. |
19 | Not sure if it is because standing on it. Done with large prim linksets. | ||
20 | Linkset child rotations. | ||
21 | Nebadon spiral tube has middle sections which are rotated wrong. | ||
22 | Select linked spiral tube. Delink and note where the middle section ends up. | ||
23 | Refarb compound linkset creation to create a pseudo-root for center-of-mass | ||
24 | Let children change their shape to physical indendently and just add shapes to compound | ||
25 | Vehicle angular vertical attraction | ||
26 | vehicle angular banking | ||
27 | Center-of-gravity | ||
28 | Vehicle angular deflection | ||
29 | Preferred orientation angular correction fix | ||
30 | when should angular and linear motor targets be zeroed? when selected? | ||
31 | Need a vehicle.clear()? Or an 'else' in prestep if not physical. | ||
32 | Teravus llMoveToTarget script debug | ||
33 | Mixing of hover, buoyancy/gravity, moveToTarget, into one force | ||
34 | Setting hover height to zero disables hover even if hover flags are on (from SL wiki) | ||
35 | limitMotorUp calibration (more down?) | ||
36 | llRotLookAt | ||
37 | llLookAt | ||
38 | Avatars walking up stairs (HALF DONE) | ||
39 | Avatar movement | ||
40 | flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE) | ||
41 | walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE) | ||
42 | avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution) | ||
14 | Vehicle script tuning/debugging | 43 | Vehicle script tuning/debugging |
15 | Avanti speed script | 44 | Avanti speed script |
16 | Weapon shooter script | 45 | Weapon shooter script |
17 | limitMotorUp calibration (more down?) | 46 | Move material definitions (friction, ...) into simulator. |
18 | Boats float low in the water | ||
19 | Add material densities to the material types. | 47 | Add material densities to the material types. |
20 | 48 | One sided meshes? Should terrain be built into a closed shape? | |
21 | CRASHES | 49 | When meshes get partially wedged into the terrain, they cannot push themselves out. |
22 | ================================================= | 50 | It is possible that Bullet processes collisions whether entering or leaving a mesh. |
23 | 20121129.1411: editting/moving phys object across region boundries causes crash | 51 | Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869 |
24 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
25 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
26 | Causes many errors. Doesn't stop after first error with box shape. | ||
27 | Eventually crashes when deleting the object. | ||
28 | 20121206.1434: rez Sam-pan into OSGrid BulletSim11 region | ||
29 | Immediate simulator crash. Mono does not output any stacktrace and | ||
30 | log just stops after reporting taint-time linking of the linkset. | ||
31 | 52 | ||
32 | VEHICLES TODO LIST: | 53 | VEHICLES TODO LIST: |
33 | ================================================= | 54 | ================================================= |
34 | Angular motor direction is global coordinates rather than local coordinates | 55 | LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers. |
56 | What are the limits in SL? | ||
57 | Same for other velocity settings. | ||
58 | UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims: | ||
59 | https://github.com/UbitUmarov/Ubit-opensim | ||
35 | Border crossing with linked vehicle causes crash | 60 | Border crossing with linked vehicle causes crash |
61 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
62 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
36 | Vehicles (Move smoothly) | 63 | Vehicles (Move smoothly) |
37 | Add vehicle collisions so IsColliding is properly reported. | ||
38 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
39 | VehicleAddForce is not scaled by the simulation step but it is only | ||
40 | applied for one step. Should it be scaled? | ||
41 | Some vehicles should not be able to turn if no speed or off ground. | 64 | Some vehicles should not be able to turn if no speed or off ground. |
65 | What to do if vehicle and prim buoyancy differ? | ||
42 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | 66 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. |
43 | Neb car jiggling left and right | 67 | Neb car jiggling left and right |
44 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | 68 | Happens on terrain and any other mesh object. Flat cubes are much smoother. |
45 | This has been reduced but not eliminated. | 69 | This has been reduced but not eliminated. |
46 | Implement referenceFrame for all the motion routines. | 70 | Implement referenceFrame for all the motion routines. |
47 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | 71 | For limitMotorUp, use raycast down to find if vehicle is in the air. |
48 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
49 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | 72 | Verify llGetVel() is returning a smooth and good value for vehicle movement. |
50 | llGetVel() should return the root's velocity if requested in a child prim. | 73 | llGetVel() should return the root's velocity if requested in a child prim. |
51 | Implement function efficiency for lineaar and angular motion. | 74 | Implement function efficiency for lineaar and angular motion. |
52 | After getting off a vehicle, the root prim is phantom (can be walked through) | 75 | After getting off a vehicle, the root prim is phantom (can be walked through) |
53 | Need to force a position update for the root prim after compound shape destruction | 76 | Need to force a position update for the root prim after compound shape destruction |
54 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | 77 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) |
55 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
56 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | 78 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). |
57 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | 79 | A kludge that isn't fixing the real problem of Bullet adding extra motion. |
58 | Incorporate inter-relationship of angular corrections. For instance, angularDeflection | 80 | Incorporate inter-relationship of angular corrections. For instance, angularDeflection |
59 | and angularMotorUp will compute same X or Y correction. When added together | 81 | and angularMotorUp will compute same X or Y correction. When added together |
60 | creates over-correction and over-shoot and wabbling. | 82 | creates over-correction and over-shoot and wabbling. |
83 | Vehicle attributes are not restored when a vehicle is rezzed on region creation | ||
84 | Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized. | ||
61 | 85 | ||
62 | BULLETSIM TODO LIST: | 86 | GENERAL TODO LIST: |
63 | ================================================= | 87 | ================================================= |
88 | Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects. | ||
89 | Regular triangle meshes don't do physical collisions. | ||
90 | Resitution of a prim works on another prim but not on terrain. | ||
91 | The dropped prim doesn't bounce properly on the terrain. | ||
92 | Add a sanity check for PIDTarget location. | ||
93 | Level-of-detail for mesh creation. Prims with circular interiors require lod of 32. | ||
94 | Is much saved with lower LODs? At the moment, all set to 32. | ||
95 | Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't. | ||
96 | If arrow show at prim, collision reported about 1/3 of time. If collision reported, | ||
97 | both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times. | ||
98 | Shooting 5m sphere "arrows" at 60m/s. | ||
99 | llMoveToTarget objects are not effected by gravity until target is removed. | ||
100 | Compute CCD parameters based on body size | ||
101 | Can solver iterations be changed per body/shape? Can be for constraints but what | ||
102 | about regular vehicles? | ||
103 | Implement llSetPhysicalMaterial. | ||
104 | extend it with Center-of-mass, rolling friction, density | ||
105 | Implement llSetForceAndTorque. | ||
106 | Change BSPrim.moveToTarget to used forces rather than changing position | ||
107 | Changing position allows one to move through walls | ||
64 | Implement an avatar mesh shape. The Bullet capsule is way too limited. | 108 | Implement an avatar mesh shape. The Bullet capsule is way too limited. |
65 | Consider just hand creating a vertex/index array in a new BSShapeAvatar. | 109 | Consider just hand creating a vertex/index array in a new BSShapeAvatar. |
110 | Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain. | ||
66 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | 111 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. |
67 | Duplicating a physical prim causes old prim to jump away | 112 | Duplicating a physical prim causes old prim to jump away |
68 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | 113 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. |
@@ -86,6 +131,8 @@ setForce should set a constant force. Different than AddImpulse. | |||
86 | Implement raycast. | 131 | Implement raycast. |
87 | Implement ShapeCollection.Dispose() | 132 | Implement ShapeCollection.Dispose() |
88 | Implement water as a plain so raycasting and collisions can happen with same. | 133 | Implement water as a plain so raycasting and collisions can happen with same. |
134 | Add collision penetration return | ||
135 | Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance() | ||
89 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | 136 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE |
90 | Also osGetPhysicsEngineVerion() maybe. | 137 | Also osGetPhysicsEngineVerion() maybe. |
91 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | 138 | Linkset.Position and Linkset.Orientation requre rewrite to properly return |
@@ -107,6 +154,12 @@ Physical and phantom will drop through the terrain | |||
107 | 154 | ||
108 | LINKSETS | 155 | LINKSETS |
109 | ====================================================== | 156 | ====================================================== |
157 | Child prims do not report collisions | ||
158 | Allow children of a linkset to be phantom: | ||
159 | http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html | ||
160 | Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast. | ||
161 | Editing a child of a linkset causes the child to go phantom | ||
162 | Move a child prim once when it is physical and can never move it again without it going phantom | ||
110 | Offset the center of the linkset to be the geometric center of all the prims | 163 | Offset the center of the linkset to be the geometric center of all the prims |
111 | Not quite the same as the center-of-gravity | 164 | Not quite the same as the center-of-gravity |
112 | Linksets should allow collisions to individual children | 165 | Linksets should allow collisions to individual children |
@@ -117,11 +170,9 @@ LinksetCompound: when one of the children changes orientation (like tires | |||
117 | Verify/think through scripts in children of linksets. What do they reference | 170 | Verify/think through scripts in children of linksets. What do they reference |
118 | and return when getting position, velocity, ... | 171 | and return when getting position, velocity, ... |
119 | Confirm constraint linksets still work after making all the changes for compound linksets. | 172 | Confirm constraint linksets still work after making all the changes for compound linksets. |
173 | Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding | ||
120 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | 174 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. |
121 | For compound linksets, add ability to remove or reposition individual child shapes. | 175 | For compound linksets, add ability to remove or reposition individual child shapes. |
122 | Disable activity of passive linkset children. | ||
123 | Since the linkset is a compound object, the old prims are left lying | ||
124 | around and need to be phantomized so they don't collide, ... | ||
125 | Speed up creation of large physical linksets | 176 | Speed up creation of large physical linksets |
126 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. | 177 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. |
127 | REALLY bad for very large physical linksets (freezes the sim for many seconds). | 178 | REALLY bad for very large physical linksets (freezes the sim for many seconds). |
@@ -131,25 +182,28 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint) | |||
131 | 182 | ||
132 | MORE | 183 | MORE |
133 | ====================================================== | 184 | ====================================================== |
134 | Test avatar walking up stairs. How does compare with SL. | 185 | Compute avatar size and scale correctly. Now it is a bit off from the capsule size. |
135 | Radius of the capsule affects ability to climb edges. | 186 | Create tests for different interface components |
187 | Have test objects/scripts measure themselves and turn color if correct/bad | ||
188 | Test functions in SL and calibrate correctness there | ||
189 | Create auto rezzer and tracker to run through the tests | ||
190 | Do we need to do convex hulls all the time? Can complex meshes be left meshes? | ||
191 | There is some problem with meshes and collisions | ||
192 | Hulls are not as detailed as meshes. Hulled vehicles insides are different shape. | ||
136 | Debounce avatar contact so legs don't keep folding up when standing. | 193 | Debounce avatar contact so legs don't keep folding up when standing. |
137 | Implement LSL physics controls. Like STATUS_ROTATE_X. | 194 | Implement LSL physics controls. Like STATUS_ROTATE_X. |
138 | Add border extensions to terrain to help region crossings and objects leaving region. | 195 | Add border extensions to terrain to help region crossings and objects leaving region. |
139 | Use a different capsule shape for avatar when sitting | 196 | Use a different capsule shape for avatar when sitting |
140 | LL uses a pyrimidal shape scaled by the avatar's bounding box | 197 | LL uses a pyrimidal shape scaled by the avatar's bounding box |
141 | http://wiki.secondlife.com/wiki/File:Avmeshforms.png | 198 | http://wiki.secondlife.com/wiki/File:Avmeshforms.png |
142 | |||
143 | Performance test with lots of avatars. Can BulletSim support a thousand? | 199 | Performance test with lots of avatars. Can BulletSim support a thousand? |
144 | Optimize collisions in C++: only send up to the object subscribed to collisions. | 200 | Optimize collisions in C++: only send up to the object subscribed to collisions. |
145 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | 201 | Use collision subscription and remove the collsion(A,B) and collision(B,A) |
146 | Check whether SimMotionState needs large if statement (see TODO). | 202 | Check whether SimMotionState needs large if statement (see TODO). |
147 | |||
148 | Implement 'top colliders' info. | 203 | Implement 'top colliders' info. |
149 | Avatar jump | 204 | Avatar jump |
150 | Performance measurement and changes to make quicker. | 205 | Performance measurement and changes to make quicker. |
151 | Implement detailed physics stats (GetStats()). | 206 | Implement detailed physics stats (GetStats()). |
152 | |||
153 | Measure performance improvement from hulls | 207 | Measure performance improvement from hulls |
154 | Test not using ghost objects for volume detect implementation. | 208 | Test not using ghost objects for volume detect implementation. |
155 | Performance of closures and delegates for taint processing | 209 | Performance of closures and delegates for taint processing |
@@ -157,9 +211,7 @@ Performance of closures and delegates for taint processing | |||
157 | Is any slowdown introduced by the existing implementation significant? | 211 | Is any slowdown introduced by the existing implementation significant? |
158 | Is there are more efficient method of implementing pre and post step actions? | 212 | Is there are more efficient method of implementing pre and post step actions? |
159 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | 213 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C |
160 | |||
161 | Physics Arena central pyramid: why is one side permiable? | 214 | Physics Arena central pyramid: why is one side permiable? |
162 | |||
163 | In SL, perfect spheres don't seem to have rolling friction. Add special case. | 215 | In SL, perfect spheres don't seem to have rolling friction. Add special case. |
164 | Enforce physical parameter min/max: | 216 | Enforce physical parameter min/max: |
165 | Gravity: [-1, 28] | 217 | Gravity: [-1, 28] |
@@ -168,9 +220,12 @@ Enforce physical parameter min/max: | |||
168 | Restitution [0, 1] | 220 | Restitution [0, 1] |
169 | http://wiki.secondlife.com/wiki/Physics_Material_Settings_test | 221 | http://wiki.secondlife.com/wiki/Physics_Material_Settings_test |
170 | Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html | 222 | Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html |
223 | Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html | ||
171 | 224 | ||
172 | INTERNAL IMPROVEMENT/CLEANUP | 225 | INTERNAL IMPROVEMENT/CLEANUP |
173 | ================================================= | 226 | ================================================= |
227 | Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to | ||
228 | BSScene.TaintedObject() could immediately execute the callback if already in taint time. | ||
174 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on | 229 | Create the physical wrapper classes (BulletBody, BulletShape) by methods on |
175 | BSAPITemplate and make their actual implementation Bullet engine specific. | 230 | BSAPITemplate and make their actual implementation Bullet engine specific. |
176 | For the short term, just call the existing functions in ShapeCollection. | 231 | For the short term, just call the existing functions in ShapeCollection. |
@@ -190,22 +245,19 @@ Generalize Dynamics and PID with standardized motors. | |||
190 | Generalize Linkset and vehicles into PropertyManagers | 245 | Generalize Linkset and vehicles into PropertyManagers |
191 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | 246 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies |
192 | Potentially add events for shape destruction, etc. | 247 | Potentially add events for shape destruction, etc. |
193 | Complete implemention of preStepActions | 248 | Better mechanism for resetting linkset set and vehicle parameters when body rebuilt. |
194 | Replace vehicle step call with prestep event. | 249 | BSPrim.CreateGeomAndObject is kludgy with the callbacks, etc. |
195 | Is there a need for postStepActions? postStepTaints? | ||
196 | Implement linkset by setting position of children when root updated. (LinksetManual) | 250 | Implement linkset by setting position of children when root updated. (LinksetManual) |
197 | Linkset implementation using manual prim movement. | 251 | Linkset implementation using manual prim movement. |
198 | LinkablePrim class? Would that simplify/centralize the linkset logic? | 252 | LinkablePrim class? Would that simplify/centralize the linkset logic? |
199 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | 253 | BSScene.UpdateParameterSet() is broken. How to set params on objects? |
200 | Remove HeightmapInfo from terrain specification | ||
201 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
202 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | 254 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will |
203 | bob at the water level. BSPrim.PositionSanityCheck(). | 255 | bob at the water level. BSPrim.PositionSanityCheck() |
204 | Should taints check for existance or activeness of target? | 256 | Should taints check for existance or activeness of target? |
205 | When destroying linksets/etc, taints can be generated for objects that are | 257 | When destroying linksets/etc, taints can be generated for objects that are |
206 | actually gone when the taint happens. Crashes don't happen because the taint closure | 258 | actually gone when the taint happens. Crashes don't happen because the taint closure |
207 | keeps the object from being freed, but that is just an accident. | 259 | keeps the object from being freed, but that is just an accident. |
208 | Possibly have and 'active' flag that is checked by the taint processor? | 260 | Possibly have an 'active' flag that is checked by the taint processor? |
209 | Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) | 261 | Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) |
210 | Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? | 262 | Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? |
211 | There are TOO MANY interfaces from BulletSim core to Bullet itself | 263 | There are TOO MANY interfaces from BulletSim core to Bullet itself |
@@ -270,3 +322,43 @@ llSetBuoyancy() (DONE) | |||
270 | (Resolution: Bullet resets object gravity when added to world. Moved set gravity) | 322 | (Resolution: Bullet resets object gravity when added to world. Moved set gravity) |
271 | Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) | 323 | Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) |
272 | (Resolution: set default density to 3.5 (from 60) which is closer to SL) | 324 | (Resolution: set default density to 3.5 (from 60) which is closer to SL) |
325 | Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE) | ||
326 | (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA | ||
327 | Meshes rendering as bounding boxes (DONE) | ||
328 | (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box) | ||
329 | llMoveToTarget (Resolution: added simple motor to update the position.) | ||
330 | Angular motor direction is global coordinates rather than local coordinates (DONE) | ||
331 | Add vehicle collisions so IsColliding is properly reported. (DONE) | ||
332 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
333 | (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it) | ||
334 | VehicleAddForce is not scaled by the simulation step but it is only | ||
335 | applied for one step. Should it be scaled? (DONE) | ||
336 | (Resolution: use force for timed things, Impulse for immediate, non-timed things) | ||
337 | Complete implemention of preStepActions (DONE) | ||
338 | Replace vehicle step call with prestep event. | ||
339 | Is there a need for postStepActions? postStepTaints? | ||
340 | Disable activity of passive linkset children. (DONE) | ||
341 | Since the linkset is a compound object, the old prims are left lying | ||
342 | around and need to be phantomized so they don't collide, ... | ||
343 | Remove HeightmapInfo from terrain specification (DONE) | ||
344 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
345 | Surfboard go wonky when turning (DONE) | ||
346 | Angular motor direction is global coordinates rather than local coordinates? | ||
347 | (Resolution: made angular motor direction correct coordinate system) | ||
348 | Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE) | ||
349 | Msg Kayaker on OSGrid when working | ||
350 | (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the | ||
351 | same in SL as in OS/BulletSim) | ||
352 | Boats float low in the water (DONE) | ||
353 | Boats floating at proper level (DONE) | ||
354 | When is force introduced by SetForce removed? The prestep action could go forever. (DONE) | ||
355 | (Resolution: setForce registers a prestep action which keeps applying the force) | ||
356 | Child movement in linkset (don't rebuild linkset) (DONE 20130122)) | ||
357 | Avatar standing on a moving object should start to move with the object. (DONE 20130125) | ||
358 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
359 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
360 | DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. | ||
361 | Nebadon vehicles turning funny in arena (DONE) | ||
362 | Lock axis (DONE 20130401) | ||
363 | Terrain detail: double terrain mesh detail (DONE) | ||
364 | |||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs index 0d1db3b..02b03a8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 32 | [assembly: AssemblyVersion("0.7.6.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 33 | |
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 1f41e04..1e94d05 100755 --- a/bin/lib32/BulletSim.dll +++ b/bin/lib32/BulletSim.dll | |||
Binary files differ | |||
diff --git a/bin/lib32/libBulletSim.dylib b/bin/lib32/libBulletSim.dylib new file mode 100755 index 0000000..02f8a7f --- /dev/null +++ b/bin/lib32/libBulletSim.dylib | |||
Binary files differ | |||
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index 85ff318..6216a65 100755 --- a/bin/lib32/libBulletSim.so +++ b/bin/lib32/libBulletSim.so | |||
Binary files differ | |||
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 674af3e..68cfcc4 100755 --- a/bin/lib64/BulletSim.dll +++ b/bin/lib64/BulletSim.dll | |||
Binary files differ | |||
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 14892a4..08c00af 100755 --- a/bin/lib64/libBulletSim.so +++ b/bin/lib64/libBulletSim.so | |||
Binary files differ | |||