aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorRobert Adams2013-05-08 06:02:12 -0700
committerRobert Adams2013-05-08 06:02:12 -0700
commiteb0687f5af127ad6195b95965ce31346f2bc0a24 (patch)
tree8888b8d4c45874c646da0b475d09bd051b33e1cc
parentAdd regression test for inventory item give, reject and subsequent trash fold... (diff)
downloadopensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.zip
opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.gz
opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.bz2
opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.xz
vh: update BulletSim (OpenSim/Region/Physics/BulletSPlugin
and DLL/SO) to ac6dcd35fb77f118fc6c3d72cb029591306c7e99 (Mon May 6 21:10:02 2013 -0400) on top of 0.7.5-postfixes.
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs207
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1470
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs351
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorHover.cs173
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs187
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorMoveToTarget.cs157
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetForce.cs137
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs138
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActors.cs160
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs167
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs385
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs2
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs16
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs13
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs826
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs77
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs386
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs60
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs3
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs234
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs913
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs351
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs2
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs889
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimDisplaced.cs165
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs192
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs163
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs927
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs1021
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs30
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs212
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs258
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs54
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt184
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs4
-rwxr-xr-xbin/lib32/BulletSim.dllbin551936 -> 1010176 bytes
-rwxr-xr-xbin/lib32/libBulletSim.dylibbin0 -> 1181656 bytes
-rwxr-xr-xbin/lib32/libBulletSim.sobin1719480 -> 2096576 bytes
-rwxr-xr-xbin/lib64/BulletSim.dllbin700928 -> 1142272 bytes
-rwxr-xr-xbin/lib64/libBulletSim.sobin1857745 -> 2265980 bytes
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
75private sealed class BulletShapeUnman : BulletShape 75private sealed class BulletShapeUnman : BulletShape
76{ 76{
77 public IntPtr ptr; 77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) 78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base() 79 : base()
80 { 80 {
81 ptr = xx; 81 ptr = xx;
82 type = typ; 82 shapeType = typ;
83 } 83 }
84 public override bool HasPhysicalShape 84 public override bool HasPhysicalShape
85 { 85 {
@@ -91,7 +91,7 @@ private sealed class BulletShapeUnman : BulletShape
91 } 91 }
92 public override BulletShape Clone() 92 public override BulletShape Clone()
93 { 93 {
94 return new BulletShapeUnman(ptr, type); 94 return new BulletShapeUnman(ptr, shapeType);
95 } 95 }
96 public override bool ReferenceSame(BulletShape other) 96 public override bool ReferenceSame(BulletShape other)
97 { 97 {
@@ -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
204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, 204public 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
217public override bool PushUpdate(BulletBody obj) 230public 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
249public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) 262public 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
271public 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
280public 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
258public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) 290public 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
279public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) 311public 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
362public 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
330public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) 368public 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
343public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 381public 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
460public 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
470public 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
422public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 482public 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
494public 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
506public 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
518public 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
529public 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
434public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) 540public 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
531public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) 637public 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;
924public override void ApplyCentralForce(BulletBody obj, Vector3 force) 1031public 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;
967public override void ApplyTorque(BulletBody obj, Vector3 torque) 1075public 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));
974public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) 1084public 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;
981public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) 1092public 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;
988public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) 1100public 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));
995public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) 1109public 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}
1376public override void ResetBroadphasePool(BulletWorld world)
1377{
1378 BulletWorldUnman worldu = world as BulletWorldUnman;
1379 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1380}
1381public 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]
1309public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); 1433public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1434
1435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1436public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1437
1438[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1439public 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]
1312public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); 1444public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
@@ -1315,7 +1447,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
1315public static extern bool IsNativeShape2(IntPtr shape); 1447public static extern bool IsNativeShape2(IntPtr shape);
1316 1448
1317[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1318public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); 1450public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1319 1451
1320[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1452[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1321public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 1453public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
@@ -1339,6 +1471,9 @@ public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShap
1339public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 1471public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1340 1472
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1473[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1474public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1475
1476[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); 1477public 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);
1368public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1503public 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]
1371public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1506public 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]
1524public 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]
1529public 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]
1389public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 1535public 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]
1541public 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]
1547public 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]
1553public 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]
1558public 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]
1395public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); 1564public 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]
1833public static extern void DumpPhysicsStatistics2(IntPtr sim); 2002public static extern void DumpPhysicsStatistics2(IntPtr sim);
1834 2003
2004[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2005public static extern void ResetBroadphasePool(IntPtr sim);
2006
2007[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2008public 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 @@
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.IO; 29using System.IO;
30using System.Runtime.InteropServices;
30using System.Text; 31using System.Text;
31 32
32using OpenSim.Framework; 33using OpenSim.Framework;
@@ -80,11 +81,11 @@ private sealed class BulletBodyXNA : BulletBody
80private sealed class BulletShapeXNA : BulletShape 81private 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorAvatarMove : BSActor
40{
41 BSVMotor m_velocityMotor;
42
43 // Set to true if we think we're going up stairs.
44 // This state is remembered because collisions will turn on and off as we go up stairs.
45 int m_walkingUpStairs;
46 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorHover : BSActor
40{
41 private BSFMotor m_hoverMotor;
42
43 public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_hoverMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, turn me off
71 if (!m_controllingPrim.HoverActive)
72 {
73 SetEnabled(false);
74 }
75
76 // If the object is physically active, add the hoverer prestep action
77 if (isActive)
78 {
79 ActivateHover();
80 }
81 else
82 {
83 DeactivateHover();
84 }
85 }
86
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time.
90 // BSActor.RemoveDependencies()
91 public override void RemoveDependencies()
92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 }
95
96 // If a hover motor has not been created, create one and start the hovering.
97 private void ActivateHover()
98 {
99 if (m_hoverMotor == null)
100 {
101 // Turning the target on
102 m_hoverMotor = new BSFMotor("BSActorHover",
103 m_controllingPrim.HoverTau, // timeScale
104 BSMotor.Infinite, // decay time scale
105 1f // efficiency
106 );
107 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
108 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
109 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
110
111 m_physicsScene.BeforeStep += Hoverer;
112 }
113 }
114
115 private void DeactivateHover()
116 {
117 if (m_hoverMotor != null)
118 {
119 m_physicsScene.BeforeStep -= Hoverer;
120 m_hoverMotor = null;
121 }
122 }
123
124 // Called just before the simulation step. Update the vertical position for hoverness.
125 private void Hoverer(float timeStep)
126 {
127 // Don't do hovering while the object is selected.
128 if (!isActive)
129 return;
130
131 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
132 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
133 float targetHeight = m_hoverMotor.Step(timeStep);
134
135 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
136 // Compute the amount of force to push us there.
137 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
138 // Undo anything the object thinks it's doing at the moment
139 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
140
141 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
142 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
143 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
144 }
145
146 // Based on current position, determine what we should be hovering at now.
147 // Must recompute often. What if we walked offa cliff>
148 private float ComputeCurrentHoverHeight()
149 {
150 float ret = m_controllingPrim.HoverHeight;
151 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
152
153 switch (m_controllingPrim.HoverType)
154 {
155 case PIDHoverType.Ground:
156 ret = groundHeight + m_controllingPrim.HoverHeight;
157 break;
158 case PIDHoverType.GroundAndWater:
159 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
160 if (groundHeight > waterHeight)
161 {
162 ret = groundHeight + m_controllingPrim.HoverHeight;
163 }
164 else
165 {
166 ret = waterHeight + m_controllingPrim.HoverHeight;
167 }
168 break;
169 }
170 return ret;
171 }
172}
173}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorLockAxis.cs
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetForce : BSActor
40{
41 BSFMotor m_forceMotor;
42
43 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_forceMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetForce();
82 }
83 else
84 {
85 DeactivateSetForce();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetForce()
100 {
101 if (m_forceMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetForce()
111 {
112 if (m_forceMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_forceMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
new file mode 100755
index 0000000..65098e1
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorSetTorque.cs
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorSetTorque : BSActor
40{
41 BSFMotor m_torqueMotor;
42
43 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_torqueMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
54 }
55
56 // Release any connections and resources used by the actor.
57 // BSActor.Dispose()
58 public override void Dispose()
59 {
60 Enabled = false;
61 }
62
63 // Called when physical parameters (properties set in Bullet) need to be re-applied.
64 // Called at taint-time.
65 // BSActor.Refresh()
66 public override void Refresh()
67 {
68 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
69
70 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
71 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
72 {
73 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
74 Enabled = false;
75 return;
76 }
77
78 // If the object is physically active, add the hoverer prestep action
79 if (isActive)
80 {
81 ActivateSetTorque();
82 }
83 else
84 {
85 DeactivateSetTorque();
86 }
87 }
88
89 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
90 // Register a prestep action to restore physical requirements before the next simulation step.
91 // Called at taint-time.
92 // BSActor.RemoveDependencies()
93 public override void RemoveDependencies()
94 {
95 // Nothing to do for the hoverer since it is all software at pre-step action time.
96 }
97
98 // If a hover motor has not been created, create one and start the hovering.
99 private void ActivateSetTorque()
100 {
101 if (m_torqueMotor == null)
102 {
103 // A fake motor that might be used someday
104 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
105
106 m_physicsScene.BeforeStep += Mover;
107 }
108 }
109
110 private void DeactivateSetTorque()
111 {
112 if (m_torqueMotor != null)
113 {
114 m_physicsScene.BeforeStep -= Mover;
115 m_torqueMotor = null;
116 }
117 }
118
119 // Called just before the simulation step. Update the vertical position for hoverness.
120 private void Mover(float timeStep)
121 {
122 // Don't do force while the object is selected.
123 if (!isActive)
124 return;
125
126 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
127 if (m_controllingPrim.PhysBody.HasPhysicalBody)
128 {
129 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
130 m_controllingPrim.ActivateIfPhysical(false);
131 }
132
133 // TODO:
134 }
135}
136}
137
138
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActors.cs
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31namespace OpenSim.Region.Physics.BulletSPlugin
32{
33public 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>
124public 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)]
88public struct ShapeData 89public 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)]
112public struct SweepHit 113public 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)]
120public struct RaycastHit 121public 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)]
127public struct CollisionDesc 128public 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)]
135public struct EntityProperties 137public 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)]
197public 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
209public enum ActivationState : uint 212public 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
296public abstract string BulletEngineName { get; } 300public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;} 301public abstract string BulletEngineVersion { get; protected set;}
298 302
299// Initialization and simulation 303// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 304public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -305,7 +309,7 @@ public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, 309public 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
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); 312public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
309 313
310public abstract void Shutdown(BulletWorld sim); 314public abstract void Shutdown(BulletWorld sim);
311 315
@@ -320,7 +324,13 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
320public abstract BulletShape CreateHullShape(BulletWorld world, 324public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls); 325 int hullCount, float[] hulls);
322 326
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); 327public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
328
329public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
330
331public abstract BulletShape CreateConvexHullShape(BulletWorld world,
332 int indicesCount, int[] indices,
333 int verticesCount, float[] vertices );
324 334
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); 335public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326 336
@@ -342,26 +352,28 @@ public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape c
342 352
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); 353public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344 354
355public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
356
345public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); 357public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
346 358
347public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); 359public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
348 360
349public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); 361public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
350 362
351public abstract CollisionObjectTypes GetBodyType(BulletBody obj); 363public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
352 364
353public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 365public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
354 366
355public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); 367public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
356 368
357public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 369public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
358 370
359public abstract void DestroyObject(BulletWorld sim, BulletBody obj); 371public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
360 372
361// ===================================================================================== 373// =====================================================================================
362public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); 374public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
363 375
364public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 376public 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
390public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
391 Vector3 frameInBloc, Quaternion frameInBrot,
392 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
393
394public 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
378public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 399public 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
404public 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
409public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
410 Vector3 frameInAloc, Quaternion frameInArot,
411 Vector3 frameInBloc, Quaternion frameInBrot,
412 bool disableCollisionsBetweenLinkedBodies);
413
414public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
415 Vector3 axisInA, Vector3 axisInB,
416 float ratio, bool disableCollisionsBetweenLinkedBodies);
417
418public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 pivotInA, Vector3 pivotInB,
420 bool disableCollisionsBetweenLinkedBodies);
421
383public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); 422public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
384 423
385public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); 424public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
@@ -607,7 +646,7 @@ public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
607 646
608public abstract int GetNumConstraintRefs(BulletBody obj); 647public abstract int GetNumConstraintRefs(BulletBody obj);
609 648
610public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); 649public 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
649public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject); 688public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
689
690public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
691
692public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
650 693
651public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape); 694public virtual void DumpActivationInfo(BulletWorld sim) { }
652 695
653public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain); 696public virtual void DumpAllInfo(BulletWorld sim) { }
654 697
655public abstract void DumpActivationInfo(BulletWorld sim); 698public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
656 699
657public abstract void DumpAllInfo(BulletWorld sim); 700public virtual void ResetBroadphasePool(BulletWorld sim) { }
658 701
659public abstract void DumpPhysicsStatistics(BulletWorld sim); 702public 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;
35using System.Reflection; 35using System.Reflection;
36using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
39 40
40namespace OpenSim.Region.Physics.BulletSPlugin 41namespace 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;
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace 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.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo 42sealed 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
67public sealed class BSLinksetCompound : BSLinkset 94public 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// ============================================================================
249public class BSFMotor : BSMotor 244public 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.
277public class BSPIDVMotor : BSVMotor 368public 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 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Text; 30using System.Text;
30 31
31using OpenSim.Region.Physics.Manager; 32using OpenSim.Region.Physics.Manager;
@@ -37,14 +38,41 @@ namespace OpenSim.Region.Physics.BulletSPlugin
37{ 38{
38public static class BSParam 39public 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.
59public 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}
58public abstract class BSPhysObject : PhysicsActor 68public 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]
42public sealed class BSPrim : BSPhysObject 42public 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
33using System;
34using System.Collections.Generic;
35using System.Reflection;
36using System.Runtime.InteropServices;
37using OpenMetaverse;
38using OpenSim.Framework;
39using OpenSim.Region.Physics.Manager;
40
41using OMV = OpenMetaverse;
42
43namespace OpenSim.Region.Physics.BulletSPlugin
44{
45public 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 */
27using System;
28using System.Collections.Generic;
29using System.Linq;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OMV = OpenMetaverse;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public 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 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Linq;
29using System.Reflection; 30using System.Reflection;
30using System.Runtime.InteropServices; 31using System.Runtime.InteropServices;
31using System.Text; 32using 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
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Text; 30using System.Text;
32 31
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34using OpenSim.Region.Physics.ConvexDecompositionDotNet;
35
36using OMV = OpenMetaverse;
37
33namespace OpenSim.Region.Physics.BulletSPlugin 38namespace OpenSim.Region.Physics.BulletSPlugin
34{ 39{
35public abstract class BSShape 40public 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// ============================================================================================================
116public class BSShapeNull : BSShape 258public 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// ============================================================================================================
125public class BSShapeNative : BSShape 269public 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// ============================================================================================================
183public class BSShapeMesh : BSShape 342public 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// ============================================================================================================
195public class BSShapeHull : BSShape 495public 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// ============================================================================================================
207public class BSShapeCompound : BSShape 735public 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// ============================================================================================================
838public 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// ============================================================================================================
220public class BSShapeAvatar : BSShape 933public 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.
221public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 227public 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 @@
1PROBLEMS TO LOOK INTO
2=================================================
3Nebadon 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.
5Hitting 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
7Two of Nebadon vehicles in a sim max the CPU. This is new.
8A sitting, active vehicle bobs up and down a small amount.
9
1CURRENT PRIORITIES 10CURRENT PRIORITIES
2================================================= 11=================================================
3Redo BulletSimAPI to allow native C# implementation of Bullet option. 12Use the HACD convex hull routine in Bullet rather than the C# version.
4Avatar 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
8llMoveToTarget
9Enable vehicle border crossings (at least as poorly as ODE) 14Enable 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)
13Vehicle movement on terrain smoothness 18Deleting 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.
20Linkset 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.
23Refarb 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
25Vehicle angular vertical attraction
26vehicle angular banking
27Center-of-gravity
28Vehicle angular deflection
29 Preferred orientation angular correction fix
30when should angular and linear motor targets be zeroed? when selected?
31 Need a vehicle.clear()? Or an 'else' in prestep if not physical.
32Teravus 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)
35limitMotorUp calibration (more down?)
36llRotLookAt
37llLookAt
38Avatars walking up stairs (HALF DONE)
39Avatar 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)
14Vehicle script tuning/debugging 43Vehicle script tuning/debugging
15 Avanti speed script 44 Avanti speed script
16 Weapon shooter script 45 Weapon shooter script
17limitMotorUp calibration (more down?) 46Move material definitions (friction, ...) into simulator.
18Boats float low in the water
19Add material densities to the material types. 47Add material densities to the material types.
20 48One sided meshes? Should terrain be built into a closed shape?
21CRASHES 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.
2320121129.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
2520121128.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.
2820121206.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
32VEHICLES TODO LIST: 53VEHICLES TODO LIST:
33================================================= 54=================================================
34Angular motor direction is global coordinates rather than local coordinates 55LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
56 What are the limits in SL?
57 Same for other velocity settings.
58UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
59 https://github.com/UbitUmarov/Ubit-opensim
35Border crossing with linked vehicle causes crash 60Border crossing with linked vehicle causes crash
61 20121129.1411: editting/moving phys object across region boundries causes crash
62 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
36Vehicles (Move smoothly) 63Vehicles (Move smoothly)
37Add vehicle collisions so IsColliding is properly reported.
38 Needed for banking, limitMotorUp, movementLimiting, ...
39VehicleAddForce is not scaled by the simulation step but it is only
40 applied for one step. Should it be scaled?
41Some vehicles should not be able to turn if no speed or off ground. 64Some vehicles should not be able to turn if no speed or off ground.
65What to do if vehicle and prim buoyancy differ?
42Cannot edit/move a vehicle being ridden: it jumps back to the origional position. 66Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
43Neb car jiggling left and right 67Neb 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.
46Implement referenceFrame for all the motion routines. 70Implement referenceFrame for all the motion routines.
47Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. 71For 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.
49Verify llGetVel() is returning a smooth and good value for vehicle movement. 72Verify llGetVel() is returning a smooth and good value for vehicle movement.
50llGetVel() should return the root's velocity if requested in a child prim. 73llGetVel() should return the root's velocity if requested in a child prim.
51Implement function efficiency for lineaar and angular motion. 74Implement function efficiency for lineaar and angular motion.
52After getting off a vehicle, the root prim is phantom (can be walked through) 75After 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
54Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) 77Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
55For limitMotorUp, use raycast down to find if vehicle is in the air.
56Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). 78Remove 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.
58Incorporate inter-relationship of angular corrections. For instance, angularDeflection 80Incorporate 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.
83Vehicle 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
62BULLETSIM TODO LIST: 86GENERAL TODO LIST:
63================================================= 87=================================================
88Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
89 Regular triangle meshes don't do physical collisions.
90Resitution of a prim works on another prim but not on terrain.
91 The dropped prim doesn't bounce properly on the terrain.
92Add a sanity check for PIDTarget location.
93Level-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.
95Collisions 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.
99llMoveToTarget objects are not effected by gravity until target is removed.
100Compute CCD parameters based on body size
101Can solver iterations be changed per body/shape? Can be for constraints but what
102 about regular vehicles?
103Implement llSetPhysicalMaterial.
104 extend it with Center-of-mass, rolling friction, density
105Implement llSetForceAndTorque.
106Change BSPrim.moveToTarget to used forces rather than changing position
107 Changing position allows one to move through walls
64Implement an avatar mesh shape. The Bullet capsule is way too limited. 108Implement 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.
110Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
66Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. 111Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
67Duplicating a physical prim causes old prim to jump away 112Duplicating 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.
86Implement raycast. 131Implement raycast.
87Implement ShapeCollection.Dispose() 132Implement ShapeCollection.Dispose()
88Implement water as a plain so raycasting and collisions can happen with same. 133Implement water as a plain so raycasting and collisions can happen with same.
134Add collision penetration return
135 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
89Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE 136Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
90 Also osGetPhysicsEngineVerion() maybe. 137 Also osGetPhysicsEngineVerion() maybe.
91Linkset.Position and Linkset.Orientation requre rewrite to properly return 138Linkset.Position and Linkset.Orientation requre rewrite to properly return
@@ -107,6 +154,12 @@ Physical and phantom will drop through the terrain
107 154
108LINKSETS 155LINKSETS
109====================================================== 156======================================================
157Child prims do not report collisions
158Allow 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.
161Editing 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
110Offset the center of the linkset to be the geometric center of all the prims 163Offset 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
112Linksets should allow collisions to individual children 165Linksets should allow collisions to individual children
@@ -117,11 +170,9 @@ LinksetCompound: when one of the children changes orientation (like tires
117Verify/think through scripts in children of linksets. What do they reference 170Verify/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, ...
119Confirm constraint linksets still work after making all the changes for compound linksets. 172Confirm constraint linksets still work after making all the changes for compound linksets.
173Use PostTaint callback to do rebuilds for constraint linksets to reduce rebuilding
120Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. 174Add '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.
122Disable 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, ...
125Speed up creation of large physical linksets 176Speed 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
132MORE 183MORE
133====================================================== 184======================================================
134Test avatar walking up stairs. How does compare with SL. 185Compute 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. 186Create 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
190Do 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.
136Debounce avatar contact so legs don't keep folding up when standing. 193Debounce avatar contact so legs don't keep folding up when standing.
137Implement LSL physics controls. Like STATUS_ROTATE_X. 194Implement LSL physics controls. Like STATUS_ROTATE_X.
138Add border extensions to terrain to help region crossings and objects leaving region. 195Add border extensions to terrain to help region crossings and objects leaving region.
139Use a different capsule shape for avatar when sitting 196Use 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
143Performance test with lots of avatars. Can BulletSim support a thousand? 199Performance test with lots of avatars. Can BulletSim support a thousand?
144Optimize collisions in C++: only send up to the object subscribed to collisions. 200Optimize 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)
146Check whether SimMotionState needs large if statement (see TODO). 202Check whether SimMotionState needs large if statement (see TODO).
147
148Implement 'top colliders' info. 203Implement 'top colliders' info.
149Avatar jump 204Avatar jump
150Performance measurement and changes to make quicker. 205Performance measurement and changes to make quicker.
151Implement detailed physics stats (GetStats()). 206Implement detailed physics stats (GetStats()).
152
153Measure performance improvement from hulls 207Measure performance improvement from hulls
154Test not using ghost objects for volume detect implementation. 208Test not using ghost objects for volume detect implementation.
155Performance of closures and delegates for taint processing 209Performance 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?
158Is there are more efficient method of implementing pre and post step actions? 212Is 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
161Physics Arena central pyramid: why is one side permiable? 214Physics Arena central pyramid: why is one side permiable?
162
163In SL, perfect spheres don't seem to have rolling friction. Add special case. 215In SL, perfect spheres don't seem to have rolling friction. Add special case.
164Enforce physical parameter min/max: 216Enforce 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
170Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html 222Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
223Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
171 224
172INTERNAL IMPROVEMENT/CLEANUP 225INTERNAL IMPROVEMENT/CLEANUP
173================================================= 226=================================================
227Can 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.
174Create the physical wrapper classes (BulletBody, BulletShape) by methods on 229Create 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.
190Generalize Linkset and vehicles into PropertyManagers 245Generalize 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.
193Complete implemention of preStepActions 248Better 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?
196Implement linkset by setting position of children when root updated. (LinksetManual) 250Implement linkset by setting position of children when root updated. (LinksetManual)
197 Linkset implementation using manual prim movement. 251 Linkset implementation using manual prim movement.
198LinkablePrim class? Would that simplify/centralize the linkset logic? 252LinkablePrim class? Would that simplify/centralize the linkset logic?
199BSScene.UpdateParameterSet() is broken. How to set params on objects? 253BSScene.UpdateParameterSet() is broken. How to set params on objects?
200Remove HeightmapInfo from terrain specification
201 Since C++ code does not need terrain height, this structure et al are not needed.
202Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will 254Add 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()
204Should taints check for existance or activeness of target? 256Should 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?
209Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones) 261Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
210Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'? 262Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
211There are TOO MANY interfaces from BulletSim core to Bullet itself 263There 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)
271Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE) 323Avatar 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)
325Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
326 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
327Meshes rendering as bounding boxes (DONE)
328 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
329llMoveToTarget (Resolution: added simple motor to update the position.)
330Angular motor direction is global coordinates rather than local coordinates (DONE)
331Add 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)
334VehicleAddForce 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)
337Complete implemention of preStepActions (DONE)
338 Replace vehicle step call with prestep event.
339 Is there a need for postStepActions? postStepTaints?
340Disable 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, ...
343Remove HeightmapInfo from terrain specification (DONE)
344 Since C++ code does not need terrain height, this structure et al are not needed.
345Surfboard 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)
348Mantis 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)
352Boats float low in the water (DONE)
353Boats floating at proper level (DONE)
354When 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)
356Child movement in linkset (don't rebuild linkset) (DONE 20130122))
357Avatar standing on a moving object should start to move with the object. (DONE 20130125)
358Angular 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.
361Nebadon vehicles turning funny in arena (DONE)
362Lock axis (DONE 20130401)
363Terrain 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