aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/PhysicsModules/BulletS
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs)315
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs2589
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs457
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs174
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs219
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs220
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs138
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs139
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSActors.cs154
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs)245
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs)572
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs)10
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs)39
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs (renamed from OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs)15
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs54
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs)4
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs (renamed from OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs)22
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs103
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs (renamed from OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs)1099
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs503
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs477
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs852
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs)5
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSMotors.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs)246
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSParam.cs927
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs620
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs1895
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs182
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs349
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSScene.cs1333
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs425
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSShapes.cs1463
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs)42
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs)244
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs440
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs)72
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt (renamed from OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt)249
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs622
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs)7
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs156
-rwxr-xr-x[-rw-r--r--]OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppWriter.cs)113
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs109
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs205
43 files changed, 17044 insertions, 1060 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
index 8c6e7d6..c4a923c 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -35,7 +35,7 @@ using OpenSim.Framework;
35 35
36using OpenMetaverse; 36using OpenMetaverse;
37 37
38namespace OpenSim.Region.Physics.BulletSPlugin 38namespace OpenSim.Region.PhysicsModule.BulletS
39{ 39{
40public sealed class BSAPIUnman : BSAPITemplate 40public sealed class BSAPIUnman : BSAPITemplate
41{ 41{
@@ -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)
@@ -238,23 +251,52 @@ public override BulletShape CreateMeshShape(BulletWorld world,
238 BSPhysicsShapeType.SHAPE_MESH); 251 BSPhysicsShapeType.SHAPE_MESH);
239} 252}
240 253
254public override BulletShape CreateGImpactShape(BulletWorld world,
255 int indicesCount, int[] indices,
256 int verticesCount, float[] vertices)
257{
258 BulletWorldUnman worldu = world as BulletWorldUnman;
259 return new BulletShapeUnman(
260 BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
261 BSPhysicsShapeType.SHAPE_GIMPACT);
262}
263
241public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) 264public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
242{ 265{
243 BulletWorldUnman worldu = world as BulletWorldUnman; 266 BulletWorldUnman worldu = world as BulletWorldUnman;
244 return new BulletShapeUnman( 267 return new BulletShapeUnman(
245 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), 268 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
246 BSPhysicsShapeType.SHAPE_HULL); 269 BSPhysicsShapeType.SHAPE_HULL);
247} 270}
248 271
249public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) 272public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
250{ 273{
251 BulletWorldUnman worldu = world as BulletWorldUnman; 274 BulletWorldUnman worldu = world as BulletWorldUnman;
252 BulletShapeUnman shapeu = meshShape as BulletShapeUnman; 275 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
253 return new BulletShapeUnman( 276 return new BulletShapeUnman(
254 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr), 277 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
255 BSPhysicsShapeType.SHAPE_HULL); 278 BSPhysicsShapeType.SHAPE_HULL);
256} 279}
257 280
281public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
282{
283 BulletWorldUnman worldu = world as BulletWorldUnman;
284 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
285 return new BulletShapeUnman(
286 BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
287 BSPhysicsShapeType.SHAPE_CONVEXHULL);
288}
289
290public override BulletShape CreateConvexHullShape(BulletWorld world,
291 int indicesCount, int[] indices,
292 int verticesCount, float[] vertices)
293{
294 BulletWorldUnman worldu = world as BulletWorldUnman;
295 return new BulletShapeUnman(
296 BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
297 BSPhysicsShapeType.SHAPE_CONVEXHULL);
298}
299
258public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) 300public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
259{ 301{
260 BulletWorldUnman worldu = world as BulletWorldUnman; 302 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -273,7 +315,7 @@ public override void SetShapeCollisionMargin(BulletShape shape, float margin)
273{ 315{
274 BulletShapeUnman shapeu = shape as BulletShapeUnman; 316 BulletShapeUnman shapeu = shape as BulletShapeUnman;
275 if (shapeu != null && shapeu.HasPhysicalShape) 317 if (shapeu != null && shapeu.HasPhysicalShape)
276 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin); 318 BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
277} 319}
278 320
279public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) 321public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
@@ -327,6 +369,12 @@ public override void RemoveChildShapeFromCompoundShape(BulletShape shape, Bullet
327 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); 369 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
328} 370}
329 371
372public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
373{
374 BulletShapeUnman shapeu = pShape as BulletShapeUnman;
375 BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
376}
377
330public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) 378public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
331{ 379{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman; 380 BulletShapeUnman shapeu = shape as BulletShapeUnman;
@@ -337,7 +385,7 @@ public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletSha
337{ 385{
338 BulletWorldUnman worldu = world as BulletWorldUnman; 386 BulletWorldUnman worldu = world as BulletWorldUnman;
339 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; 387 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
340 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type); 388 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
341} 389}
342 390
343public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) 391public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
@@ -419,6 +467,28 @@ public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
419 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 467 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
420} 468}
421 469
470public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
471 Vector3 frameInBloc, Quaternion frameInBrot,
472 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
473{
474 BulletWorldUnman worldu = world as BulletWorldUnman;
475 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
476 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
477 frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
478}
479
480public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
481 Vector3 frame1loc, Quaternion frame1rot,
482 Vector3 frame2loc, Quaternion frame2rot,
483 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
484{
485 BulletWorldUnman worldu = world as BulletWorldUnman;
486 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
487 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
488 return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
489 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
490}
491
422public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 492public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
423 Vector3 pivotinA, Vector3 pivotinB, 493 Vector3 pivotinA, Vector3 pivotinB,
424 Vector3 axisInA, Vector3 axisInB, 494 Vector3 axisInA, Vector3 axisInB,
@@ -431,6 +501,52 @@ public override BulletConstraint CreateHingeConstraint(BulletWorld world, Bullet
431 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 501 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
432} 502}
433 503
504public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
505 Vector3 frame1loc, Quaternion frame1rot,
506 Vector3 frame2loc, Quaternion frame2rot,
507 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
508{
509 BulletWorldUnman worldu = world as BulletWorldUnman;
510 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
511 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
512 return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
513 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
514}
515
516public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
517 Vector3 frame1loc, Quaternion frame1rot,
518 Vector3 frame2loc, Quaternion frame2rot,
519 bool disableCollisionsBetweenLinkedBodies)
520{
521 BulletWorldUnman worldu = world as BulletWorldUnman;
522 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
523 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
524 return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
525 frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
526}
527
528public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
529 Vector3 axisInA, Vector3 axisInB,
530 float ratio, bool disableCollisionsBetweenLinkedBodies)
531{
532 BulletWorldUnman worldu = world as BulletWorldUnman;
533 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
534 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
535 return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
536 ratio, disableCollisionsBetweenLinkedBodies));
537}
538
539public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
540 Vector3 pivotInA, Vector3 pivotInB,
541 bool disableCollisionsBetweenLinkedBodies)
542{
543 BulletWorldUnman worldu = world as BulletWorldUnman;
544 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
545 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
546 return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
547 disableCollisionsBetweenLinkedBodies));
548}
549
434public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) 550public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
435{ 551{
436 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; 552 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -480,6 +596,60 @@ public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, flo
480 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); 596 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
481} 597}
482 598
599public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
600{
601 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
602 return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
603}
604
605public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
606{
607 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
608 return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
609}
610
611public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
612{
613 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
614 return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
615}
616
617public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
618{
619 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
620 return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
621}
622
623public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
624{
625 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
626 return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
627}
628
629public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
630{
631 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
632 return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
633}
634
635public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
636{
637 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
638 return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
639}
640
641public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
642{
643 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
644 return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
645}
646
647public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
648{
649 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
650 return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
651}
652
483public override bool CalculateTransforms(BulletConstraint constrain) 653public override bool CalculateTransforms(BulletConstraint constrain)
484{ 654{
485 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; 655 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
@@ -530,12 +700,12 @@ public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
530// btDynamicsWorld entries 700// btDynamicsWorld entries
531public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) 701public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
532{ 702{
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; 703 BulletWorldUnman worldu = world as BulletWorldUnman;
537 BulletBodyUnman bodyu = obj as BulletBodyUnman; 704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
538 705
706 // Bullet resets several variables when an object is added to the world.
707 // Gravity is reset to world default depending on the static/dynamic
708 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
539 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); 709 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
540 710
541 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); 711 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
@@ -555,6 +725,13 @@ public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
555 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); 725 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
556} 726}
557 727
728public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
729{
730 BulletWorldUnman worldu = world as BulletWorldUnman;
731 BulletBodyUnman bodyu = obj as BulletBodyUnman;
732 return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
733}
734
558public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) 735public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
559{ 736{
560 BulletWorldUnman worldu = world as BulletWorldUnman; 737 BulletWorldUnman worldu = world as BulletWorldUnman;
@@ -921,6 +1098,7 @@ public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quater
921} 1098}
922 1099
923// Add a force to the object as if its mass is one. 1100// Add a force to the object as if its mass is one.
1101// Deep down in Bullet: m_totalForce += force*m_linearFactor;
924public override void ApplyCentralForce(BulletBody obj, Vector3 force) 1102public override void ApplyCentralForce(BulletBody obj, Vector3 force)
925{ 1103{
926 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1104 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -964,6 +1142,7 @@ public override void SetSleepingThresholds(BulletBody obj, float lin_threshold,
964 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); 1142 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
965} 1143}
966 1144
1145// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
967public override void ApplyTorque(BulletBody obj, Vector3 torque) 1146public override void ApplyTorque(BulletBody obj, Vector3 torque)
968{ 1147{
969 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1148 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -971,6 +1150,8 @@ public override void ApplyTorque(BulletBody obj, Vector3 torque)
971} 1150}
972 1151
973// Apply force at the given point. Will add torque to the object. 1152// Apply force at the given point. Will add torque to the object.
1153// Deep down in Bullet: applyCentralForce(force);
1154// applyTorque(rel_pos.cross(force*m_linearFactor));
974public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) 1155public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
975{ 1156{
976 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1157 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -978,6 +1159,7 @@ public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
978} 1159}
979 1160
980// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. 1161// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1162// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
981public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) 1163public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
982{ 1164{
983 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1165 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -985,6 +1167,7 @@ public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
985} 1167}
986 1168
987// Apply impulse to the object's torque. Force is scaled by object's mass. 1169// Apply impulse to the object's torque. Force is scaled by object's mass.
1170// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
988public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) 1171public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
989{ 1172{
990 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1173 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -992,6 +1175,8 @@ public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
992} 1175}
993 1176
994// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. 1177// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1178// Deep down in Bullet: applyCentralImpulse(impulse);
1179// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
995public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) 1180public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
996{ 1181{
997 BulletBodyUnman bodyu = obj as BulletBodyUnman; 1182 BulletBodyUnman bodyu = obj as BulletBodyUnman;
@@ -1259,6 +1444,16 @@ public override void DumpPhysicsStatistics(BulletWorld world)
1259 BulletWorldUnman worldu = world as BulletWorldUnman; 1444 BulletWorldUnman worldu = world as BulletWorldUnman;
1260 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); 1445 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1261} 1446}
1447public override void ResetBroadphasePool(BulletWorld world)
1448{
1449 BulletWorldUnman worldu = world as BulletWorldUnman;
1450 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1451}
1452public override void ResetConstraintSolver(BulletWorld world)
1453{
1454 BulletWorldUnman worldu = world as BulletWorldUnman;
1455 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1456}
1262 1457
1263// ===================================================================================== 1458// =====================================================================================
1264// ===================================================================================== 1459// =====================================================================================
@@ -1302,11 +1497,24 @@ public static extern IntPtr CreateMeshShape2(IntPtr world,
1302 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); 1497 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1303 1498
1304[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern IntPtr CreateGImpactShape2(IntPtr world,
1501 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1502 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1503
1504[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1305public static extern IntPtr CreateHullShape2(IntPtr world, 1505public static extern IntPtr CreateHullShape2(IntPtr world,
1306 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); 1506 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1307 1507
1308[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1309public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape); 1509public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
1510
1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern IntPtr CreateConvexHullShape2(IntPtr world,
1516 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1517 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1310 1518
1311[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1519[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1312public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); 1520public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
@@ -1315,7 +1523,7 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
1315public static extern bool IsNativeShape2(IntPtr shape); 1523public static extern bool IsNativeShape2(IntPtr shape);
1316 1524
1317[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1318public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin); 1526public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
1319 1527
1320[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1321public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 1529public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
@@ -1339,6 +1547,9 @@ public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShap
1339public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 1547public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1340 1548
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); 1553public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1343 1554
1344[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1368,7 +1579,7 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1368public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); 1579public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1369 1580
1370[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1371public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, 1582public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1372 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, 1583 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1373 float scaleFactor, float collisionMargin); 1584 float scaleFactor, float collisionMargin);
1374 1585
@@ -1386,12 +1597,46 @@ public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr ob
1386 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 1597 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1387 1598
1388[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
1601 Vector3 frameInBloc, Quaternion frameInBrot,
1602 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
1603
1604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1605public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1606 Vector3 frame1loc, Quaternion frame1rot,
1607 Vector3 frame2loc, Quaternion frame2rot,
1608 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1609
1610[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1389public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 1611public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1390 Vector3 pivotinA, Vector3 pivotinB, 1612 Vector3 pivotinA, Vector3 pivotinB,
1391 Vector3 axisInA, Vector3 axisInB, 1613 Vector3 axisInA, Vector3 axisInB,
1392 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 1614 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1393 1615
1394[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1617public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1618 Vector3 frameInAloc, Quaternion frameInArot,
1619 Vector3 frameInBloc, Quaternion frameInBrot,
1620 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1621
1622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1623public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1624 Vector3 frameInAloc, Quaternion frameInArot,
1625 Vector3 frameInBloc, Quaternion frameInBrot,
1626 bool disableCollisionsBetweenLinkedBodies);
1627
1628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1629public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1630 Vector3 axisInA, Vector3 axisInB,
1631 float ratio, bool disableCollisionsBetweenLinkedBodies);
1632
1633[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1634public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1635 Vector3 pivotInA, Vector3 pivotInB,
1636 bool disableCollisionsBetweenLinkedBodies);
1637
1638
1639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1395public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); 1640public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1396 1641
1397[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1417,6 +1662,33 @@ public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enabl
1417public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); 1662public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1418 1663
1419[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1664[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1665public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
1666
1667[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1668public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
1669
1670[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1671public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
1672
1673[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1674public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
1675
1676[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1677public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
1678
1679[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1680public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
1681
1682[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1683public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
1684
1685[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1686public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
1687
1688[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1689public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
1690
1691[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1420public static extern bool CalculateTransforms2(IntPtr constrain); 1692public static extern bool CalculateTransforms2(IntPtr constrain);
1421 1693
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1694[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1448,6 +1720,9 @@ public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1448public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 1720public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1449 1721
1450[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1723public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
1724
1725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1451public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); 1726public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1452 1727
1453[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -1832,6 +2107,12 @@ public static extern void DumpAllInfo2(IntPtr sim);
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 2107[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void DumpPhysicsStatistics2(IntPtr sim); 2108public static extern void DumpPhysicsStatistics2(IntPtr sim);
1834 2109
2110[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2111public static extern void ResetBroadphasePool(IntPtr sim);
2112
2113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
2114public static extern void ResetConstraintSolver(IntPtr sim);
2115
1835} 2116}
1836 2117
1837} 2118}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
new file mode 100755
index 0000000..887311d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
@@ -0,0 +1,2589 @@
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.IO;
30using System.Runtime.InteropServices;
31using System.Text;
32
33using OpenSim.Framework;
34
35using OpenMetaverse;
36
37using BulletXNA;
38using BulletXNA.LinearMath;
39using BulletXNA.BulletCollision;
40using BulletXNA.BulletDynamics;
41using BulletXNA.BulletCollision.CollisionDispatch;
42
43namespace OpenSim.Region.PhysicsModule.BulletS
44{
45public sealed class BSAPIXNA : BSAPITemplate
46{
47private sealed class BulletWorldXNA : BulletWorld
48{
49 public DiscreteDynamicsWorld world;
50 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
51 : base(id, physScene)
52 {
53 world = xx;
54 }
55}
56
57private sealed class BulletBodyXNA : BulletBody
58{
59 public CollisionObject body;
60 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
61
62 public BulletBodyXNA(uint id, CollisionObject xx)
63 : base(id)
64 {
65 body = xx;
66 }
67 public override bool HasPhysicalBody
68 {
69 get { return body != null; }
70 }
71 public override void Clear()
72 {
73 body = null;
74 }
75 public override string AddrString
76 {
77 get { return "XNARigidBody"; }
78 }
79}
80
81private sealed class BulletShapeXNA : BulletShape
82{
83 public CollisionShape shape;
84 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
85 : base()
86 {
87 shape = xx;
88 shapeType = typ;
89 }
90 public override bool HasPhysicalShape
91 {
92 get { return shape != null; }
93 }
94 public override void Clear()
95 {
96 shape = null;
97 }
98 public override BulletShape Clone()
99 {
100 return new BulletShapeXNA(shape, shapeType);
101 }
102 public override bool ReferenceSame(BulletShape other)
103 {
104 BulletShapeXNA otheru = other as BulletShapeXNA;
105 return (otheru != null) && (this.shape == otheru.shape);
106
107 }
108 public override string AddrString
109 {
110 get { return "XNACollisionShape"; }
111 }
112}
113private sealed class BulletConstraintXNA : BulletConstraint
114{
115 public TypedConstraint constrain;
116 public BulletConstraintXNA(TypedConstraint xx) : base()
117 {
118 constrain = xx;
119 }
120
121 public override void Clear()
122 {
123 constrain = null;
124 }
125 public override bool HasPhysicalConstraint { get { return constrain != null; } }
126
127 // Used for log messages for a unique display of the memory/object allocated to this instance
128 public override string AddrString
129 {
130 get { return "XNAConstraint"; }
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;
141
142 private static int m_collisionsThisFrame;
143 private BSScene PhysicsScene { get; set; }
144
145 public override string BulletEngineName { get { return "BulletXNA"; } }
146 public override string BulletEngineVersion { get; protected set; }
147
148 public BSAPIXNA(string paramName, BSScene physScene)
149 {
150 PhysicsScene = physScene;
151 }
152
153 /// <summary>
154 ///
155 /// </summary>
156 /// <param name="p"></param>
157 /// <param name="p_2"></param>
158 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
159 {
160 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
161 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
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;
169 return true;
170 }
171
172 public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
173 {
174 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
175 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
176 CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
177 if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
178 {
179 world.RemoveCollisionObject(collisionObject);
180 world.AddCollisionObject(collisionObject);
181 }
182 return true;
183 }
184
185 public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
186 {
187 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
188 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
189 world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
190
191 return true;
192
193 }
194
195 public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
196 {
197 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
198 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
199 world.RemoveConstraint(constraint);
200 return true;
201 }
202
203 public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
204 {
205 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
206 collisionObject.SetRestitution(pRestitution);
207 }
208
209 public override int GetShapeType(BulletShape pShape)
210 {
211 CollisionShape shape = (pShape as BulletShapeXNA).shape;
212 return (int)shape.GetShapeType();
213 }
214 public override void SetMargin(BulletShape pShape, float pMargin)
215 {
216 CollisionShape shape = (pShape as BulletShapeXNA).shape;
217 shape.SetMargin(pMargin);
218 }
219
220 public override float GetMargin(BulletShape pShape)
221 {
222 CollisionShape shape = (pShape as BulletShapeXNA).shape;
223 return shape.GetMargin();
224 }
225
226 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
227 {
228 CollisionShape shape = (pShape as BulletShapeXNA).shape;
229 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
230 shape.SetLocalScaling(ref vec);
231
232 }
233
234 public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
235 {
236 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
237 collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
238 }
239
240 public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
241 {
242 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
243 collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
244 }
245
246 public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
247 {
248 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
249 collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
250 }
251
252 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
253 {
254 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
255 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
256 }
257
258 public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
259 {
260 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
261 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
262 existingcollisionFlags |= pcollisionFlags;
263 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
264 return (CollisionFlags) (uint) existingcollisionFlags;
265 }
266
267 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
268 {
269 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
270 CollisionObject cbody = (pBody as BulletBodyXNA).body;
271 RigidBody rbody = cbody as RigidBody;
272
273 // Bullet resets several variables when an object is added to the world. In particular,
274 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
275 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
276 IndexedMatrix origPos = cbody.GetWorldTransform();
277 if (rbody != null)
278 {
279 IndexedVector3 origGrav = rbody.GetGravity();
280 world.AddRigidBody(rbody);
281 rbody.SetGravity(origGrav);
282 }
283 else
284 {
285 world.AddCollisionObject(cbody);
286 }
287 cbody.SetWorldTransform(origPos);
288
289 pBody.ApplyCollisionMask(pWorld.physicsScene);
290
291 //if (body.GetBroadphaseHandle() != null)
292 // world.UpdateSingleAabb(body);
293 return true;
294 }
295
296 public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
297 {
298 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
299 collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
300 }
301
302 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
303 {
304 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
305 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
306 world.UpdateSingleAabb(collisionObject);
307 }
308
309 public override void UpdateAabbs(BulletWorld pWorld) {
310 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
311 world.UpdateAabbs();
312 }
313 public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
314 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
315 return world.GetForceUpdateAllAabbs();
316
317 }
318 public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
319 {
320 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
321 world.SetForceUpdateAllAabbs(pForce);
322 }
323
324 public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
325 {
326 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
327 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
328 collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
329 if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
330 return false;
331 return true;
332 }
333
334 public override void ClearAllForces(BulletBody pCollisionObject)
335 {
336 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
337 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
338 collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
339 collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
340 IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
341
342 collisionObject.SetInterpolationWorldTransform(ref bodytransform);
343
344 if (collisionObject is RigidBody)
345 {
346 RigidBody rigidbody = collisionObject as RigidBody;
347 rigidbody.SetLinearVelocity(zeroVector);
348 rigidbody.SetAngularVelocity(zeroVector);
349 rigidbody.ClearForces();
350 }
351 }
352
353 public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
354 {
355 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
356 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
357 collisionObject.SetInterpolationAngularVelocity(ref vec);
358 }
359
360 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
361 {
362 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
363 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
364 body.SetAngularVelocity(ref vec);
365 }
366 public override Vector3 GetTotalForce(BulletBody pBody)
367 {
368 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
369 IndexedVector3 iv3 = body.GetTotalForce();
370 return new Vector3(iv3.X, iv3.Y, iv3.Z);
371 }
372 public override Vector3 GetTotalTorque(BulletBody pBody)
373 {
374 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
375 IndexedVector3 iv3 = body.GetTotalTorque();
376 return new Vector3(iv3.X, iv3.Y, iv3.Z);
377 }
378 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
379 {
380 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
381 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
382 return new Vector3(iv3.X, iv3.Y, iv3.Z);
383 }
384 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
385 {
386 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
387 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
388 body.SetInvInertiaDiagLocal(ref iv3);
389 }
390 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
391 {
392 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
393 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
394 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
395 body.ApplyForce(ref forceiv3, ref posiv3);
396 }
397 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
398 {
399 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
400 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
401 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
402 body.ApplyImpulse(ref impiv3, ref posiv3);
403 }
404
405 public override void ClearForces(BulletBody pBody)
406 {
407 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
408 body.ClearForces();
409 }
410
411 public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
412 {
413 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
414 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
415 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
416 _orientation.W);
417 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
418 mat._origin = vposition;
419 collisionObject.SetWorldTransform(mat);
420
421 }
422
423 public override Vector3 GetPosition(BulletBody pCollisionObject)
424 {
425 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
426 IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
427 return new Vector3(pos.X, pos.Y, pos.Z);
428 }
429
430 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
431 {
432 CollisionShape shape = (pShape as BulletShapeXNA).shape;
433 IndexedVector3 inertia = IndexedVector3.Zero;
434 shape.CalculateLocalInertia(pphysMass, out inertia);
435 return new Vector3(inertia.X, inertia.Y, inertia.Z);
436 }
437
438 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
439 {
440 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
441 if (body != null) // Can't set mass props on collision object.
442 {
443 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
444 body.SetMassProps(pphysMass, inertia);
445 }
446 }
447
448
449 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
450 {
451 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
452 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
453 body.SetTotalForce(ref force);
454 }
455
456 public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
457 {
458 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
459 collisionObject.SetFriction(_currentFriction);
460 }
461
462 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
463 {
464 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
465 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
466 body.SetLinearVelocity(velocity);
467 }
468
469 public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
470 {
471 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
472 collisionObject.Activate(pforceactivation);
473
474 }
475
476 public override Quaternion GetOrientation(BulletBody pCollisionObject)
477 {
478 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
479 IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
480 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
481 }
482
483 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
484 {
485 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
486 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
487 existingcollisionFlags &= ~pcollisionFlags;
488 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
489 return (CollisionFlags)(uint)existingcollisionFlags;
490 }
491
492 public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
493 {
494 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
495 return collisionObject.GetCcdSquareMotionThreshold();
496 }
497
498 public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
499 {
500 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
501 return collisionObject.GetCcdSweptSphereRadius();
502
503 }
504
505 public override IntPtr GetUserPointer(BulletBody pCollisionObject)
506 {
507 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
508 return (IntPtr)shape.GetUserPointer();
509 }
510
511 public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
512 {
513 CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
514 shape.SetUserPointer(val);
515 }
516
517 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
518 {
519 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
520 if (body != null) // Can't set collisionobject.set gravity
521 {
522 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
523 body.SetGravity(gravity);
524 }
525 }
526
527 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
528 {
529 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
530 TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
531 world.RemoveConstraint(constraint);
532 return true;
533 }
534
535 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
536 {
537 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
538 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
539 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
540 constraint.SetLinearLowerLimit(lowlimit);
541 constraint.SetLinearUpperLimit(highlimit);
542 return true;
543 }
544
545 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
546 {
547 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
548 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
549 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
550 constraint.SetAngularLowerLimit(lowlimit);
551 constraint.SetAngularUpperLimit(highlimit);
552 return true;
553 }
554
555 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
556 {
557 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
558 constraint.SetOverrideNumSolverIterations((int)cnt);
559 }
560
561 public override bool CalculateTransforms(BulletConstraint pConstraint)
562 {
563 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
564 constraint.CalculateTransforms();
565 return true;
566 }
567
568 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
569 {
570 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
571 constraint.SetEnabled((p_2 == 0) ? false : true);
572 }
573
574
575 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
576 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
577 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
578
579 {
580 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
581 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
582 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
583 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
584 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
585 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
586 frame1._origin = frame1v;
587
588 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
589 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
590 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
591 frame2._origin = frame1v;
592
593 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
594 puseLinearReferenceFrameA);
595 consttr.CalculateTransforms();
596 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
597
598 return new BulletConstraintXNA(consttr);
599 }
600
601 public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
602 Vector3 pframe1, Quaternion pframe1rot,
603 bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
604 {
605 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
606 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
607 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
608 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
609 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
610 frame1._origin = frame1v;
611
612 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
613 consttr.CalculateTransforms();
614 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
615
616 return new BulletConstraintXNA(consttr);
617 }
618
619 /// <summary>
620 ///
621 /// </summary>
622 /// <param name="pWorld"></param>
623 /// <param name="pBody1"></param>
624 /// <param name="pBody2"></param>
625 /// <param name="pjoinPoint"></param>
626 /// <param name="puseLinearReferenceFrameA"></param>
627 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
628 /// <returns></returns>
629 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
630 {
631 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
632 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
633 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
634 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
635 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
636
637 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
638 IndexedMatrix mat = IndexedMatrix.Identity;
639 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
640 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
641 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
642
643 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
644 consttr.CalculateTransforms();
645 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
646
647 return new BulletConstraintXNA(consttr);
648 }
649 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
650 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
651 {
652 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
653 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
654 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
655 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
656 frame1._origin = frame1v;
657
658 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
659 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
660 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
661 frame2._origin = frame2v;
662 constraint.SetFrames(ref frame1, ref frame2);
663 return true;
664 }
665
666 public override Vector3 GetLinearVelocity(BulletBody pBody)
667 {
668 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
669 IndexedVector3 iv3 = body.GetLinearVelocity();
670 return new Vector3(iv3.X, iv3.Y, iv3.Z);
671 }
672 public override Vector3 GetAngularVelocity(BulletBody pBody)
673 {
674 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
675 IndexedVector3 iv3 = body.GetAngularVelocity();
676 return new Vector3(iv3.X, iv3.Y, iv3.Z);
677 }
678 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
679 {
680 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
681 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
682 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
683 return new Vector3(iv3.X, iv3.Y, iv3.Z);
684 }
685 public override void Translate(BulletBody pCollisionObject, Vector3 trans)
686 {
687 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
688 collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
689 }
690 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
691 {
692 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
693 body.UpdateDeactivation(timeStep);
694 }
695
696 public override bool WantsSleeping(BulletBody pBody)
697 {
698 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
699 return body.WantsSleeping();
700 }
701
702 public override void SetAngularFactor(BulletBody pBody, float factor)
703 {
704 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
705 body.SetAngularFactor(factor);
706 }
707
708 public override Vector3 GetAngularFactor(BulletBody pBody)
709 {
710 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
711 IndexedVector3 iv3 = body.GetAngularFactor();
712 return new Vector3(iv3.X, iv3.Y, iv3.Z);
713 }
714
715 public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
716 {
717 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
718 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
719 return world.IsInWorld(collisionObject);
720 }
721
722 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
723 {
724 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
725 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
726 body.AddConstraintRef(constrain);
727 }
728
729 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
730 {
731 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
732 TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
733 body.RemoveConstraintRef(constrain);
734 }
735
736 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
737 {
738 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
739 return new BulletConstraintXNA(body.GetConstraintRef(index));
740 }
741
742 public override int GetNumConstraintRefs(BulletBody pBody)
743 {
744 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
745 return body.GetNumConstraintRefs();
746 }
747
748 public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
749 {
750 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
751 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
752 collisionObject.SetInterpolationLinearVelocity(ref velocity);
753 }
754
755 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
756 {
757 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
758 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
759 return true;
760 }
761 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
762 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
763 {
764 Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
765 constraint.SetBreakingImpulseThreshold(threshold);
766 return true;
767 }
768 public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
769 {
770 HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
771 if (softness == HINGE_NOT_SPECIFIED)
772 constraint.SetLimit(low, high);
773 else
774 constraint.SetLimit(low, high, softness, bias, relaxation);
775 return true;
776 }
777 public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
778 {
779 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
780 constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
781 return true;
782 }
783
784 public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
785 {
786 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
787 if (index == SPRING_NOT_SPECIFIED)
788 {
789 constraint.SetEquilibriumPoint();
790 }
791 else
792 {
793 if (equilibriumPoint == SPRING_NOT_SPECIFIED)
794 constraint.SetEquilibriumPoint(index);
795 else
796 constraint.SetEquilibriumPoint(index, equilibriumPoint);
797 }
798 return true;
799 }
800
801 public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
802 {
803 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
804 constraint.SetStiffness(index, stiffness);
805 return true;
806 }
807
808 public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
809 {
810 Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
811 constraint.SetDamping(index, damping);
812 return true;
813 }
814
815 public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
816 {
817 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
818 switch (lowerUpper)
819 {
820 case SLIDER_LOWER_LIMIT:
821 switch (linAng)
822 {
823 case SLIDER_LINEAR:
824 constraint.SetLowerLinLimit(val);
825 break;
826 case SLIDER_ANGULAR:
827 constraint.SetLowerAngLimit(val);
828 break;
829 }
830 break;
831 case SLIDER_UPPER_LIMIT:
832 switch (linAng)
833 {
834 case SLIDER_LINEAR:
835 constraint.SetUpperLinLimit(val);
836 break;
837 case SLIDER_ANGULAR:
838 constraint.SetUpperAngLimit(val);
839 break;
840 }
841 break;
842 }
843 return true;
844 }
845 public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
846 {
847 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
848 switch (softRestDamp)
849 {
850 case SLIDER_SET_SOFTNESS:
851 switch (dirLimOrtho)
852 {
853 case SLIDER_SET_DIRECTION:
854 switch (linAng)
855 {
856 case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
857 case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
858 }
859 break;
860 case SLIDER_SET_LIMIT:
861 switch (linAng)
862 {
863 case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
864 case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
865 }
866 break;
867 case SLIDER_SET_ORTHO:
868 switch (linAng)
869 {
870 case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
871 case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
872 }
873 break;
874 }
875 break;
876 case SLIDER_SET_RESTITUTION:
877 switch (dirLimOrtho)
878 {
879 case SLIDER_SET_DIRECTION:
880 switch (linAng)
881 {
882 case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
883 case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
884 }
885 break;
886 case SLIDER_SET_LIMIT:
887 switch (linAng)
888 {
889 case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
890 case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
891 }
892 break;
893 case SLIDER_SET_ORTHO:
894 switch (linAng)
895 {
896 case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
897 case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
898 }
899 break;
900 }
901 break;
902 case SLIDER_SET_DAMPING:
903 switch (dirLimOrtho)
904 {
905 case SLIDER_SET_DIRECTION:
906 switch (linAng)
907 {
908 case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
909 case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
910 }
911 break;
912 case SLIDER_SET_LIMIT:
913 switch (linAng)
914 {
915 case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
916 case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
917 }
918 break;
919 case SLIDER_SET_ORTHO:
920 switch (linAng)
921 {
922 case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
923 case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
924 }
925 break;
926 }
927 break;
928 }
929 return true;
930 }
931 public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
932 {
933 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
934 switch (linAng)
935 {
936 case SLIDER_LINEAR:
937 constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
938 break;
939 case SLIDER_ANGULAR:
940 constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
941 break;
942 }
943 return true;
944 }
945 public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
946 {
947 SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
948 switch (forceVel)
949 {
950 case SLIDER_MOTOR_VELOCITY:
951 switch (linAng)
952 {
953 case SLIDER_LINEAR:
954 constraint.SetTargetLinMotorVelocity(val);
955 break;
956 case SLIDER_ANGULAR:
957 constraint.SetTargetAngMotorVelocity(val);
958 break;
959 }
960 break;
961 case SLIDER_MAX_MOTOR_FORCE:
962 switch (linAng)
963 {
964 case SLIDER_LINEAR:
965 constraint.SetMaxLinMotorForce(val);
966 break;
967 case SLIDER_ANGULAR:
968 constraint.SetMaxAngMotorForce(val);
969 break;
970 }
971 break;
972 }
973 return true;
974 }
975
976 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
977 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
978 {
979 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
980 float lineardamping = body.GetLinearDamping();
981 body.SetDamping(lineardamping, angularDamping);
982
983 }
984
985 public override void UpdateInertiaTensor(BulletBody pBody)
986 {
987 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
988 if (body != null) // can't update inertia tensor on CollisionObject
989 body.UpdateInertiaTensor();
990 }
991
992 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
993 {
994 CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
995 shape.RecalculateLocalAabb();
996 }
997
998 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
999 public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
1000 {
1001 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1002 uint flags = (uint)collisionObject.GetCollisionFlags();
1003 return (CollisionFlags) flags;
1004 }
1005
1006 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
1007 {
1008 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1009 body.SetDamping(pLinear, pAngular);
1010 }
1011 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
1012 public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
1013 {
1014 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1015 collisionObject.SetDeactivationTime(pDeactivationTime);
1016 }
1017 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
1018 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
1019 {
1020 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1021 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
1022 }
1023
1024 public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
1025 {
1026 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1027 return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
1028 }
1029
1030 public override void ApplyGravity(BulletBody pBody)
1031 {
1032
1033 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1034 body.ApplyGravity();
1035 }
1036
1037 public override Vector3 GetGravity(BulletBody pBody)
1038 {
1039 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1040 IndexedVector3 gravity = body.GetGravity();
1041 return new Vector3(gravity.X, gravity.Y, gravity.Z);
1042 }
1043
1044 public override void SetLinearDamping(BulletBody pBody, float lin_damping)
1045 {
1046 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1047 float angularDamping = body.GetAngularDamping();
1048 body.SetDamping(lin_damping, angularDamping);
1049 }
1050
1051 public override float GetLinearDamping(BulletBody pBody)
1052 {
1053 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1054 return body.GetLinearDamping();
1055 }
1056
1057 public override float GetAngularDamping(BulletBody pBody)
1058 {
1059 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1060 return body.GetAngularDamping();
1061 }
1062
1063 public override float GetLinearSleepingThreshold(BulletBody pBody)
1064 {
1065 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1066 return body.GetLinearSleepingThreshold();
1067 }
1068
1069 public override void ApplyDamping(BulletBody pBody, float timeStep)
1070 {
1071 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1072 body.ApplyDamping(timeStep);
1073 }
1074
1075 public override Vector3 GetLinearFactor(BulletBody pBody)
1076 {
1077 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1078 IndexedVector3 linearFactor = body.GetLinearFactor();
1079 return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
1080 }
1081
1082 public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
1083 {
1084 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1085 body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
1086 }
1087
1088 public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
1089 {
1090 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1091 IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
1092 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
1093 mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
1094 body.SetCenterOfMassTransform( ref mat);
1095 /* TODO: double check this */
1096 }
1097
1098 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
1099 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
1100 {
1101 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1102 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1103 body.ApplyCentralForce(ref fSum);
1104 }
1105 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
1106 {
1107 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1108 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1109 body.ApplyCentralImpulse(ref fSum);
1110 }
1111 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
1112 {
1113 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1114 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1115 body.ApplyTorque(ref fSum);
1116 }
1117 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
1118 {
1119 RigidBody body = (pBody as BulletBodyXNA).rigidBody;
1120 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
1121 body.ApplyTorqueImpulse(ref fSum);
1122 }
1123
1124 public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
1125 {
1126 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1127 CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
1128 RigidBody bo = co as RigidBody;
1129 if (bo == null)
1130 {
1131
1132 if (world.IsInWorld(co))
1133 {
1134 world.RemoveCollisionObject(co);
1135 }
1136 }
1137 else
1138 {
1139
1140 if (world.IsInWorld(bo))
1141 {
1142 world.RemoveRigidBody(bo);
1143 }
1144 }
1145 if (co != null)
1146 {
1147 if (co.GetUserPointer() != null)
1148 {
1149 uint localId = (uint) co.GetUserPointer();
1150 if (specialCollisionObjects.ContainsKey(localId))
1151 {
1152 specialCollisionObjects.Remove(localId);
1153 }
1154 }
1155 }
1156
1157 }
1158
1159 public override void Shutdown(BulletWorld pWorld)
1160 {
1161 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1162 world.Cleanup();
1163 }
1164
1165 public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
1166 {
1167 CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
1168
1169 // TODO: Turn this from a reference copy to a Value Copy.
1170 BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
1171
1172 return shape2;
1173 }
1174
1175 public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
1176 {
1177 //TODO:
1178 return false;
1179 }
1180 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
1181
1182 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1183 {
1184 CollisionWorld world = (pWorld as BulletWorldXNA).world;
1185 IndexedMatrix mat =
1186 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1187 pRawOrientation.Z, pRawOrientation.W));
1188 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1189 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1190 //UpdateSingleAabb(world, shape);
1191 // TODO: Feed Update array into null
1192 SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
1193 RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
1194 RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
1195 {
1196 m_mass = 0
1197 };
1198 /*
1199 m_mass = mass;
1200 m_motionState =motionState;
1201 m_collisionShape = collisionShape;
1202 m_localInertia = localInertia;
1203 m_linearDamping = 0f;
1204 m_angularDamping = 0f;
1205 m_friction = 0.5f;
1206 m_restitution = 0f;
1207 m_linearSleepingThreshold = 0.8f;
1208 m_angularSleepingThreshold = 1f;
1209 m_additionalDamping = false;
1210 m_additionalDampingFactor = 0.005f;
1211 m_additionalLinearDampingThresholdSqr = 0.01f;
1212 m_additionalAngularDampingThresholdSqr = 0.01f;
1213 m_additionalAngularDampingFactor = 0.01f;
1214 m_startWorldTransform = IndexedMatrix.Identity;
1215 */
1216 body.SetUserPointer(pLocalID);
1217
1218 return new BulletBodyXNA(pLocalID, body);
1219 }
1220
1221
1222 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1223 {
1224
1225 IndexedMatrix mat =
1226 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
1227 pRawOrientation.Z, pRawOrientation.W));
1228 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1229
1230 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1231
1232 // TODO: Feed Update array into null
1233 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
1234 body.SetWorldTransform(mat);
1235 body.SetUserPointer(pLocalID);
1236 return new BulletBodyXNA(pLocalID, body);
1237 }
1238 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
1239 public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
1240 {
1241 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1242 collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
1243 return (CollisionFlags)collisionObject.GetCollisionFlags();
1244 }
1245
1246 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
1247 {
1248
1249 /* TODO */
1250 return Vector3.Zero;
1251 }
1252 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
1253 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
1254 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
1255 public override bool IsStaticObject(BulletBody pCollisionObject)
1256 {
1257 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1258 return collisionObject.IsStaticObject();
1259
1260 }
1261 public override bool IsKinematicObject(BulletBody pCollisionObject)
1262 {
1263 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1264 return collisionObject.IsKinematicObject();
1265 }
1266 public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
1267 {
1268 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1269 return collisionObject.IsStaticOrKinematicObject();
1270 }
1271 public override bool HasContactResponse(BulletBody pCollisionObject)
1272 {
1273 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1274 return collisionObject.HasContactResponse();
1275 }
1276 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
1277 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
1278 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
1279 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
1280 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
1281 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
1282 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
1283 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
1284
1285 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
1286 public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
1287 {
1288 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1289 collisionObject.SetHitFraction(pHitFraction);
1290 }
1291 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
1292 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
1293 {
1294 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1295 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
1296 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
1297 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
1298 capsuleShapeZ.SetLocalScaling(ref scale);
1299
1300 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
1301 }
1302
1303 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
1304 int maxCollisions, ref CollisionDesc[] collisionArray,
1305 int maxUpdates, ref EntityProperties[] updateArray
1306 )
1307 {
1308
1309 UpdatedObjects = updateArray;
1310 UpdatedCollisions = collisionArray;
1311 /* TODO */
1312 ConfigurationParameters[] configparms = new ConfigurationParameters[1];
1313 configparms[0] = parms;
1314 Vector3 worldExtent = maxPosition;
1315 m_maxCollisions = maxCollisions;
1316 m_maxUpdatesPerFrame = maxUpdates;
1317 specialCollisionObjects = new Dictionary<uint, GhostObject>();
1318
1319 return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
1320 }
1321
1322 private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
1323 ConfigurationParameters[] o,
1324 int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
1325 int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
1326 object mDebugLogCallbackHandle)
1327 {
1328 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
1329
1330 p.angularDamping = BSParam.AngularDamping;
1331 p.defaultFriction = o[0].defaultFriction;
1332 p.defaultFriction = o[0].defaultFriction;
1333 p.defaultDensity = o[0].defaultDensity;
1334 p.defaultRestitution = o[0].defaultRestitution;
1335 p.collisionMargin = o[0].collisionMargin;
1336 p.gravity = o[0].gravity;
1337
1338 p.linearDamping = BSParam.LinearDamping;
1339 p.angularDamping = BSParam.AngularDamping;
1340 p.deactivationTime = BSParam.DeactivationTime;
1341 p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
1342 p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
1343 p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
1344 p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
1345 p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
1346
1347 p.terrainImplementation = BSParam.TerrainImplementation;
1348 p.terrainFriction = BSParam.TerrainFriction;
1349
1350 p.terrainHitFraction = BSParam.TerrainHitFraction;
1351 p.terrainRestitution = BSParam.TerrainRestitution;
1352 p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
1353
1354 p.avatarFriction = BSParam.AvatarFriction;
1355 p.avatarStandingFriction = BSParam.AvatarStandingFriction;
1356 p.avatarDensity = BSParam.AvatarDensity;
1357 p.avatarRestitution = BSParam.AvatarRestitution;
1358 p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
1359 p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
1360 p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
1361 p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
1362
1363 p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
1364
1365 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
1366 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
1367 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
1368 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
1369 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
1370 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
1371 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
1372 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
1373
1374 p.linksetImplementation = BSParam.LinksetImplementation;
1375 p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
1376 p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
1377 p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
1378 p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
1379 p.linkConstraintERP = BSParam.LinkConstraintERP;
1380 p.linkConstraintCFM = BSParam.LinkConstraintCFM;
1381 p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
1382 p.physicsLoggingFrames = o[0].physicsLoggingFrames;
1383 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
1384
1385 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
1386 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
1387
1388
1389 if (p.maxPersistantManifoldPoolSize > 0)
1390 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
1391 if (p.shouldDisableContactPoolDynamicAllocation !=0)
1392 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
1393 //if (p.maxCollisionAlgorithmPoolSize >0 )
1394
1395 DbvtBroadphase m_broadphase = new DbvtBroadphase();
1396 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
1397 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
1398
1399 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
1400 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
1401
1402 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
1403
1404 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
1405
1406 world.LastCollisionDesc = 0;
1407 world.LastEntityProperty = 0;
1408
1409 world.WorldSettings.Params = p;
1410 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
1411 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
1412 if (p.shouldRandomizeSolverOrder != 0)
1413 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
1414
1415 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
1416 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
1417
1418 if (p.shouldEnableFrictionCaching != 0)
1419 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
1420
1421 if (p.numberOfSolverIterations > 0)
1422 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
1423
1424
1425 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
1426 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
1427 world.GetSolverInfo().m_globalCfm = 0.0f;
1428 world.GetSolverInfo().m_tau = 0.6f;
1429 world.GetSolverInfo().m_friction = 0.3f;
1430 world.GetSolverInfo().m_maxErrorReduction = 20f;
1431 world.GetSolverInfo().m_numIterations = 10;
1432 world.GetSolverInfo().m_erp = 0.2f;
1433 world.GetSolverInfo().m_erp2 = 0.1f;
1434 world.GetSolverInfo().m_sor = 1.0f;
1435 world.GetSolverInfo().m_splitImpulse = false;
1436 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1437 world.GetSolverInfo().m_linearSlop = 0.0f;
1438 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1439 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1440 world.SetForceUpdateAllAabbs(true);
1441
1442 //BSParam.TerrainImplementation = 0;
1443 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1444
1445 // Turn off Pooling since globals and pooling are bad for threading.
1446 BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false);
1447 BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false);
1448 BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false);
1449 BulletGlobals.CastResultPool.SetPoolingEnabled(false);
1450 BulletGlobals.SphereShapePool.SetPoolingEnabled(false);
1451 BulletGlobals.DbvtNodePool.SetPoolingEnabled(false);
1452 BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false);
1453 BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false);
1454 BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false);
1455 BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false);
1456 BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false);
1457 BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false);
1458 BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false);
1459 BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false);
1460 BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false);
1461 BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false);
1462
1463 BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1464 BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false);
1465 BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false);
1466 BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false);
1467 BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false);
1468 BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
1469 BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false);
1470 BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false);
1471 BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false);
1472 BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false);
1473 BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false);
1474 BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false);
1475 BulletGlobals.GJKPool.SetPoolingEnabled(false);
1476 BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false);
1477 BulletGlobals.TriangleShapePool.SetPoolingEnabled(false);
1478 BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false);
1479 BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false);
1480 BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false);
1481 BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false);
1482 BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false);
1483 BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false);
1484 BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false);
1485 BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false);
1486 BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false);
1487 BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false);
1488
1489 return world;
1490 }
1491 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1492 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1493 {
1494 Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
1495 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1496 {
1497 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1498 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1499 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1500 }
1501 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1502 {
1503 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1504 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1505 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1506 }
1507 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1508 {
1509 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1510 }
1511 return true;
1512 }
1513
1514 public override bool PushUpdate(BulletBody pCollisionObject)
1515 {
1516 bool ret = false;
1517 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1518 RigidBody rb = collisionObject as RigidBody;
1519 if (rb != null)
1520 {
1521 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1522 if (sms != null)
1523 {
1524 IndexedMatrix wt = IndexedMatrix.Identity;
1525 sms.GetWorldTransform(out wt);
1526 sms.SetWorldTransform(ref wt, true);
1527 ret = true;
1528 }
1529 }
1530 return ret;
1531
1532 }
1533
1534 public override float GetAngularMotionDisc(BulletShape pShape)
1535 {
1536 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1537 return shape.GetAngularMotionDisc();
1538 }
1539 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1540 {
1541 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1542 return shape.GetContactBreakingThreshold(defaultFactor);
1543 }
1544 public override bool IsCompound(BulletShape pShape)
1545 {
1546 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1547 return shape.IsCompound();
1548 }
1549 public override bool IsSoftBody(BulletShape pShape)
1550 {
1551 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1552 return shape.IsSoftBody();
1553 }
1554 public override bool IsPolyhedral(BulletShape pShape)
1555 {
1556 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1557 return shape.IsPolyhedral();
1558 }
1559 public override bool IsConvex2d(BulletShape pShape)
1560 {
1561 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1562 return shape.IsConvex2d();
1563 }
1564 public override bool IsConvex(BulletShape pShape)
1565 {
1566 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1567 return shape.IsConvex();
1568 }
1569 public override bool IsNonMoving(BulletShape pShape)
1570 {
1571 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1572 return shape.IsNonMoving();
1573 }
1574 public override bool IsConcave(BulletShape pShape)
1575 {
1576 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1577 return shape.IsConcave();
1578 }
1579 public override bool IsInfinite(BulletShape pShape)
1580 {
1581 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1582 return shape.IsInfinite();
1583 }
1584 public override bool IsNativeShape(BulletShape pShape)
1585 {
1586 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1587 bool ret;
1588 switch (shape.GetShapeType())
1589 {
1590 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1591 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1592 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1593 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1594 ret = true;
1595 break;
1596 default:
1597 ret = false;
1598 break;
1599 }
1600 return ret;
1601 }
1602
1603 public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
1604 {
1605 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1606 shape.SetMargin(pMargin);
1607 }
1608
1609 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1610 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1611 {
1612 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1613 IndexedMatrix bodyTransform = new IndexedMatrix();
1614 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1615 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1616 GhostObject gObj = new PairCachingGhostObject();
1617 gObj.SetWorldTransform(bodyTransform);
1618 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1619 gObj.SetCollisionShape(shape);
1620 gObj.SetUserPointer(pLocalID);
1621
1622 if (specialCollisionObjects.ContainsKey(pLocalID))
1623 specialCollisionObjects[pLocalID] = gObj;
1624 else
1625 specialCollisionObjects.Add(pLocalID, gObj);
1626
1627 // TODO: Add to Special CollisionObjects!
1628 return new BulletBodyXNA(pLocalID, gObj);
1629 }
1630
1631 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
1632 {
1633 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1634 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
1635 if (pShape == null)
1636 {
1637 collisionObject.SetCollisionShape(new EmptyShape());
1638 }
1639 else
1640 {
1641 CollisionShape shape = (pShape as BulletShapeXNA).shape;
1642 collisionObject.SetCollisionShape(shape);
1643 }
1644 }
1645 public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
1646 {
1647 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
1648 CollisionShape shape = collisionObject.GetCollisionShape();
1649 return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1650 }
1651
1652 //(PhysicsScene.World.ptr, nativeShapeData)
1653 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1654 {
1655 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1656 CollisionShape shape = null;
1657 switch (pShapeData.Type)
1658 {
1659 case BSPhysicsShapeType.SHAPE_BOX:
1660 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1661 break;
1662 case BSPhysicsShapeType.SHAPE_CONE:
1663 shape = new ConeShapeZ(0.5f, 1.0f);
1664 break;
1665 case BSPhysicsShapeType.SHAPE_CYLINDER:
1666 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1667 break;
1668 case BSPhysicsShapeType.SHAPE_SPHERE:
1669 shape = new SphereShape(0.5f);
1670 break;
1671
1672 }
1673 if (shape != null)
1674 {
1675 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1676 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1677 shape.SetLocalScaling(ref scaling);
1678
1679 }
1680 return new BulletShapeXNA(shape, pShapeData.Type);
1681 }
1682 //PhysicsScene.World.ptr, false
1683 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1684 {
1685 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1686 }
1687
1688 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1689 {
1690 CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
1691 return compoundshape.GetNumChildShapes();
1692 }
1693 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1694 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1695 {
1696 IndexedMatrix relativeTransform = new IndexedMatrix();
1697 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1698 CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
1699
1700 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1701 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1702 compoundshape.AddChildShape(ref relativeTransform, addshape);
1703
1704 }
1705
1706 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1707 {
1708 CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
1709 CollisionShape ret = null;
1710 ret = compoundshape.GetChildShape(pii);
1711 compoundshape.RemoveChildShapeByIndex(pii);
1712 return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
1713 }
1714
1715 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
1716
1717 if (cShape == null)
1718 return null;
1719 CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
1720 CollisionShape shape = compoundShape.GetChildShape(indx);
1721 BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
1722
1723
1724 return retShape;
1725 }
1726
1727 public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
1728 {
1729 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1730 switch (pin)
1731 {
1732 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1733 ret = BSPhysicsShapeType.SHAPE_BOX;
1734 break;
1735 case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
1736 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1737 break;
1738
1739 case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
1740 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1741 break;
1742 case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
1743 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1744 break;
1745 case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
1746 ret = BSPhysicsShapeType.SHAPE_HULL;
1747 break;
1748 case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
1749 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1750 break;
1751 case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
1752 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1753 break;
1754 //implicit convex shapes
1755 case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
1756 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1757 break;
1758 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1759 ret = BSPhysicsShapeType.SHAPE_SPHERE;
1760 break;
1761 case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
1762 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1763 break;
1764 case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
1765 ret = BSPhysicsShapeType.SHAPE_CAPSULE;
1766 break;
1767 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1768 ret = BSPhysicsShapeType.SHAPE_CONE;
1769 break;
1770 case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
1771 ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
1772 break;
1773 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1774 ret = BSPhysicsShapeType.SHAPE_CYLINDER;
1775 break;
1776 case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
1777 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1778 break;
1779 case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
1780 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1781 break;
1782 case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
1783 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1784 break;
1785 case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
1786 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1787 break;
1788 case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
1789 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1790 break;
1791 case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
1792 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1793 break;
1794 //concave shape
1795 case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
1796 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1797 break;
1798 //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
1799 case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
1800 ret = BSPhysicsShapeType.SHAPE_MESH;
1801 break;
1802 case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
1803 ret = BSPhysicsShapeType.SHAPE_MESH;
1804 break;
1805 ///used for demo integration FAST/Swift collision library and Bullet
1806 case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
1807 ret = BSPhysicsShapeType.SHAPE_MESH;
1808 break;
1809 //terrain
1810 case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
1811 ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
1812 break;
1813 ///Used for GIMPACT Trimesh integration
1814 case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
1815 ret = BSPhysicsShapeType.SHAPE_GIMPACT;
1816 break;
1817 ///Multimaterial mesh
1818 case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
1819 ret = BSPhysicsShapeType.SHAPE_MESH;
1820 break;
1821
1822 case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
1823 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1824 break;
1825 case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
1826 ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
1827 break;
1828 case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
1829 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1830 break;
1831 case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
1832 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1833 break;
1834
1835 case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
1836 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
1837 break;
1838
1839 case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
1840 ret = BSPhysicsShapeType.SHAPE_MESH;
1841 break;
1842 case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
1843 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1844 break;
1845 case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
1846 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1847 break;
1848 case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
1849 ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
1850 break;
1851 }
1852 return ret;
1853 }
1854
1855 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1856 public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
1857
1858 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1859 {
1860 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1861 m_planeshape.SetMargin(pcollisionMargin);
1862 m_planeshape.SetUserPointer(pLocalId);
1863 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1864 }
1865
1866 public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1867 Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
1868 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1869
1870 {
1871 Generic6DofSpringConstraint constrain = null;
1872 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1873 RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
1874 RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
1875 if (body1 != null && body2 != null)
1876 {
1877 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1878 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1879 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1880 frame1._origin = frame1v;
1881
1882 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1883 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1884 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1885 frame2._origin = frame1v;
1886
1887 constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1888 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1889
1890 constrain.CalculateTransforms();
1891 }
1892
1893 return new BulletConstraintXNA(constrain);
1894 }
1895
1896 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1897 Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
1898 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1899 {
1900 HingeConstraint constrain = null;
1901 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1902 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1903 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1904 if (rb1 != null && rb2 != null)
1905 {
1906 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1907 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1908 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1909 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1910 constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
1911 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1912 }
1913 return new BulletConstraintXNA(constrain);
1914 }
1915
1916 public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1917 Vector3 pframe1, Quaternion pframe1rot,
1918 Vector3 pframe2, Quaternion pframe2rot,
1919 bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1920 {
1921 SliderConstraint constrain = null;
1922 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1923 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1924 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1925 if (rb1 != null && rb2 != null)
1926 {
1927 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1928 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1929 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1930 frame1._origin = frame1v;
1931
1932 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1933 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1934 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1935 frame2._origin = frame1v;
1936
1937 constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
1938 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1939 }
1940 return new BulletConstraintXNA(constrain);
1941 }
1942
1943 public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1944 Vector3 pframe1, Quaternion pframe1rot,
1945 Vector3 pframe2, Quaternion pframe2rot,
1946 bool pdisableCollisionsBetweenLinkedBodies)
1947 {
1948 ConeTwistConstraint constrain = null;
1949 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1950 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1951 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1952 if (rb1 != null && rb2 != null)
1953 {
1954 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
1955 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
1956 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
1957 frame1._origin = frame1v;
1958
1959 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
1960 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
1961 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
1962 frame2._origin = frame1v;
1963
1964 constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
1965 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1966 }
1967 return new BulletConstraintXNA(constrain);
1968 }
1969
1970 public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1971 Vector3 paxisInA, Vector3 paxisInB,
1972 float pratio, bool pdisableCollisionsBetweenLinkedBodies)
1973 {
1974 Generic6DofConstraint constrain = null;
1975 /* BulletXNA does not have a gear constraint
1976 GearConstraint constrain = null;
1977 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1978 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1979 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1980 if (rb1 != null && rb2 != null)
1981 {
1982 IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1983 IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1984 constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
1985 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1986 }
1987 */
1988 return new BulletConstraintXNA(constrain);
1989 }
1990
1991 public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
1992 Vector3 ppivotInA, Vector3 ppivotInB,
1993 bool pdisableCollisionsBetweenLinkedBodies)
1994 {
1995 Point2PointConstraint constrain = null;
1996 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
1997 RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
1998 RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
1999 if (rb1 != null && rb2 != null)
2000 {
2001 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
2002 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
2003 constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
2004 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
2005 }
2006 return new BulletConstraintXNA(constrain);
2007 }
2008
2009 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
2010 {
2011 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2012 CompoundShape compoundshape = new CompoundShape(false);
2013
2014 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
2015 int ii = 1;
2016
2017 for (int i = 0; i < pHullCount; i++)
2018 {
2019 int vertexCount = (int) pConvHulls[ii];
2020
2021 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
2022 IndexedMatrix childTrans = IndexedMatrix.Identity;
2023 childTrans._origin = centroid;
2024
2025 List<IndexedVector3> virts = new List<IndexedVector3>();
2026 int ender = ((ii + 4) + (vertexCount*3));
2027 for (int iii = ii + 4; iii < ender; iii+=3)
2028 {
2029
2030 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
2031 }
2032 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
2033 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2034 compoundshape.AddChildShape(ref childTrans, convexShape);
2035 ii += (vertexCount*3 + 4);
2036 }
2037
2038 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
2039 }
2040
2041 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
2042 {
2043 /* TODO */ return null;
2044 }
2045
2046 public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
2047 {
2048 /* TODO */ return null;
2049 }
2050
2051 public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2052 {
2053 /* TODO */ return null;
2054 }
2055
2056 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2057 {
2058 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
2059
2060 for (int iter = 0; iter < pVerticesCount; iter++)
2061 {
2062 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
2063 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
2064 }
2065
2066 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
2067 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
2068 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
2069 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2070 IndexedMesh mesh = new IndexedMesh();
2071 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2072 mesh.m_numTriangles = pIndicesCount/3;
2073 mesh.m_numVertices = pVerticesCount;
2074 mesh.m_triangleIndexBase = indicesarr;
2075 mesh.m_vertexBase = vertices;
2076 mesh.m_vertexStride = 3;
2077 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2078 mesh.m_triangleIndexStride = 3;
2079
2080 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2081 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2082 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
2083 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
2084 // world.UpdateSingleAabb(meshShape);
2085 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
2086
2087 }
2088 public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
2089 {
2090 // TODO:
2091 return null;
2092 }
2093 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
2094 {
2095
2096 String fileName = "objTest3.raw";
2097 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2098 StreamWriter sw = new StreamWriter(completePath);
2099 IndexedMesh mesh = new IndexedMesh();
2100
2101 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2102 mesh.m_numTriangles = pIndicesCount / 3;
2103 mesh.m_numVertices = pVerticesCount;
2104 mesh.m_triangleIndexBase = indices;
2105 mesh.m_vertexBase = vertices;
2106 mesh.m_vertexStride = 3;
2107 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2108 mesh.m_triangleIndexStride = 3;
2109
2110 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2111 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2112
2113
2114
2115 for (int i = 0; i < pVerticesCount; i++)
2116 {
2117
2118 string s = vertices[indices[i * 3]].ToString("0.0000");
2119 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2120 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2121
2122 sw.Write(s + "\n");
2123 }
2124
2125 sw.Close();
2126 }
2127 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
2128 {
2129
2130 String fileName = "objTest6.raw";
2131 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
2132 StreamWriter sw = new StreamWriter(completePath);
2133 IndexedMesh mesh = new IndexedMesh();
2134
2135 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
2136 mesh.m_numTriangles = pIndicesCount / 3;
2137 mesh.m_numVertices = pVerticesCount;
2138 mesh.m_triangleIndexBase = indices;
2139 mesh.m_vertexBase = vertices;
2140 mesh.m_vertexStride = 3;
2141 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
2142 mesh.m_triangleIndexStride = 3;
2143
2144 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
2145 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
2146
2147
2148 sw.WriteLine("Indices");
2149 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
2150 for (int iter = 0; iter < indices.Length; iter++)
2151 {
2152 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
2153 }
2154 sw.WriteLine("VerticesFloats");
2155 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
2156 for (int iter = 0; iter < vertices.Length; iter++)
2157 {
2158 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
2159 }
2160
2161 // for (int i = 0; i < pVerticesCount; i++)
2162 // {
2163 //
2164 // string s = vertices[indices[i * 3]].ToString("0.0000");
2165 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
2166 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
2167 //
2168 // sw.Write(s + "\n");
2169 //}
2170
2171 sw.Close();
2172 }
2173
2174 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
2175 float scaleFactor, float collisionMargin)
2176 {
2177 const int upAxis = 2;
2178 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
2179 heightMap, scaleFactor,
2180 minHeight, maxHeight, upAxis,
2181 false);
2182 terrainShape.SetMargin(collisionMargin);
2183 terrainShape.SetUseDiamondSubdivision(true);
2184 terrainShape.SetUserPointer(id);
2185 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
2186 }
2187
2188 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
2189 {
2190 TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
2191 bool onOff = ponOff != 0;
2192 bool ret = false;
2193
2194 switch (tconstrain.GetConstraintType())
2195 {
2196 case TypedConstraintType.D6_CONSTRAINT_TYPE:
2197 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
2198 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
2199 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
2200 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
2201 ret = true;
2202 break;
2203 }
2204
2205
2206 return ret;
2207
2208 }
2209
2210 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
2211 out int updatedEntityCount, out int collidersCount)
2212 {
2213 /* TODO */
2214 updatedEntityCount = 0;
2215 collidersCount = 0;
2216
2217
2218 int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
2219
2220 return ret;
2221 }
2222
2223 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
2224 out int updatedEntityCount, out EntityProperties[] updatedEntities,
2225 out int collidersCount, out CollisionDesc[] colliders)
2226 {
2227 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
2228 out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
2229 return epic;
2230 }
2231
2232 private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
2233 out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
2234 {
2235 int numSimSteps = 0;
2236 Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
2237 Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
2238 LastEntityProperty=0;
2239
2240
2241
2242
2243
2244
2245 LastCollisionDesc=0;
2246
2247 updatedEntityCount = 0;
2248 collidersCount = 0;
2249
2250
2251 if (pWorld is BulletWorldXNA)
2252 {
2253 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2254
2255 world.LastCollisionDesc = 0;
2256 world.LastEntityProperty = 0;
2257 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
2258
2259 PersistentManifold contactManifold;
2260 CollisionObject objA;
2261 CollisionObject objB;
2262 ManifoldPoint manifoldPoint;
2263 PairCachingGhostObject pairCachingGhostObject;
2264
2265 m_collisionsThisFrame = 0;
2266 int numManifolds = world.GetDispatcher().GetNumManifolds();
2267 for (int j = 0; j < numManifolds; j++)
2268 {
2269 contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
2270 int numContacts = contactManifold.GetNumContacts();
2271 if (numContacts == 0)
2272 continue;
2273
2274 objA = contactManifold.GetBody0() as CollisionObject;
2275 objB = contactManifold.GetBody1() as CollisionObject;
2276
2277 manifoldPoint = contactManifold.GetContactPoint(0);
2278 //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
2279 // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
2280
2281 RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
2282 m_collisionsThisFrame ++;
2283 if (m_collisionsThisFrame >= 9999999)
2284 break;
2285
2286
2287 }
2288
2289 foreach (GhostObject ghostObject in specialCollisionObjects.Values)
2290 {
2291 pairCachingGhostObject = ghostObject as PairCachingGhostObject;
2292 if (pairCachingGhostObject != null)
2293 {
2294 RecordGhostCollisions(pairCachingGhostObject);
2295 }
2296
2297 }
2298
2299
2300 updatedEntityCount = LastEntityProperty;
2301 updatedEntities = UpdatedObjects;
2302
2303 collidersCount = LastCollisionDesc;
2304 colliders = UpdatedCollisions;
2305
2306
2307 }
2308 else
2309 {
2310 //if (updatedEntities is null)
2311 //updatedEntities = new List<BulletXNA.EntityProperties>();
2312 //updatedEntityCount = 0;
2313
2314
2315 //collidersCount = 0;
2316
2317 updatedEntities = new EntityProperties[0];
2318
2319
2320 colliders = new CollisionDesc[0];
2321
2322 }
2323 return numSimSteps;
2324 }
2325 public void RecordGhostCollisions(PairCachingGhostObject obj)
2326 {
2327 IOverlappingPairCache cache = obj.GetOverlappingPairCache();
2328 ObjectArray<BroadphasePair> pairs = cache.GetOverlappingPairArray();
2329
2330 DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
2331 PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
2332 BroadphasePair collisionPair;
2333 PersistentManifold contactManifold;
2334
2335 CollisionObject objA;
2336 CollisionObject objB;
2337
2338 ManifoldPoint pt;
2339
2340 int numPairs = pairs.Count;
2341
2342 for (int i = 0; i < numPairs; i++)
2343 {
2344 manifoldArray.Clear();
2345 if (LastCollisionDesc < UpdatedCollisions.Length)
2346 break;
2347 collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
2348 if (collisionPair == null)
2349 continue;
2350
2351 collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
2352 for (int j = 0; j < manifoldArray.Count; j++)
2353 {
2354 contactManifold = manifoldArray[j];
2355 int numContacts = contactManifold.GetNumContacts();
2356 objA = contactManifold.GetBody0() as CollisionObject;
2357 objB = contactManifold.GetBody1() as CollisionObject;
2358 for (int p = 0; p < numContacts; p++)
2359 {
2360 pt = contactManifold.GetContactPoint(p);
2361 if (pt.GetDistance() < 0.0f)
2362 {
2363 RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
2364 break;
2365 }
2366 }
2367 }
2368 }
2369
2370 }
2371 private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
2372 {
2373
2374 IndexedVector3 contactNormal = norm;
2375 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
2376 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
2377 {
2378 return;
2379 }
2380 uint idA = (uint)objA.GetUserPointer();
2381 uint idB = (uint)objB.GetUserPointer();
2382 if (idA > idB)
2383 {
2384 uint temp = idA;
2385 idA = idB;
2386 idB = temp;
2387 contactNormal = -contactNormal;
2388 }
2389
2390 //ulong collisionID = ((ulong) idA << 32) | idB;
2391
2392 CollisionDesc cDesc = new CollisionDesc()
2393 {
2394 aID = idA,
2395 bID = idB,
2396 point = new Vector3(contact.X,contact.Y,contact.Z),
2397 normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
2398 penetration = penetration
2399
2400 };
2401 if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
2402 world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
2403 m_collisionsThisFrame++;
2404
2405
2406 }
2407 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
2408 {
2409 EntityProperties ent = new EntityProperties();
2410 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2411 CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
2412 IndexedMatrix transform = collisionObject.GetWorldTransform();
2413 IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
2414 IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
2415 IndexedQuaternion rotation = transform.GetRotation();
2416 ent.Acceleration = Vector3.Zero;
2417 ent.ID = (uint)collisionObject.GetUserPointer();
2418 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
2419 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
2420 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
2421 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
2422 return ent;
2423 }
2424
2425 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
2426 return false; }
2427
2428 public override Vector3 GetLocalScaling(BulletShape pShape)
2429 {
2430 CollisionShape shape = (pShape as BulletShapeXNA).shape;
2431 IndexedVector3 scale = shape.GetLocalScaling();
2432 return new Vector3(scale.X,scale.Y,scale.Z);
2433 }
2434
2435 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
2436 {
2437 DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
2438 if (world != null)
2439 {
2440 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
2441 {
2442 CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
2443
2444 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
2445 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
2446 using (
2447 ClosestNotMeRayResultCallback rayCallback =
2448 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
2449 )
2450 {
2451 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
2452 if (rayCallback.HasHit())
2453 {
2454 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
2455 }
2456 return rayCallback.HasHit();
2457 }
2458 }
2459 }
2460 return false;
2461 }
2462}
2463
2464
2465
2466
2467 public class SimMotionState : DefaultMotionState
2468 {
2469 public RigidBody Rigidbody;
2470 public Vector3 ZeroVect;
2471
2472 private IndexedMatrix m_xform;
2473
2474 private EntityProperties m_properties;
2475 private EntityProperties m_lastProperties;
2476 private BSAPIXNA m_world;
2477
2478 const float POSITION_TOLERANCE = 0.05f;
2479 const float VELOCITY_TOLERANCE = 0.001f;
2480 const float ROTATION_TOLERANCE = 0.01f;
2481 const float ANGULARVELOCITY_TOLERANCE = 0.01f;
2482
2483 public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
2484 {
2485 IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
2486 m_properties = new EntityProperties()
2487 {
2488 ID = id,
2489 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
2490 Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
2491 };
2492 m_lastProperties = new EntityProperties()
2493 {
2494 ID = id,
2495 Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
2496 Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
2497 };
2498 m_world = pWorld;
2499 m_xform = starTransform;
2500 }
2501
2502 public override void GetWorldTransform(out IndexedMatrix worldTrans)
2503 {
2504 worldTrans = m_xform;
2505 }
2506
2507 public override void SetWorldTransform(IndexedMatrix worldTrans)
2508 {
2509 SetWorldTransform(ref worldTrans);
2510 }
2511
2512 public override void SetWorldTransform(ref IndexedMatrix worldTrans)
2513 {
2514 SetWorldTransform(ref worldTrans, false);
2515 }
2516 public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
2517 {
2518 m_xform = worldTrans;
2519 // Put the new transform into m_properties
2520 IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
2521 IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
2522 IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
2523 m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
2524 m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
2525 OrientationQuaternion.Z, OrientationQuaternion.W);
2526 // A problem with stock Bullet is that we don't get an event when an object is deactivated.
2527 // This means that the last non-zero values for linear and angular velocity
2528 // are left in the viewer who does dead reconning and the objects look like
2529 // they float off.
2530 // BulletSim ships with a patch to Bullet which creates such an event.
2531 m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
2532 m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
2533
2534 if (force
2535
2536 || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
2537 || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
2538 // If the Velocity and AngularVelocity are zero, most likely the object has
2539 // been deactivated. If they both are zero and they have become zero recently,
2540 // make sure a property update is sent so the zeros make it to the viewer.
2541 || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
2542 &&
2543 (m_properties.Velocity != m_lastProperties.Velocity ||
2544 m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
2545 // If Velocity and AngularVelocity are non-zero but have changed, send an update.
2546 || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
2547 ||
2548 !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
2549 ANGULARVELOCITY_TOLERANCE)
2550 )
2551
2552
2553 {
2554 // Add this update to the list of updates for this frame.
2555 m_lastProperties = m_properties;
2556 if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
2557 m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
2558
2559 //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
2560 }
2561
2562
2563
2564
2565 }
2566 public override void SetRigidBody(RigidBody body)
2567 {
2568 Rigidbody = body;
2569 }
2570 internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
2571 {
2572 return
2573 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2574 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2575 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
2576 }
2577
2578 internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
2579 {
2580 return
2581 (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
2582 (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
2583 (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
2584 (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
2585 }
2586
2587 }
2588}
2589
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
new file mode 100755
index 0000000..0191893
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
@@ -0,0 +1,457 @@
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.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40public class BSActorAvatarMove : BSActor
41{
42 BSVMotor m_velocityMotor;
43
44 // Set to true if we think we're going up stairs.
45 // This state is remembered because collisions will turn on and off as we go up stairs.
46 int m_walkingUpStairs;
47 // The amount the step up is applying. Used to smooth stair walking.
48 float m_lastStepUp;
49
50 // Jumping happens over several frames. If use applies up force while colliding, start the
51 // jump and allow the jump to continue for this number of frames.
52 int m_jumpFrames = 0;
53 float m_jumpVelocity = 0f;
54
55 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
56 : base(physicsScene, pObj, actorName)
57 {
58 m_velocityMotor = null;
59 m_walkingUpStairs = 0;
60 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
61 }
62
63 // BSActor.isActive
64 public override bool isActive
65 {
66 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
67 }
68
69 // Release any connections and resources used by the actor.
70 // BSActor.Dispose()
71 public override void Dispose()
72 {
73 base.SetEnabled(false);
74 DeactivateAvatarMove();
75 }
76
77 // Called when physical parameters (properties set in Bullet) need to be re-applied.
78 // Called at taint-time.
79 // BSActor.Refresh()
80 public override void Refresh()
81 {
82 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
83
84 // If the object is physically active, add the hoverer prestep action
85 if (isActive)
86 {
87 ActivateAvatarMove();
88 }
89 else
90 {
91 DeactivateAvatarMove();
92 }
93 }
94
95 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
96 // Register a prestep action to restore physical requirements before the next simulation step.
97 // Called at taint-time.
98 // BSActor.RemoveDependencies()
99 public override void RemoveDependencies()
100 {
101 // Nothing to do for the hoverer since it is all software at pre-step action time.
102 }
103
104 // Usually called when target velocity changes to set the current velocity and the target
105 // into the movement motor.
106 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
107 {
108 m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
109 {
110 if (m_velocityMotor != null)
111 {
112// if (targ == OMV.Vector3.Zero)
113// Util.PrintCallStack();
114//
115// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ);
116 m_velocityMotor.Reset();
117 m_velocityMotor.SetTarget(targ);
118 m_velocityMotor.SetCurrent(vel);
119 m_velocityMotor.Enabled = true;
120 }
121 });
122 }
123
124 // If a hover motor has not been created, create one and start the hovering.
125 private void ActivateAvatarMove()
126 {
127 if (m_velocityMotor == null)
128 {
129 // Infinite decay and timescale values so motor only changes current to target values.
130 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
131 0.2f, // time scale
132 BSMotor.Infinite, // decay time scale
133 1f // efficiency
134 );
135 m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
136 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
137 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
138
139 m_physicsScene.BeforeStep += Mover;
140 m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
141
142 m_walkingUpStairs = 0;
143 }
144 }
145
146 private void DeactivateAvatarMove()
147 {
148 if (m_velocityMotor != null)
149 {
150 m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
151 m_physicsScene.BeforeStep -= Mover;
152 m_velocityMotor = null;
153 }
154 }
155
156 // Called just before the simulation step. Update the vertical position for hoverness.
157 private void Mover(float timeStep)
158 {
159 // Don't do movement while the object is selected.
160 if (!isActive)
161 return;
162
163 // TODO: Decide if the step parameters should be changed depending on the avatar's
164 // state (flying, colliding, ...). There is code in ODE to do this.
165
166 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
167 // specified for the avatar is the one that should be used. For falling, if the avatar
168 // is not flying and is not colliding then it is presumed to be falling and the Z
169 // component is not fooled with (thus allowing gravity to do its thing).
170 // When the avatar is standing, though, the user has specified a velocity of zero and
171 // the avatar should be standing. But if the avatar is pushed by something in the world
172 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
173 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
174 // errors can creap in and the avatar will slowly float off in some direction.
175 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
176 // from real pushing.
177 // The code below uses whether the collider is static or moving to decide whether to zero motion.
178
179 m_velocityMotor.Step(timeStep);
180 m_controllingPrim.IsStationary = false;
181
182 // If we're not supposed to be moving, make sure things are zero.
183 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
184 {
185 // The avatar shouldn't be moving
186 m_velocityMotor.Zero();
187
188 if (m_controllingPrim.IsColliding)
189 {
190 // If we are colliding with a stationary object, presume we're standing and don't move around
191 if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect)
192 {
193 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
194 m_controllingPrim.IsStationary = true;
195 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
196 }
197
198 // Standing has more friction on the ground
199 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
200 {
201 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
202 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
203 }
204 }
205 else
206 {
207 if (m_controllingPrim.Flying)
208 {
209 // Flying and not colliding and velocity nearly zero.
210 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
211 }
212 else
213 {
214 //We are falling but are not touching any keys make sure not falling too fast
215 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
216 {
217
218 OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass;
219 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce);
220 }
221
222 }
223 }
224
225 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
226 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
227 }
228 else
229 {
230 // Supposed to be moving.
231 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
232
233 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
234 {
235 // Probably starting to walk. Set friction to moving friction.
236 m_controllingPrim.Friction = BSParam.AvatarFriction;
237 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
238 }
239
240 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
241 {
242 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
243 }
244
245 // Colliding and not flying with an upward force. The avatar must be trying to jump.
246 if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0)
247 {
248 // We allow the upward force to happen for this many frames.
249 m_jumpFrames = BSParam.AvatarJumpFrames;
250 m_jumpVelocity = stepVelocity.Z;
251 }
252
253 // The case where the avatar is not colliding and is not flying is special.
254 // The avatar is either falling or jumping and the user can be applying force to the avatar
255 // (force in some direction or force up or down).
256 // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity.
257 // If the user is trying to apply upward force but we're not colliding, assume the avatar
258 // is trying to jump and don't apply the upward force if not touching the ground any more.
259 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
260 {
261 // If upward velocity is being applied, this must be a jump and only allow that to go on so long
262 if (m_jumpFrames > 0)
263 {
264 // Since not touching the ground, only apply upward force for so long.
265 m_jumpFrames--;
266 stepVelocity.Z = m_jumpVelocity;
267 }
268 else
269 {
270
271 // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast.
272 if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
273 {
274
275 stepVelocity.Z = BSParam.AvatarTerminalVelocity;
276 }
277 else
278 {
279 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
280 }
281 }
282 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
283 }
284
285 //Alicia: Maintain minimum height when flying.
286 // SL has a flying effect that keeps the avatar flying above the ground by some margin
287 if (m_controllingPrim.Flying)
288 {
289 float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition)
290 + BSParam.AvatarFlyingGroundMargin;
291
292 if( m_controllingPrim.Position.Z < hover_height)
293 {
294 stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce;
295 }
296 }
297
298 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
299 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
300
301 // Add special movement force to allow avatars to walk up stepped surfaces.
302 moveForce += WalkUpStairs();
303
304 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
305 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
306 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
307 }
308 }
309
310 // Called just as the property update is received from the physics engine.
311 // Do any mode necessary for avatar movement.
312 private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
313 {
314 // Don't change position if standing on a stationary object.
315 if (m_controllingPrim.IsStationary)
316 {
317 entprop.Position = m_controllingPrim.RawPosition;
318 entprop.Velocity = OMV.Vector3.Zero;
319 m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
320 }
321
322 }
323
324 // Decide if the character is colliding with a low object and compute a force to pop the
325 // avatar up so it can walk up and over the low objects.
326 private OMV.Vector3 WalkUpStairs()
327 {
328 OMV.Vector3 ret = OMV.Vector3.Zero;
329
330 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
331 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
332 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
333
334 // Check for stairs climbing if colliding, not flying and moving forward
335 if ( m_controllingPrim.IsColliding
336 && !m_controllingPrim.Flying
337 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
338 {
339 // The range near the character's feet where we will consider stairs
340 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
341 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
342 // from the height. Revisit size and this computation when height is scaled properly.
343 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge;
344 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
345
346 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
347 // Find the highest 'good' collision.
348 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
349 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
350 {
351 // Don't care about collisions with the terrain
352 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
353 {
354 BSPhysObject collisionObject;
355 if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject))
356 {
357 if (!collisionObject.IsVolumeDetect)
358 {
359 OMV.Vector3 touchPosition = kvp.Value.Position;
360 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
361 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
362 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
363 {
364 // This contact is within the 'near the feet' range.
365 // The step is presumed to be more or less vertical. Thus the Z component should
366 // be nearly horizontal.
367 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
368 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
369 const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles
370 // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}",
371 // m_controllingPrim.LocalID, directionFacing, touchNormal,
372 // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) );
373 if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle
374 && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle)
375 {
376 // The normal should be our contact point to the object so it is pointing away
377 // thus the difference between our facing orientation and the normal should be small.
378 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
379 if (diff < BSParam.AvatarStepApproachFactor)
380 {
381 if (highestTouchPosition.Z < touchPosition.Z)
382 highestTouchPosition = touchPosition;
383 }
384 }
385 }
386 }
387 }
388 }
389 }
390 m_walkingUpStairs = 0;
391 // If there is a good step sensing, move the avatar over the step.
392 if (highestTouchPosition != OMV.Vector3.Zero)
393 {
394 // Remember that we are going up stairs. This is needed because collisions
395 // will stop when we move up so this smoothes out that effect.
396 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
397
398 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
399 ret = ComputeStairCorrection(m_lastStepUp);
400 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
401 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
402 }
403 }
404 else
405 {
406 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
407 // we are bouncing up the stairs.
408 if (m_walkingUpStairs > 0)
409 {
410 m_walkingUpStairs--;
411 ret = ComputeStairCorrection(m_lastStepUp);
412 }
413 }
414
415 return ret;
416 }
417
418 private OMV.Vector3 ComputeStairCorrection(float stepUp)
419 {
420 OMV.Vector3 ret = OMV.Vector3.Zero;
421 OMV.Vector3 displacement = OMV.Vector3.Zero;
422
423 if (stepUp > 0f)
424 {
425 // Found the stairs contact point. Push up a little to raise the character.
426 if (BSParam.AvatarStepForceFactor > 0f)
427 {
428 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
429 ret = new OMV.Vector3(0f, 0f, upForce);
430 }
431
432 // Also move the avatar up for the new height
433 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
434 {
435 // Move the avatar up related to the height of the collision
436 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
437 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
438 }
439 else
440 {
441 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
442 {
443 // Move the avatar up about the specified step height
444 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
445 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
446 }
447 }
448 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}",
449 m_controllingPrim.LocalID, stepUp, displacement, ret);
450
451 }
452 return ret;
453 }
454}
455}
456
457
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
new file mode 100755
index 0000000..7ff171e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
@@ -0,0 +1,174 @@
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.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
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 DeactivateHover();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, turn me off
72 if (!m_controllingPrim.HoverActive)
73 {
74 SetEnabled(false);
75 }
76
77 // If the object is physically active, add the hoverer prestep action
78 if (isActive)
79 {
80 ActivateHover();
81 }
82 else
83 {
84 DeactivateHover();
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 hoverer 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 ActivateHover()
99 {
100 if (m_hoverMotor == null)
101 {
102 // Turning the target on
103 m_hoverMotor = new BSFMotor("BSActorHover",
104 m_controllingPrim.HoverTau, // timeScale
105 BSMotor.Infinite, // decay time scale
106 1f // efficiency
107 );
108 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
109 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
110 m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
111
112 m_physicsScene.BeforeStep += Hoverer;
113 }
114 }
115
116 private void DeactivateHover()
117 {
118 if (m_hoverMotor != null)
119 {
120 m_physicsScene.BeforeStep -= Hoverer;
121 m_hoverMotor = null;
122 }
123 }
124
125 // Called just before the simulation step. Update the vertical position for hoverness.
126 private void Hoverer(float timeStep)
127 {
128 // Don't do hovering while the object is selected.
129 if (!isActive)
130 return;
131
132 m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
133 m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
134 float targetHeight = m_hoverMotor.Step(timeStep);
135
136 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
137 // Compute the amount of force to push us there.
138 float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
139 // Undo anything the object thinks it's doing at the moment
140 moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
141
142 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
143 m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
144 m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
145 }
146
147 // Based on current position, determine what we should be hovering at now.
148 // Must recompute often. What if we walked offa cliff>
149 private float ComputeCurrentHoverHeight()
150 {
151 float ret = m_controllingPrim.HoverHeight;
152 float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
153
154 switch (m_controllingPrim.HoverType)
155 {
156 case PIDHoverType.Ground:
157 ret = groundHeight + m_controllingPrim.HoverHeight;
158 break;
159 case PIDHoverType.GroundAndWater:
160 float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
161 if (groundHeight > waterHeight)
162 {
163 ret = groundHeight + m_controllingPrim.HoverHeight;
164 }
165 else
166 {
167 ret = waterHeight + m_controllingPrim.HoverHeight;
168 }
169 break;
170 }
171 return ret;
172 }
173}
174}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
new file mode 100755
index 0000000..78c1b6a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
@@ -0,0 +1,219 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37public class BSActorLockAxis : BSActor
38{
39 private BSConstraint LockAxisConstraint = null;
40 private bool HaveRegisteredForBeforeStepCallback = false;
41
42 // The lock access flags (which axises were locked) when the contraint was built.
43 // Used to see if locking has changed since when the constraint was built.
44 OMV.Vector3 LockAxisLinearFlags;
45 OMV.Vector3 LockAxisAngularFlags;
46
47 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
48 : base(physicsScene, pObj, actorName)
49 {
50 m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
51 LockAxisConstraint = null;
52 HaveRegisteredForBeforeStepCallback = false;
53 }
54
55 // BSActor.isActive
56 public override bool isActive
57 {
58 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
59 }
60
61 // Release any connections and resources used by the actor.
62 // BSActor.Dispose()
63 public override void Dispose()
64 {
65 Enabled = false;
66 UnRegisterForBeforeStepCallback();
67 RemoveAxisLockConstraint();
68 }
69
70 // Called when physical parameters (properties set in Bullet) need to be re-applied.
71 // Called at taint-time.
72 // BSActor.Refresh()
73 public override void Refresh()
74 {
75 // Since the axis logging is done with a constraint, Refresh() time is good for
76 // changing parameters but this needs to wait until the prim/linkset is physically
77 // constructed. Therefore, the constraint itself is placed at pre-step time.
78
79 // If all the axis are free, we don't need to exist
80 // Refresh() only turns off. Enabling is done by InitializeAxisActor()
81 // whenever parameters are changed.
82 // This leaves 'enable' free to turn off an actor when it is not wanted to run.
83 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
84 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
85 {
86 Enabled = false;
87 }
88
89 if (isActive)
90 {
91 RegisterForBeforeStepCallback();
92 }
93 else
94 {
95 RemoveDependencies();
96 UnRegisterForBeforeStepCallback();
97 }
98 }
99
100 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
101 // Register a prestep action to restore physical requirements before the next simulation step.
102 // Called at taint-time.
103 // BSActor.RemoveDependencies()
104 public override void RemoveDependencies()
105 {
106 RemoveAxisLockConstraint();
107 }
108
109 private void RegisterForBeforeStepCallback()
110 {
111 if (!HaveRegisteredForBeforeStepCallback)
112 {
113 m_physicsScene.BeforeStep += PhysicsScene_BeforeStep;
114 HaveRegisteredForBeforeStepCallback = true;
115 }
116 }
117
118 private void UnRegisterForBeforeStepCallback()
119 {
120 if (HaveRegisteredForBeforeStepCallback)
121 {
122 m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep;
123 HaveRegisteredForBeforeStepCallback = false;
124 }
125 }
126
127 private void PhysicsScene_BeforeStep(float timestep)
128 {
129 // If all the axis are free, we don't need to exist
130 if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
131 && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
132 {
133 Enabled = false;
134 }
135
136 // If the object is physically active, add the axis locking constraint
137 if (isActive)
138 {
139 // Check to see if the locking parameters have changed
140 if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags
141 || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags)
142 {
143 // The locking has changed. Remove the old constraint and build a new one
144 RemoveAxisLockConstraint();
145 }
146
147 AddAxisLockConstraint();
148 }
149 else
150 {
151 RemoveAxisLockConstraint();
152 }
153 }
154
155 // Note that this relies on being called at TaintTime
156 private void AddAxisLockConstraint()
157 {
158 if (LockAxisConstraint == null)
159 {
160 // Lock that axis by creating a 6DOF constraint that has one end in the world and
161 // the other in the object.
162 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
163 // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
164
165 // Remove any existing axis constraint (just to be sure)
166 RemoveAxisLockConstraint();
167
168 BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
169 OMV.Vector3.Zero, OMV.Quaternion.Identity,
170 false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
171 LockAxisConstraint = axisConstrainer;
172 m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
173
174 // Remember the clocking being inforced so we can notice if they have changed
175 LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis;
176 LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis;
177
178 // The constraint is tied to the world and oriented to the prim.
179
180 if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh))
181 {
182 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits",
183 m_controllingPrim.LocalID);
184 }
185
186 if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh))
187 {
188 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
189 m_controllingPrim.LocalID);
190 }
191
192 m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
193 m_controllingPrim.LocalID,
194 m_controllingPrim.LockedLinearAxisLow,
195 m_controllingPrim.LockedLinearAxisHigh,
196 m_controllingPrim.LockedAngularAxisLow,
197 m_controllingPrim.LockedAngularAxisHigh);
198
199 // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
200 axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
201
202 axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
203
204 RegisterForBeforeStepCallback();
205 }
206 }
207
208 private void RemoveAxisLockConstraint()
209 {
210 UnRegisterForBeforeStepCallback();
211 if (LockAxisConstraint != null)
212 {
213 m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
214 LockAxisConstraint = null;
215 m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
216 }
217 }
218}
219}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..3db8f2c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
@@ -0,0 +1,220 @@
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.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public class BSActorMoveToTarget : BSActor
40{
41 private BSVMotor m_targetMotor;
42
43 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
44 : base(physicsScene, pObj, actorName)
45 {
46 m_targetMotor = null;
47 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
48 }
49
50 // BSActor.isActive
51 public override bool isActive
52 {
53 // MoveToTarget only works on physical prims
54 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
55 }
56
57 // Release any connections and resources used by the actor.
58 // BSActor.Dispose()
59 public override void Dispose()
60 {
61 Enabled = false;
62 DeactivateMoveToTarget();
63 }
64
65 // Called when physical parameters (properties set in Bullet) need to be re-applied.
66 // Called at taint-time.
67 // BSActor.Refresh()
68 public override void Refresh()
69 {
70 m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
71 m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
72 m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
73
74 // If not active any more...
75 if (!m_controllingPrim.MoveToTargetActive)
76 {
77 Enabled = false;
78 }
79
80 if (isActive)
81 {
82 ActivateMoveToTarget();
83 }
84 else
85 {
86 DeactivateMoveToTarget();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the moveToTarget since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateMoveToTarget()
101 {
102 if (m_targetMotor == null)
103 {
104 // We're taking over after this.
105 m_controllingPrim.ZeroMotion(true);
106
107 /* Someday use the PID controller
108 m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString());
109 m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau;
110 m_targetMotor.Efficiency = 1f;
111 */
112 m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(),
113 m_controllingPrim.MoveToTargetTau, // timeScale
114 BSMotor.Infinite, // decay time scale
115 1f // efficiency
116 );
117 m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
118 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
119 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
120
121 // m_physicsScene.BeforeStep += Mover;
122 m_physicsScene.BeforeStep += Mover2;
123 }
124 else
125 {
126 // If already allocated, make sure the target and other paramters are current
127 m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
128 m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
129 }
130 }
131
132 private void DeactivateMoveToTarget()
133 {
134 if (m_targetMotor != null)
135 {
136 // m_physicsScene.BeforeStep -= Mover;
137 m_physicsScene.BeforeStep -= Mover2;
138 m_targetMotor = null;
139 }
140 }
141
142 // Origional mover that set the objects position to move to the target.
143 // The problem was that gravity would keep trying to push the object down so
144 // the overall downward velocity would increase to infinity.
145 // Called just before the simulation step.
146 private void Mover(float timeStep)
147 {
148 // Don't do hovering while the object is selected.
149 if (!isActive)
150 return;
151
152 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
153
154 // 'movePosition' is where we'd like the prim to be at this moment.
155 OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
156
157 // If we are very close to our target, turn off the movement motor.
158 if (m_targetMotor.ErrorIsZero())
159 {
160 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
161 m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
162 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
163 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
164 // Setting the position does not cause the physics engine to generate a property update. Force it.
165 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
166 }
167 else
168 {
169 m_controllingPrim.ForcePosition = movePosition;
170 // Setting the position does not cause the physics engine to generate a property update. Force it.
171 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
172 }
173 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}",
174 m_controllingPrim.LocalID, origPosition, movePosition);
175 }
176
177 // Version of mover that applies forces to move the physical object to the target.
178 // Also overcomes gravity so the object doesn't just drop to the ground.
179 // Called just before the simulation step.
180 private void Mover2(float timeStep)
181 {
182 // Don't do hovering while the object is selected.
183 if (!isActive)
184 return;
185
186 OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
187 OMV.Vector3 addedForce = OMV.Vector3.Zero;
188
189 // CorrectionVector is the movement vector required this step
190 OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition);
191
192 // If we are very close to our target, turn off the movement motor.
193 if (m_targetMotor.ErrorIsZero())
194 {
195 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}",
196 m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
197 m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
198 m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
199 // Setting the position does not cause the physics engine to generate a property update. Force it.
200 m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
201 }
202 else
203 {
204 // First force to move us there -- the motor return a timestep scaled value.
205 addedForce = correctionVector / timeStep;
206 // Remove the existing velocity (only the moveToTarget force counts)
207 addedForce -= m_controllingPrim.RawVelocity;
208 // Overcome gravity.
209 addedForce -= m_controllingPrim.Gravity;
210
211 // Add enough force to overcome the mass of the object
212 addedForce *= m_controllingPrim.Mass;
213
214 m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */);
215 }
216 m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}",
217 m_controllingPrim.LocalID, origPosition, addedForce);
218 }
219}
220}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
new file mode 100755
index 0000000..ecb4b7f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.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.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
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 DeactivateSetForce();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetForce();
83 }
84 else
85 {
86 DeactivateSetForce();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetForce()
101 {
102 if (m_forceMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetForce()
112 {
113 if (m_forceMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_forceMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
new file mode 100755
index 0000000..a1cf4db
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
@@ -0,0 +1,139 @@
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.PhysicsModules.SharedBase;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
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 DeactivateSetTorque();
62 }
63
64 // Called when physical parameters (properties set in Bullet) need to be re-applied.
65 // Called at taint-time.
66 // BSActor.Refresh()
67 public override void Refresh()
68 {
69 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
70
71 // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
72 if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
73 {
74 m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
75 Enabled = false;
76 return;
77 }
78
79 // If the object is physically active, add the hoverer prestep action
80 if (isActive)
81 {
82 ActivateSetTorque();
83 }
84 else
85 {
86 DeactivateSetTorque();
87 }
88 }
89
90 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
91 // Register a prestep action to restore physical requirements before the next simulation step.
92 // Called at taint-time.
93 // BSActor.RemoveDependencies()
94 public override void RemoveDependencies()
95 {
96 // Nothing to do for the hoverer since it is all software at pre-step action time.
97 }
98
99 // If a hover motor has not been created, create one and start the hovering.
100 private void ActivateSetTorque()
101 {
102 if (m_torqueMotor == null)
103 {
104 // A fake motor that might be used someday
105 m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
106
107 m_physicsScene.BeforeStep += Mover;
108 }
109 }
110
111 private void DeactivateSetTorque()
112 {
113 if (m_torqueMotor != null)
114 {
115 m_physicsScene.BeforeStep -= Mover;
116 m_torqueMotor = null;
117 }
118 }
119
120 // Called just before the simulation step. Update the vertical position for hoverness.
121 private void Mover(float timeStep)
122 {
123 // Don't do force while the object is selected.
124 if (!isActive)
125 return;
126
127 m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
128 if (m_controllingPrim.PhysBody.HasPhysicalBody)
129 {
130 m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
131 m_controllingPrim.ActivateIfPhysical(false);
132 }
133
134 // TODO:
135 }
136}
137}
138
139
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
new file mode 100755
index 0000000..851347b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
@@ -0,0 +1,154 @@
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.PhysicsModule.BulletS
32{
33public class BSActorCollection
34{
35 private Dictionary<string, BSActor> m_actors;
36
37 public BSActorCollection()
38 {
39 m_actors = new Dictionary<string, BSActor>();
40 }
41 public void Add(string name, BSActor actor)
42 {
43 lock (m_actors)
44 {
45 if (!m_actors.ContainsKey(name))
46 {
47 m_actors[name] = actor;
48 }
49 }
50 }
51 public bool RemoveAndRelease(string name)
52 {
53 bool ret = false;
54 lock (m_actors)
55 {
56 if (m_actors.ContainsKey(name))
57 {
58 BSActor beingRemoved = m_actors[name];
59 m_actors.Remove(name);
60 beingRemoved.Dispose();
61 ret = true;
62 }
63 }
64 return ret;
65 }
66 public void Clear()
67 {
68 lock (m_actors)
69 {
70 ForEachActor(a => a.Dispose());
71 m_actors.Clear();
72 }
73 }
74 public void Dispose()
75 {
76 Clear();
77 }
78 public bool HasActor(string name)
79 {
80 return m_actors.ContainsKey(name);
81 }
82 public bool TryGetActor(string actorName, out BSActor theActor)
83 {
84 return m_actors.TryGetValue(actorName, out theActor);
85 }
86 public void ForEachActor(Action<BSActor> act)
87 {
88 lock (m_actors)
89 {
90 foreach (KeyValuePair<string, BSActor> kvp in m_actors)
91 act(kvp.Value);
92 }
93 }
94
95 public void Enable(bool enabl)
96 {
97 ForEachActor(a => a.SetEnabled(enabl));
98 }
99 public void Refresh()
100 {
101 ForEachActor(a => a.Refresh());
102 }
103 public void RemoveDependencies()
104 {
105 ForEachActor(a => a.RemoveDependencies());
106 }
107}
108
109// =============================================================================
110/// <summary>
111/// Each physical object can have 'actors' who are pushing the object around.
112/// This can be used for hover, locking axis, making vehicles, etc.
113/// Each physical object can have multiple actors acting on it.
114///
115/// An actor usually registers itself with physics scene events (pre-step action)
116/// and modifies the parameters on the host physical object.
117/// </summary>
118public abstract class BSActor
119{
120 protected BSScene m_physicsScene { get; private set; }
121 protected BSPhysObject m_controllingPrim { get; private set; }
122 public virtual bool Enabled { get; set; }
123 public string ActorName { get; private set; }
124
125 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
126 {
127 m_physicsScene = physicsScene;
128 m_controllingPrim = pObj;
129 ActorName = actorName;
130 Enabled = true;
131 }
132
133 // Return 'true' if activily updating the prim
134 public virtual bool isActive
135 {
136 get { return Enabled; }
137 }
138
139 // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
140 // Anyone else should assign true/false to 'Enabled'.
141 public void SetEnabled(bool setEnabled)
142 {
143 Enabled = setEnabled;
144 }
145 // Release any connections and resources used by the actor.
146 public abstract void Dispose();
147 // Called when physical parameters (properties set in Bullet) need to be re-applied.
148 public abstract void Refresh();
149 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
150 // Register a prestep action to restore physical requirements before the next simulation step.
151 public abstract void RemoveDependencies();
152
153}
154}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
index 8ad78ca..7756b10 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/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
@@ -31,7 +31,7 @@ using System.Security;
31using System.Text; 31using System.Text;
32using OpenMetaverse; 32using OpenMetaverse;
33 33
34namespace OpenSim.Region.Physics.BulletSPlugin { 34namespace OpenSim.Region.PhysicsModule.BulletS {
35 35
36 // Constraint type values as defined by Bullet 36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int 37public enum ConstraintType : int
@@ -43,7 +43,11 @@ public enum ConstraintType : int
43 SLIDER_CONSTRAINT_TYPE, 43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE, 44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE, 45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_CONSTRAINT_TYPE 46 GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82
47 FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82
48 MAX_CONSTRAINT_TYPE, // last type defined by Bullet
49 //
50 BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
47} 51}
48 52
49// =============================================================================== 53// ===============================================================================
@@ -70,6 +74,8 @@ public enum BSPhysicsShapeType
70 SHAPE_COMPOUND = 22, 74 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23, 75 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24, 76 SHAPE_AVATAR = 24,
77 SHAPE_CONVEXHULL= 25,
78 SHAPE_GIMPACT = 26,
73}; 79};
74 80
75// The native shapes have predefined shape hash keys 81// The native shapes have predefined shape hash keys
@@ -87,7 +93,7 @@ public enum FixedShapeKey : ulong
87[StructLayout(LayoutKind.Sequential)] 93[StructLayout(LayoutKind.Sequential)]
88public struct ShapeData 94public struct ShapeData
89{ 95{
90 public uint ID; 96 public UInt32 ID;
91 public BSPhysicsShapeType Type; 97 public BSPhysicsShapeType Type;
92 public Vector3 Position; 98 public Vector3 Position;
93 public Quaternion Rotation; 99 public Quaternion Rotation;
@@ -111,7 +117,7 @@ public struct ShapeData
111[StructLayout(LayoutKind.Sequential)] 117[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit 118public struct SweepHit
113{ 119{
114 public uint ID; 120 public UInt32 ID;
115 public float Fraction; 121 public float Fraction;
116 public Vector3 Normal; 122 public Vector3 Normal;
117 public Vector3 Point; 123 public Vector3 Point;
@@ -119,27 +125,47 @@ public struct SweepHit
119[StructLayout(LayoutKind.Sequential)] 125[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit 126public struct RaycastHit
121{ 127{
122 public uint ID; 128 public UInt32 ID;
123 public float Fraction; 129 public float Fraction;
124 public Vector3 Normal; 130 public Vector3 Normal;
125} 131}
126[StructLayout(LayoutKind.Sequential)] 132[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc 133public struct CollisionDesc
128{ 134{
129 public uint aID; 135 public UInt32 aID;
130 public uint bID; 136 public UInt32 bID;
131 public Vector3 point; 137 public Vector3 point;
132 public Vector3 normal; 138 public Vector3 normal;
139 public float penetration;
133} 140}
134[StructLayout(LayoutKind.Sequential)] 141[StructLayout(LayoutKind.Sequential)]
135public struct EntityProperties 142public struct EntityProperties
136{ 143{
137 public uint ID; 144 public UInt32 ID;
138 public Vector3 Position; 145 public Vector3 Position;
139 public Quaternion Rotation; 146 public Quaternion Rotation;
140 public Vector3 Velocity; 147 public Vector3 Velocity;
141 public Vector3 Acceleration; 148 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity; 149 public Vector3 RotationalVelocity;
150
151 public override string ToString()
152 {
153 StringBuilder buff = new StringBuilder();
154 buff.Append("<i=");
155 buff.Append(ID.ToString());
156 buff.Append(",p=");
157 buff.Append(Position.ToString());
158 buff.Append(",r=");
159 buff.Append(Rotation.ToString());
160 buff.Append(",v=");
161 buff.Append(Velocity.ToString());
162 buff.Append(",a=");
163 buff.Append(Acceleration.ToString());
164 buff.Append(",rv=");
165 buff.Append(RotationalVelocity.ToString());
166 buff.Append(">");
167 return buff.ToString();
168 }
143} 169}
144 170
145// Format of this structure must match the definition in the C++ code 171// Format of this structure must match the definition in the C++ code
@@ -154,32 +180,6 @@ public struct ConfigurationParameters
154 public float collisionMargin; 180 public float collisionMargin;
155 public float gravity; 181 public float gravity;
156 182
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; 183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize; 184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation; 185 public float shouldDisableContactPoolDynamicAllocation;
@@ -188,22 +188,45 @@ public struct ConfigurationParameters
188 public float shouldSplitSimulationIslands; 188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching; 189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations; 190 public float numberOfSolverIterations;
191 public float useSingleSidedMeshes;
192 public float globalContactBreakingThreshold;
191 193
192 public float XlinksetImplementation; 194 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 195
203 public const float numericTrue = 1f; 196 public const float numericTrue = 1f;
204 public const float numericFalse = 0f; 197 public const float numericFalse = 0f;
205} 198}
206 199
200// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
201[StructLayout(LayoutKind.Sequential)]
202public struct HACDParams
203{
204 // usual default values
205 public float maxVerticesPerHull; // 100
206 public float minClusters; // 2
207 public float compacityWeight; // 0.1
208 public float volumeWeight; // 0.0
209 public float concavity; // 100
210 public float addExtraDistPoints; // false
211 public float addNeighboursDistPoints; // false
212 public float addFacesPoints; // false
213 public float shouldAdjustCollisionMargin; // false
214 // VHACD
215 public float whichHACD; // zero if Bullet HACD, non-zero says VHACD
216 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
217 public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage
218 public float vHACDdepth; // 20 max number of clipping stages
219 public float vHACDconcavity; // 0.0025 maximum concavity
220 public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane
221 public float vHACDconvexHullDownsampling; // 4 precision of hull gen process
222 public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes
223 public float vHACDbeta; // 0.05 bias toward clipping along revolution axis
224 public float vHACDgamma; // 0.00125 max concavity when merging
225 public float vHACDpca; // 0 on/off normalizing mesh before decomp
226 public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based
227 public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull
228 public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls
229}
207 230
208// The states a bullet collision object can have 231// The states a bullet collision object can have
209public enum ActivationState : uint 232public enum ActivationState : uint
@@ -238,11 +261,12 @@ public enum CollisionFlags : uint
238 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, 261 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
239 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 262 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
240 // Following used by BulletSim to control collisions and updates 263 // Following used by BulletSim to control collisions and updates
241 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 264 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
242 BS_FLOATS_ON_WATER = 1 << 11, 265 BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
243 BS_VEHICLE_COLLISIONS = 1 << 12, 266 BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
267 BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
244 BS_NONE = 0, 268 BS_NONE = 0,
245 BS_ALL = 0xFFFFFFFF 269 BS_ALL = 0x7FFF // collision flags are a signed short
246}; 270};
247 271
248// Values f collisions groups and masks 272// Values f collisions groups and masks
@@ -258,14 +282,14 @@ public enum CollisionFilterGroups : uint
258 BDebrisGroup = 1 << 3, // 0008 282 BDebrisGroup = 1 << 3, // 0008
259 BSensorTrigger = 1 << 4, // 0010 283 BSensorTrigger = 1 << 4, // 0010
260 BCharacterGroup = 1 << 5, // 0020 284 BCharacterGroup = 1 << 5, // 0020
261 BAllGroup = 0x000FFFFF, 285 BAllGroup = 0x0007FFF, // collision flags are a signed short
262 // Filter groups defined by BulletSim 286 // Filter groups defined by BulletSim
263 BGroundPlaneGroup = 1 << 10, // 0400 287 BGroundPlaneGroup = 1 << 8, // 0400
264 BTerrainGroup = 1 << 11, // 0800 288 BTerrainGroup = 1 << 9, // 0800
265 BRaycastGroup = 1 << 12, // 1000 289 BRaycastGroup = 1 << 10, // 1000
266 BSolidGroup = 1 << 13, // 2000 290 BSolidGroup = 1 << 11, // 2000
267 // BLinksetGroup = xx // a linkset proper is either static or dynamic 291 // BLinksetGroup = xx // a linkset proper is either static or dynamic
268 BLinksetChildGroup = 1 << 14, // 4000 292 BLinksetChildGroup = 1 << 12, // 4000
269}; 293};
270 294
271// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 295// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -285,7 +309,7 @@ public enum ConstraintParamAxis : int
285 AXIS_ANGULAR_X, 309 AXIS_ANGULAR_X,
286 AXIS_ANGULAR_Y, 310 AXIS_ANGULAR_Y,
287 AXIS_ANGULAR_Z, 311 AXIS_ANGULAR_Z,
288 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls 312 AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
289 AXIS_ANGULAR_ALL, 313 AXIS_ANGULAR_ALL,
290 AXIS_ALL 314 AXIS_ALL
291}; 315};
@@ -294,7 +318,7 @@ public abstract class BSAPITemplate
294{ 318{
295// Returns the name of the underlying Bullet engine 319// Returns the name of the underlying Bullet engine
296public abstract string BulletEngineName { get; } 320public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;} 321public abstract string BulletEngineVersion { get; protected set;}
298 322
299// Initialization and simulation 323// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, 324public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
@@ -305,7 +329,7 @@ public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParamet
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, 329public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
306 out int updatedEntityCount, out int collidersCount); 330 out int updatedEntityCount, out int collidersCount);
307 331
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value); 332public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
309 333
310public abstract void Shutdown(BulletWorld sim); 334public abstract void Shutdown(BulletWorld sim);
311 335
@@ -317,10 +341,20 @@ public abstract BulletShape CreateMeshShape(BulletWorld world,
317 int indicesCount, int[] indices, 341 int indicesCount, int[] indices,
318 int verticesCount, float[] vertices ); 342 int verticesCount, float[] vertices );
319 343
344public abstract BulletShape CreateGImpactShape(BulletWorld world,
345 int indicesCount, int[] indices,
346 int verticesCount, float[] vertices );
347
320public abstract BulletShape CreateHullShape(BulletWorld world, 348public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls); 349 int hullCount, float[] hulls);
322 350
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape); 351public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
352
353public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
354
355public abstract BulletShape CreateConvexHullShape(BulletWorld world,
356 int indicesCount, int[] indices,
357 int verticesCount, float[] vertices );
324 358
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); 359public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326 360
@@ -342,26 +376,28 @@ public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape c
342 376
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); 377public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344 378
379public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
380
345public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); 381public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
346 382
347public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id); 383public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
348 384
349public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); 385public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
350 386
351public abstract CollisionObjectTypes GetBodyType(BulletBody obj); 387public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
352 388
353public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 389public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
354 390
355public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot); 391public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
356 392
357public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot); 393public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
358 394
359public abstract void DestroyObject(BulletWorld sim, BulletBody obj); 395public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
360 396
361// ===================================================================================== 397// =====================================================================================
362public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin); 398public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
363 399
364public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, 400public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
365 float scaleFactor, float collisionMargin); 401 float scaleFactor, float collisionMargin);
366 402
367// ===================================================================================== 403// =====================================================================================
@@ -375,11 +411,38 @@ public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world,
375 Vector3 joinPoint, 411 Vector3 joinPoint,
376 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 412 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
377 413
414public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
415 Vector3 frameInBloc, Quaternion frameInBrot,
416 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
417
418public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
419 Vector3 frame1loc, Quaternion frame1rot,
420 Vector3 frame2loc, Quaternion frame2rot,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
422
378public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, 423public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
379 Vector3 pivotinA, Vector3 pivotinB, 424 Vector3 pivotinA, Vector3 pivotinB,
380 Vector3 axisInA, Vector3 axisInB, 425 Vector3 axisInA, Vector3 axisInB,
381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); 426 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
382 427
428public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
429 Vector3 frameInAloc, Quaternion frameInArot,
430 Vector3 frameInBloc, Quaternion frameInBrot,
431 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
432
433public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
434 Vector3 frameInAloc, Quaternion frameInArot,
435 Vector3 frameInBloc, Quaternion frameInBrot,
436 bool disableCollisionsBetweenLinkedBodies);
437
438public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
439 Vector3 axisInA, Vector3 axisInB,
440 float ratio, bool disableCollisionsBetweenLinkedBodies);
441
442public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
443 Vector3 pivotInA, Vector3 pivotInB,
444 bool disableCollisionsBetweenLinkedBodies);
445
383public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); 446public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
384 447
385public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); 448public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
@@ -397,6 +460,38 @@ public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float e
397 460
398public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); 461public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
399 462
463public const int HINGE_NOT_SPECIFIED = -1;
464public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
465
466public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
467
468public const int SPRING_NOT_SPECIFIED = -1;
469public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
470
471public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
472
473public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
474
475public const int SLIDER_LOWER_LIMIT = 0;
476public const int SLIDER_UPPER_LIMIT = 1;
477public const int SLIDER_LINEAR = 2;
478public const int SLIDER_ANGULAR = 3;
479public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
480
481public const int SLIDER_SET_SOFTNESS = 4;
482public const int SLIDER_SET_RESTITUTION = 5;
483public const int SLIDER_SET_DAMPING = 6;
484public const int SLIDER_SET_DIRECTION = 7;
485public const int SLIDER_SET_LIMIT = 8;
486public const int SLIDER_SET_ORTHO = 9;
487public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
488
489public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
490
491public const int SLIDER_MOTOR_VELOCITY = 10;
492public const int SLIDER_MAX_MOTOR_FORCE = 11;
493public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
494
400public abstract bool CalculateTransforms(BulletConstraint constrain); 495public abstract bool CalculateTransforms(BulletConstraint constrain);
401 496
402public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); 497public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
@@ -420,6 +515,8 @@ public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
420 515
421public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); 516public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
422 517
518public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
519
423public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); 520public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
424 521
425public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); 522public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
@@ -607,7 +704,7 @@ public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
607 704
608public abstract int GetNumConstraintRefs(BulletBody obj); 705public abstract int GetNumConstraintRefs(BulletBody obj);
609 706
610public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask); 707public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
611 708
612// ===================================================================================== 709// =====================================================================================
613// btCollisionShape entries 710// btCollisionShape entries
@@ -646,17 +743,21 @@ public abstract float GetMargin(BulletShape shape);
646 743
647// ===================================================================================== 744// =====================================================================================
648// Debugging 745// Debugging
649public abstract void DumpRigidBody(BulletWorld sim, BulletBody collisionObject); 746public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
747
748public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
749
750public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
650 751
651public abstract void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape); 752public virtual void DumpActivationInfo(BulletWorld sim) { }
652 753
653public abstract void DumpConstraint(BulletWorld sim, BulletConstraint constrain); 754public virtual void DumpAllInfo(BulletWorld sim) { }
654 755
655public abstract void DumpActivationInfo(BulletWorld sim); 756public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
656 757
657public abstract void DumpAllInfo(BulletWorld sim); 758public virtual void ResetBroadphasePool(BulletWorld sim) { }
658 759
659public abstract void DumpPhysicsStatistics(BulletWorld sim); 760public virtual void ResetConstraintSolver(BulletWorld sim) { }
660 761
661}; 762};
662} 763}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
index 103d8fc..83fc3a6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -30,9 +30,9 @@ using System.Reflection;
30using log4net; 30using log4net;
31using OMV = OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.PhysicsModules.SharedBase;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.PhysicsModule.BulletS
36{ 36{
37public sealed class BSCharacter : BSPhysObject 37public sealed class BSCharacter : BSPhysObject
38{ 38{
@@ -43,53 +43,52 @@ public sealed class BSCharacter : BSPhysObject
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private bool _grabbed; 44 private bool _grabbed;
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass; 46 private float _mass;
48 private float _avatarDensity;
49 private float _avatarVolume; 47 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore; 48 private float _collisionScore;
54 private OMV.Vector3 _acceleration; 49 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType; 50 private int _physicsActorType;
57 private bool _isPhysical; 51 private bool _isPhysical;
58 private bool _flying; 52 private bool _flying;
59 private bool _setAlwaysRun; 53 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 54 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 55 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 56 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 57 private bool _kinematic;
66 private float _buoyancy; 58 private float _buoyancy;
67 59
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 60 private BSActorAvatarMove m_moveActor;
69 private float _currentFriction; // the friction currently being used (changed by setVelocity). 61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
70
71 private BSVMotor _velocityMotor;
72 62
73 private OMV.Vector3 _PIDTarget; 63 private OMV.Vector3 _PIDTarget;
74 private bool _usePID;
75 private float _PIDTau; 64 private float _PIDTau;
76 private bool _useHoverPID;
77 private float _PIDHoverHeight;
78 private PIDHoverType _PIDHoverType;
79 private float _PIDHoverTao;
80 65
81 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 66// public override OMV.Vector3 RawVelocity
67// { get { return base.RawVelocity; }
68// set {
69// if (value != base.RawVelocity)
70// Util.PrintCallStack();
71// Console.WriteLine("Set rawvel to {0}", value);
72// base.RawVelocity = value; }
73// }
74
75 // Avatars are always complete (in the physics engine sense)
76 public override bool IsIncomplete { get { return false; } }
77
78 public BSCharacter(
79 uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying)
80
82 : base(parent_scene, localID, avName, "BSCharacter") 81 : base(parent_scene, localID, avName, "BSCharacter")
83 { 82 {
84 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
85 _position = pos; 84 RawPosition = pos;
86 85
87 _flying = isFlying; 86 _flying = isFlying;
88 _orientation = OMV.Quaternion.Identity; 87 RawOrientation = OMV.Quaternion.Identity;
89 _velocity = OMV.Vector3.Zero; 88 RawVelocity = vel;
90 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 89 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = BSParam.AvatarStandingFriction; 90 Friction = BSParam.AvatarStandingFriction;
92 _avatarDensity = BSParam.AvatarDensity; 91 Density = BSParam.AvatarDensity;
93 92
94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 93 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values. 94 // replace with the default values.
@@ -103,19 +102,28 @@ public sealed class BSCharacter : BSPhysObject
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 102 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 103 ComputeAvatarVolumeAndMass();
105 104
106 SetupMovementMotor(); 105 DetailLog(
107 106 "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 107 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
110 108
111 // do actual creation in taint time 109 // do actual creation in taint time
112 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 110 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
113 { 111 {
114 DetailLog("{0},BSCharacter.create,taint", LocalID); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113
115 // New body and shape into PhysBody and PhysShape 114 // New body and shape into PhysBody and PhysShape
116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 115 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
116
117 // The avatar's movement is controlled by this motor that speeds up and slows down
118 // the avatar seeking to reach the motor's target speed.
119 // This motor runs as a prestep action for the avatar so it will keep the avatar
120 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
121 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
122 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
117 123
118 SetPhysicalProperties(); 124 SetPhysicalProperties();
125
126 IsInitialized = true;
119 }); 127 });
120 return; 128 return;
121 } 129 }
@@ -123,122 +131,77 @@ public sealed class BSCharacter : BSPhysObject
123 // called when this character is being destroyed and the resources should be released 131 // called when this character is being destroyed and the resources should be released
124 public override void Destroy() 132 public override void Destroy()
125 { 133 {
134 IsInitialized = false;
135
126 base.Destroy(); 136 base.Destroy();
127 137
128 DetailLog("{0},BSCharacter.Destroy", LocalID); 138 DetailLog("{0},BSCharacter.Destroy", LocalID);
129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 139 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
130 { 140 {
131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 141 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
132 PhysBody.Clear(); 142 PhysBody.Clear();
133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 143 PhysShape.Dereference(PhysScene);
134 PhysShape.Clear(); 144 PhysShape = new BSShapeNull();
135 }); 145 });
136 } 146 }
137 147
138 private void SetPhysicalProperties() 148 private void SetPhysicalProperties()
139 { 149 {
140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 150 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
151
152 ForcePosition = RawPosition;
141 153
142 ZeroMotion(true); 154 // Set the velocity
143 ForcePosition = _position; 155 if (m_moveActor != null)
156 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
144 157
145 // Set the velocity and compute the proper friction 158 ForceVelocity = RawVelocity;
146 _velocityMotor.Reset(); 159 TargetVelocity = RawVelocity;
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
149 ForceVelocity = _velocity;
150 160
151 // This will enable or disable the flying buoyancy of the avatar. 161 // 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. 162 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
153 Flying = _flying; 163 Flying = _flying;
154 164
155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 165 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 166 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 167 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 168 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
159 if (BSParam.CcdMotionThreshold > 0f) 169 if (BSParam.CcdMotionThreshold > 0f)
160 { 170 {
161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 171 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 172 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
163 } 173 }
164 174
165 UpdatePhysicalMassProperties(RawMass, false); 175 UpdatePhysicalMassProperties(RawMass, false);
166 176
167 // Make so capsule does not fall over 177 // Make so capsule does not fall over
168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 178 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
169 179
170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 180 // The avatar mover sets some parameters.
181 PhysicalActors.Refresh();
171 182
172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 183 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
184
185 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
173 186
174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 187 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 188 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 189 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
177 190
178 // Do this after the object has been added to the world 191 // Do this after the object has been added to the world
179 PhysBody.collisionType = CollisionType.Avatar; 192 if (BSParam.AvatarToAvatarCollisionsByDefault)
180 PhysBody.ApplyCollisionMask(PhysicsScene); 193 PhysBody.collisionType = CollisionType.Avatar;
181 } 194 else
182 195 PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
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 196
219 /* 197 PhysBody.ApplyCollisionMask(PhysScene);
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 } 198 }
237 199
238 public override void RequestPhysicsterseUpdate() 200 public override void RequestPhysicsterseUpdate()
239 { 201 {
240 base.RequestPhysicsterseUpdate(); 202 base.RequestPhysicsterseUpdate();
241 } 203 }
204
242 // No one calls this method so I don't know what it could possibly mean 205 // No one calls this method so I don't know what it could possibly mean
243 public override bool Stopped { get { return false; } } 206 public override bool Stopped { get { return false; } }
244 207
@@ -250,6 +213,10 @@ public sealed class BSCharacter : BSPhysObject
250 } 213 }
251 214
252 set { 215 set {
216 // This is how much the avatar size is changing. Positive means getting bigger.
217 // The avatar altitude must be adjusted for this change.
218 float heightChange = value.Z - _size.Z;
219
253 _size = value; 220 _size = value;
254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 221 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values. 222 // replace with the default values.
@@ -259,16 +226,20 @@ public sealed class BSCharacter : BSPhysObject
259 Scale = ComputeAvatarScale(_size); 226 Scale = ComputeAvatarScale(_size);
260 ComputeAvatarVolumeAndMass(); 227 ComputeAvatarVolumeAndMass();
261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 228 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 229 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
263 230
264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 231 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
265 { 232 {
266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 233 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
267 { 234 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 235 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
269 UpdatePhysicalMassProperties(RawMass, true); 236 UpdatePhysicalMassProperties(RawMass, true);
237
238 // Adjust the avatar's position to account for the increase/decrease in size
239 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
240
270 // Make sure this change appears as a property update event 241 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody); 242 PhysScene.PE.PushUpdate(PhysBody);
272 } 243 }
273 }); 244 });
274 245
@@ -279,11 +250,6 @@ public sealed class BSCharacter : BSPhysObject
279 { 250 {
280 set { BaseShape = value; } 251 set { BaseShape = value; }
281 } 252 }
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 253
288 public override bool Grabbed { 254 public override bool Grabbed {
289 set { _grabbed = value; } 255 set { _grabbed = value; }
@@ -291,6 +257,10 @@ public sealed class BSCharacter : BSPhysObject
291 public override bool Selected { 257 public override bool Selected {
292 set { _selected = value; } 258 set { _selected = value; }
293 } 259 }
260 public override bool IsSelected
261 {
262 get { return _selected; }
263 }
294 public override void CrossingFailure() { return; } 264 public override void CrossingFailure() { return; }
295 public override void link(PhysicsActor obj) { return; } 265 public override void link(PhysicsActor obj) { return; }
296 public override void delink() { return; } 266 public override void delink() { return; }
@@ -301,29 +271,30 @@ public sealed class BSCharacter : BSPhysObject
301 // Called at taint time! 271 // Called at taint time!
302 public override void ZeroMotion(bool inTaintTime) 272 public override void ZeroMotion(bool inTaintTime)
303 { 273 {
304 _velocity = OMV.Vector3.Zero; 274 RawVelocity = OMV.Vector3.Zero;
305 _acceleration = OMV.Vector3.Zero; 275 _acceleration = OMV.Vector3.Zero;
306 _rotationalVelocity = OMV.Vector3.Zero; 276 _rotationalVelocity = OMV.Vector3.Zero;
307 277
308 // Zero some other properties directly into the physics engine 278 // Zero some other properties directly into the physics engine
309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 279 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
310 { 280 {
311 if (PhysBody.HasPhysicalBody) 281 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody); 282 PhysScene.PE.ClearAllForces(PhysBody);
313 }); 283 });
314 } 284 }
285
315 public override void ZeroAngularMotion(bool inTaintTime) 286 public override void ZeroAngularMotion(bool inTaintTime)
316 { 287 {
317 _rotationalVelocity = OMV.Vector3.Zero; 288 _rotationalVelocity = OMV.Vector3.Zero;
318 289
319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
320 { 291 {
321 if (PhysBody.HasPhysicalBody) 292 if (PhysBody.HasPhysicalBody)
322 { 293 {
323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 294 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 295 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched. 296 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody); 297 PhysScene.PE.ClearForces(PhysBody);
327 } 298 }
328 }); 299 });
329 } 300 }
@@ -331,38 +302,34 @@ public sealed class BSCharacter : BSPhysObject
331 302
332 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 303 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
333 304
334 public override OMV.Vector3 RawPosition
335 {
336 get { return _position; }
337 set { _position = value; }
338 }
339 public override OMV.Vector3 Position { 305 public override OMV.Vector3 Position {
340 get { 306 get {
341 // Don't refetch the position because this function is called a zillion times 307 // Don't refetch the position because this function is called a zillion times
342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); 308 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
343 return _position; 309 return RawPosition;
344 } 310 }
345 set { 311 set {
346 _position = value; 312 RawPosition = value;
347 PositionSanityCheck();
348 313
349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 314 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
350 { 315 {
351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 316 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
352 if (PhysBody.HasPhysicalBody) 317 PositionSanityCheck();
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 318 ForcePosition = RawPosition;
354 }); 319 });
355 } 320 }
356 } 321 }
357 public override OMV.Vector3 ForcePosition { 322 public override OMV.Vector3 ForcePosition {
358 get { 323 get {
359 _position = PhysicsScene.PE.GetPosition(PhysBody); 324 RawPosition = PhysScene.PE.GetPosition(PhysBody);
360 return _position; 325 return RawPosition;
361 } 326 }
362 set { 327 set {
363 _position = value; 328 RawPosition = value;
364 PositionSanityCheck(); 329 if (PhysBody.HasPhysicalBody)
365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 330 {
331 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
332 }
366 } 333 }
367 } 334 }
368 335
@@ -375,28 +342,30 @@ public sealed class BSCharacter : BSPhysObject
375 bool ret = false; 342 bool ret = false;
376 343
377 // TODO: check for out of bounds 344 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) 345 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
379 { 346 {
380 // The character is out of the known/simulated area. 347 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for 348 // Force the avatar position to be within known. ScenePresence will use the position
382 // the time, we just ignore the position. 349 // plus the velocity to decide if the avatar is moving out of the region.
383 return ret; 350 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
351 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
352 return true;
384 } 353 }
385 354
386 // If below the ground, move the avatar up 355 // If below the ground, move the avatar up
387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 356 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
388 if (Position.Z < terrainHeight) 357 if (Position.Z < terrainHeight)
389 { 358 {
390 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 359 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
391 _position.Z = terrainHeight + 2.0f; 360 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
392 ret = true; 361 ret = true;
393 } 362 }
394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 363 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
395 { 364 {
396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 365 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
397 if (Position.Z < waterHeight) 366 if (Position.Z < waterHeight)
398 { 367 {
399 _position.Z = waterHeight; 368 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
400 ret = true; 369 ret = true;
401 } 370 }
402 } 371 }
@@ -414,11 +383,10 @@ public sealed class BSCharacter : BSPhysObject
414 { 383 {
415 // The new position value must be pushed into the physics engine but we can't 384 // 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. 385 // just assign to "Position" because of potential call loops.
417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 386 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
418 { 387 {
419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 388 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
420 if (PhysBody.HasPhysicalBody) 389 ForcePosition = RawPosition;
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
422 }); 390 });
423 ret = true; 391 ret = true;
424 } 392 }
@@ -428,25 +396,25 @@ public sealed class BSCharacter : BSPhysObject
428 public override float Mass { get { return _mass; } } 396 public override float Mass { get { return _mass; } }
429 397
430 // used when we only want this prim's mass and not the linkset thing 398 // used when we only want this prim's mass and not the linkset thing
431 public override float RawMass { 399 public override float RawMass {
432 get {return _mass; } 400 get {return _mass; }
433 } 401 }
434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
435 { 403 {
436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 404 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 405 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
438 } 406 }
439 407
440 public override OMV.Vector3 Force { 408 public override OMV.Vector3 Force {
441 get { return _force; } 409 get { return RawForce; }
442 set { 410 set {
443 _force = value; 411 RawForce = value;
444 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 412 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 413 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
446 { 414 {
447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 415 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
448 if (PhysBody.HasPhysicalBody) 416 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 417 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
450 }); 418 });
451 } 419 }
452 } 420 }
@@ -460,6 +428,7 @@ public sealed class BSCharacter : BSPhysObject
460 428
461 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 429 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
462 public override void SetVolumeDetect(int param) { return; } 430 public override void SetVolumeDetect(int param) { return; }
431 public override bool IsVolumeDetect { get { return false; } }
463 432
464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 433 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 434 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
@@ -469,79 +438,59 @@ public sealed class BSCharacter : BSPhysObject
469 { 438 {
470 get 439 get
471 { 440 {
472 return _velocityMotor.TargetValue; 441 return base.m_targetVelocity;
473 } 442 }
474 set 443 set
475 { 444 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 445 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
446 m_targetVelocity = value;
477 OMV.Vector3 targetVel = value; 447 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun) 448 if (_setAlwaysRun && !_flying)
479 targetVel *= BSParam.AvatarAlwaysRunFactor; 449 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
480 450
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 451 if (m_moveActor != null)
482 { 452 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 } 453 }
489 } 454 }
490 // Directly setting velocity means this is what the user really wants now. 455 // Directly setting velocity means this is what the user really wants now.
491 public override OMV.Vector3 Velocity { 456 public override OMV.Vector3 Velocity {
492 get { return _velocity; } 457 get { return RawVelocity; }
493 set { 458 set {
494 _velocity = value; 459 RawVelocity = value;
495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 460 OMV.Vector3 vel = RawVelocity;
496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 461
462 DetailLog("{0}: set Velocity = {1}", LocalID, value);
463
464 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
497 { 465 {
498 _velocityMotor.Reset(); 466 if (m_moveActor != null)
499 _velocityMotor.SetCurrent(_velocity); 467 m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
500 _velocityMotor.SetTarget(_velocity); 468
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. 469 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
502 _velocityMotor.Enabled = false; 470 ForceVelocity = vel;
503
504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
505 ForceVelocity = _velocity;
506 }); 471 });
507 } 472 }
508 } 473 }
474
509 public override OMV.Vector3 ForceVelocity { 475 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 476 get { return RawVelocity; }
511 set { 477 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 478 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
479// Util.PrintCallStack();
480 DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
513 481
514 _velocity = value; 482 RawVelocity = value;
515 // Depending on whether the avatar is moving or not, change the friction 483 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
516 // to keep the avatar from slipping around 484 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 } 485 }
539 } 486 }
487
540 public override OMV.Vector3 Torque { 488 public override OMV.Vector3 Torque {
541 get { return _torque; } 489 get { return RawTorque; }
542 set { _torque = value; 490 set { RawTorque = value;
543 } 491 }
544 } 492 }
493
545 public override float CollisionScore { 494 public override float CollisionScore {
546 get { return _collisionScore; } 495 get { return _collisionScore; }
547 set { _collisionScore = value; 496 set { _collisionScore = value;
@@ -551,22 +500,27 @@ public sealed class BSCharacter : BSPhysObject
551 get { return _acceleration; } 500 get { return _acceleration; }
552 set { _acceleration = value; } 501 set { _acceleration = value; }
553 } 502 }
554 public override OMV.Quaternion RawOrientation
555 {
556 get { return _orientation; }
557 set { _orientation = value; }
558 }
559 public override OMV.Quaternion Orientation { 503 public override OMV.Quaternion Orientation {
560 get { return _orientation; } 504 get { return RawOrientation; }
561 set { 505 set {
562 // Orientation is set zillions of times when an avatar is walking. It's like 506 // Orientation is set zillions of times when an avatar is walking. It's like
563 // the viewer doesn't trust us. 507 // the viewer doesn't trust us.
564 if (_orientation != value) 508 if (RawOrientation != value)
565 { 509 {
566 _orientation = value; 510 RawOrientation = value;
567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 511 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
568 { 512 {
569 ForceOrientation = _orientation; 513 // Bullet assumes we know what we are doing when forcing orientation
514 // so it lets us go against all the rules and just compensates for them later.
515 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
516 // This keeps us from flipping the capsule over which the veiwer does not understand.
517 float oRoll, oPitch, oYaw;
518 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
519 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
520 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
521 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
522 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
523 ForceOrientation = trimmedOrientation;
570 }); 524 });
571 } 525 }
572 } 526 }
@@ -576,16 +530,16 @@ public sealed class BSCharacter : BSPhysObject
576 { 530 {
577 get 531 get
578 { 532 {
579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 533 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
580 return _orientation; 534 return RawOrientation;
581 } 535 }
582 set 536 set
583 { 537 {
584 _orientation = value; 538 RawOrientation = value;
585 if (PhysBody.HasPhysicalBody) 539 if (PhysBody.HasPhysicalBody)
586 { 540 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody); 541 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 542 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
589 } 543 }
590 } 544 }
591 } 545 }
@@ -605,6 +559,9 @@ public sealed class BSCharacter : BSPhysObject
605 public override bool IsStatic { 559 public override bool IsStatic {
606 get { return false; } 560 get { return false; }
607 } 561 }
562 public override bool IsPhysicallyActive {
563 get { return true; }
564 }
608 public override bool Flying { 565 public override bool Flying {
609 get { return _flying; } 566 get { return _flying; }
610 set { 567 set {
@@ -631,14 +588,14 @@ public sealed class BSCharacter : BSPhysObject
631 public override bool FloatOnWater { 588 public override bool FloatOnWater {
632 set { 589 set {
633 _floatOnWater = value; 590 _floatOnWater = value;
634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 591 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
635 { 592 {
636 if (PhysBody.HasPhysicalBody) 593 if (PhysBody.HasPhysicalBody)
637 { 594 {
638 if (_floatOnWater) 595 if (_floatOnWater)
639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 596 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else 597 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 598 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 } 599 }
643 }); 600 });
644 } 601 }
@@ -659,7 +616,7 @@ public sealed class BSCharacter : BSPhysObject
659 public override float Buoyancy { 616 public override float Buoyancy {
660 get { return _buoyancy; } 617 get { return _buoyancy; }
661 set { _buoyancy = value; 618 set { _buoyancy = value;
662 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 619 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
663 { 620 {
664 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 621 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
665 ForceBuoyancy = _buoyancy; 622 ForceBuoyancy = _buoyancy;
@@ -668,15 +625,16 @@ public sealed class BSCharacter : BSPhysObject
668 } 625 }
669 public override float ForceBuoyancy { 626 public override float ForceBuoyancy {
670 get { return _buoyancy; } 627 get { return _buoyancy; }
671 set { 628 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 629 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673 630
674 _buoyancy = value; 631 _buoyancy = value;
675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 632 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
676 // Buoyancy is faked by changing the gravity applied to the object 633 // Buoyancy is faked by changing the gravity applied to the object
677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 634 float grav = BSParam.Gravity * (1f - _buoyancy);
635 Gravity = new OMV.Vector3(0f, 0f, grav);
678 if (PhysBody.HasPhysicalBody) 636 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); 637 PhysScene.PE.SetGravity(PhysBody, Gravity);
680 } 638 }
681 } 639 }
682 640
@@ -684,60 +642,32 @@ public sealed class BSCharacter : BSPhysObject
684 public override OMV.Vector3 PIDTarget { 642 public override OMV.Vector3 PIDTarget {
685 set { _PIDTarget = value; } 643 set { _PIDTarget = value; }
686 } 644 }
687 public override bool PIDActive { 645
688 set { _usePID = value; } 646 public override bool PIDActive { get; set; }
689 } 647
690 public override float PIDTau { 648 public override float PIDTau {
691 set { _PIDTau = value; } 649 set { _PIDTau = value; }
692 } 650 }
693 651
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) 652 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 { 653 {
717 // Since this force is being applied in only one step, make this a force per second. 654 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 655 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
719 AddForce(addForce, pushforce, false); 656 AddForce(addForce, pushforce, false);
720 } 657 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 658 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
722 if (force.IsFinite()) 659 if (force.IsFinite())
723 { 660 {
724 float magnitude = force.Length(); 661 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); 662 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733 663
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 664 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
735 { 665 {
736 // Bullet adds this central force to the total force for this tick 666 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 667 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody) 668 if (PhysBody.HasPhysicalBody)
739 { 669 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 670 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
741 } 671 }
742 }); 672 });
743 } 673 }
@@ -748,35 +678,66 @@ public sealed class BSCharacter : BSPhysObject
748 } 678 }
749 } 679 }
750 680
751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 681 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
752 } 682 }
753 public override void SetMomentum(OMV.Vector3 momentum) { 683 public override void SetMomentum(OMV.Vector3 momentum) {
754 } 684 }
755 685
756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 686 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
757 { 687 {
758 OMV.Vector3 newScale; 688 OMV.Vector3 newScale = size;
759 689
760 // Bullet's capsule total height is the "passed height + radius * 2"; 690 // 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) 691 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
762 // The number we pass in for 'scaling' is the multiplier to get that base 692 // The number we pass in for 'scaling' is the multiplier to get that base
763 // shape to be the size desired. 693 // shape to be the size desired.
764 // So, when creating the scale for the avatar height, we take the passed height 694 // So, when creating the scale for the avatar height, we take the passed height
765 // (size.Z) and remove the caps. 695 // (size.Z) and remove the caps.
766 // Another oddity of the Bullet capsule implementation is that it presumes the Y 696 // An oddity of the Bullet capsule implementation is that it presumes the Y
767 // dimension is the radius of the capsule. Even though some of the code allows 697 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 698 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769 699
770 // Scale is multiplier of radius with one of "0.5" 700 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
773 701
774 // The total scale height is the central cylindar plus the caps on the two ends. 702 float heightAdjust = BSParam.AvatarHeightMidFudge;
775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 703 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
704 {
705 const float AVATAR_LOW = 1.1f;
706 const float AVATAR_MID = 1.775f; // 1.87f
707 const float AVATAR_HI = 2.45f;
708 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
709 float midHeightOffset = size.Z - AVATAR_MID;
710 if (midHeightOffset < 0f)
711 {
712 // Small avatar. Add the adjustment based on the distance from midheight
713 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
714 }
715 else
716 {
717 // Large avatar. Add the adjustment based on the distance from midheight
718 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
719 }
720 }
721 if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
722 {
723 newScale.X = size.X / 2f;
724 newScale.Y = size.Y / 2f;
725 // The total scale height is the central cylindar plus the caps on the two ends.
726 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
727 }
728 else
729 {
730 newScale.Z = size.Z + heightAdjust;
731 }
732 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
733
776 // If smaller than the endcaps, just fake like we're almost that small 734 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0) 735 if (newScale.Z < 0)
778 newScale.Z = 0.1f; 736 newScale.Z = 0.1f;
779 737
738 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
739 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
740
780 return newScale; 741 return newScale;
781 } 742 }
782 743
@@ -794,34 +755,59 @@ public sealed class BSCharacter : BSPhysObject
794 * Math.Min(Size.X, Size.Y) / 2 755 * Math.Min(Size.X, Size.Y) / 2
795 * Size.Y / 2f // plus the volume of the capsule end caps 756 * Size.Y / 2f // plus the volume of the capsule end caps
796 ); 757 );
797 _mass = _avatarDensity * _avatarVolume; 758 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
798 } 759 }
799 760
800 // The physics engine says that properties have updated. Update same and inform 761 // The physics engine says that properties have updated. Update same and inform
801 // the world that things have changed. 762 // the world that things have changed.
802 public override void UpdateProperties(EntityProperties entprop) 763 public override void UpdateProperties(EntityProperties entprop)
803 { 764 {
804 _position = entprop.Position; 765 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
805 _orientation = entprop.Rotation; 766 TriggerPreUpdatePropertyAction(ref entprop);
806 _velocity = entprop.Velocity; 767
768 RawPosition = entprop.Position;
769 RawOrientation = entprop.Rotation;
770
771 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
772 // and will send agent updates to the clients if velocity changes by more than
773 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
774 // extra updates.
775 //
776 // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
777 // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
778 // This is most noticeable in level flight and can be seen with
779 // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
780 // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
781 // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
782 // has not yet been identified.
783 //
784 // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
785 // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
786// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
787 RawVelocity = entprop.Velocity;
788
807 _acceleration = entprop.Acceleration; 789 _acceleration = entprop.Acceleration;
808 _rotationalVelocity = entprop.RotationalVelocity; 790 _rotationalVelocity = entprop.RotationalVelocity;
809 791
810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 792 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
811 PositionSanityCheck(true); 793 if (PositionSanityCheck(true))
794 {
795 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
796 entprop.Position = RawPosition;
797 }
812 798
813 // remember the current and last set values 799 // remember the current and last set values
814 LastEntityProperties = CurrentEntityProperties; 800 LastEntityProperties = CurrentEntityProperties;
815 CurrentEntityProperties = entprop; 801 CurrentEntityProperties = entprop;
816 802
817 // Tell the linkset about value changes 803 // Tell the linkset about value changes
818 Linkset.UpdateProperties(this, true); 804 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
819 805
820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 806 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
821 // base.RequestPhysicsterseUpdate(); 807 // PhysScene.PostUpdate(this);
822 808
823 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 809 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
824 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 810 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
825 } 811 }
826} 812}
827} 813}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
index b813974..e42e868 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
@@ -64,7 +64,7 @@ public abstract class BSConstraint : IDisposable
64 { 64 {
65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); 65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
67 BSScene.DetailLogZero, 67 m_body1.ID,
68 m_body1.ID, m_body1.AddrString, 68 m_body1.ID, m_body1.AddrString,
69 m_body2.ID, m_body2.AddrString, 69 m_body2.ID, m_body2.AddrString,
70 success); 70 success);
@@ -77,7 +77,10 @@ public abstract class BSConstraint : IDisposable
77 { 77 {
78 bool ret = false; 78 bool ret = false;
79 if (m_enabled) 79 if (m_enabled)
80 {
81 m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); 82 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
83 }
81 return ret; 84 return ret;
82 } 85 }
83 86
@@ -85,7 +88,10 @@ public abstract class BSConstraint : IDisposable
85 { 88 {
86 bool ret = false; 89 bool ret = false;
87 if (m_enabled) 90 if (m_enabled)
91 {
92 m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); 93 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
94 }
89 return ret; 95 return ret;
90 } 96 }
91 97
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
index ecb1b32..4bcde2b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
@@ -29,15 +29,22 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public sealed class BSConstraint6Dof : BSConstraint 35public class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38 38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
42 {
43 m_body1 = obj1;
44 m_body2 = obj2;
45 m_enabled = false;
46 }
47
41 // Create a btGeneric6DofConstraint 48 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, 49 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 50 Vector3 frame1, Quaternion frame1rot,
@@ -52,11 +59,14 @@ public sealed class BSConstraint6Dof : BSConstraint
52 frame2, frame2rot, 59 frame2, frame2rot,
53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 60 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 m_enabled = true; 61 m_enabled = true;
55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 62 PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
56 BSScene.DetailLogZero, world.worldID, 63 m_body1.ID, world.worldID,
57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 64 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
65 PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
66 m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
58 } 67 }
59 68
69 // 6 Dof constraint based on a midpoint between the two constrained bodies
60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, 70 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
61 Vector3 joinPoint, 71 Vector3 joinPoint,
62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 72 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@@ -78,9 +88,11 @@ public sealed class BSConstraint6Dof : BSConstraint
78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, 88 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
79 joinPoint, 89 joinPoint,
80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); 90 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
91
81 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 92 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString, 93 m_body1.ID, world.worldID, m_constraint.AddrString,
83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); 94 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
95
84 if (!m_constraint.HasPhysicalConstraint) 96 if (!m_constraint.HasPhysicalConstraint)
85 { 97 {
86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 98 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
@@ -94,6 +106,23 @@ public sealed class BSConstraint6Dof : BSConstraint
94 } 106 }
95 } 107 }
96 108
109 // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
110 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
111 bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
112 : base(world)
113 {
114 m_body1 = obj1;
115 m_body2 = obj1; // Look out for confusion down the road
116 m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
117 frameInBloc, frameInBrot,
118 useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
119 m_enabled = true;
120 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
121 m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
122 PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
123 m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
124 }
125
97 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 126 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
98 { 127 {
99 bool ret = false; 128 bool ret = false;
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
index 87d1e44..5746ac1 100644..100755
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
@@ -30,7 +30,7 @@ using System.Text;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSNPlugin 33namespace OpenSim.Region.PhysicsModule.BulletS
34{ 34{
35 35
36public sealed class BSConstraintCollection : IDisposable 36public sealed class BSConstraintCollection : IDisposable
@@ -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/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
new file mode 100755
index 0000000..e7566a8
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
@@ -0,0 +1,54 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.PhysicsModule.BulletS
33{
34
35public sealed class BSConstraintConeTwist : BSConstraint
36{
37 public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
38
39 public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
44 {
45 m_body1 = obj1;
46 m_body2 = obj2;
47 m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 disableCollisionsBetweenLinkedBodies);
50 m_enabled = true;
51 }
52}
53
54}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
index 7714a03..d20538d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public sealed class BSConstraintHinge : BSConstraint 35public sealed class BSConstraintHinge : BSConstraint
@@ -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/BulletSNPlugin/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
index fbd1bc0..83d42af 100644..100755
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
@@ -29,26 +29,24 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSNPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34 34
35public sealed class BSConstraintHinge : BSConstraint 35public sealed class BSConstraintSlider : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
38 38
39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 frameInAloc, Quaternion frameInArot,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 frameInBloc, Quaternion frameInBrot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
43 { 44 {
44 m_world = world;
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = new BulletConstraint( 47 m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, 48 frameInAloc, frameInArot, frameInBloc, frameInBrot,
49 pivotInA, pivotInB, 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true; 50 m_enabled = true;
53 } 51 }
54 52
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
new file mode 100755
index 0000000..563a1b1
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
@@ -0,0 +1,103 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Region.PhysicsModule.BulletS
33{
34
35public sealed class BSConstraintSpring : BSConstraint6Dof
36{
37 public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
38
39 public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 frame1Loc, Quaternion frame1Rot,
41 Vector3 frame2Loc, Quaternion frame2Rot,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 :base(world, obj1, obj2)
44 {
45 m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
46 frame1Loc, frame1Rot, frame2Loc, frame2Rot,
47 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
48 m_enabled = true;
49
50 PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
51 obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
52 PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
53 m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
54 }
55
56 public bool SetAxisEnable(int pIndex, bool pAxisEnable)
57 {
58 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
59 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
60 PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
61 return true;
62 }
63
64 public bool SetStiffness(int pIndex, float pStiffness)
65 {
66 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
67 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
68 PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
69 return true;
70 }
71
72 public bool SetDamping(int pIndex, float pDamping)
73 {
74 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
75 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
76 PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
77 return true;
78 }
79
80 public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
81 {
82 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
83 m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
84 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
85 return true;
86 }
87
88 public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
89 {
90 PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
91 m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
92 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
93 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
94 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
95 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
96 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
97 PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
98 return true;
99 }
100
101}
102
103} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
index 415ad4f..0fc5577 100644
--- a/OpenSim/Region/Physics/BulletSNPlugin/BSDynamics.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
@@ -35,17 +35,21 @@ using System.Collections.Generic;
35using System.Reflection; 35using System.Reflection;
36using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Region.Physics.Manager; 38using OpenSim.Framework;
39using OpenSim.Region.PhysicsModules.SharedBase;
39 40
40namespace OpenSim.Region.Physics.BulletSNPlugin 41namespace OpenSim.Region.PhysicsModule.BulletS
41{ 42{
42 public sealed class BSDynamics 43 public sealed class BSDynamics : BSActor
43 { 44 {
45#pragma warning disable 414
44 private static string LogHeader = "[BULLETSIM VEHICLE]"; 46 private static string LogHeader = "[BULLETSIM VEHICLE]";
47#pragma warning restore 414
45 48
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to 49 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; } 50 private BSPrimLinkable ControllingPrim { get; set; }
51
52 private bool m_haveRegisteredForSceneEvents;
49 53
50 // mass of the vehicle fetched each time we're calles 54 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass; 55 private float m_vehicleMass;
@@ -72,8 +76,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 76 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
74 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 78 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
75 private float m_linearMotorDecayTimescale = 0; 79 private float m_linearMotorDecayTimescale = 1;
76 private float m_linearMotorTimescale = 0; 80 private float m_linearMotorTimescale = 1;
77 private Vector3 m_lastLinearVelocityVector = Vector3.Zero; 81 private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
78 private Vector3 m_lastPositionVector = Vector3.Zero; 82 private Vector3 m_lastPositionVector = Vector3.Zero;
79 // private bool m_LinearMotorSetLastFrame = false; 83 // private bool m_LinearMotorSetLastFrame = false;
@@ -84,8 +88,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
85 // private int m_angularMotorApply = 0; // application frame counter 89 // private int m_angularMotorApply = 0; // application frame counter
86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 91 private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate
88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 92 private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate
89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 93 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
90 private Vector3 m_lastAngularVelocity = Vector3.Zero; 94 private Vector3 m_lastAngularVelocity = Vector3.Zero;
91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
@@ -99,7 +103,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
99 103
100 //Banking properties 104 //Banking properties
101 private float m_bankingEfficiency = 0; 105 private float m_bankingEfficiency = 0;
102 private float m_bankingMix = 0; 106 private float m_bankingMix = 1;
103 private float m_bankingTimescale = 0; 107 private float m_bankingTimescale = 0;
104 108
105 //Hover and Buoyancy properties 109 //Hover and Buoyancy properties
@@ -108,10 +112,9 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
108 private float m_VhoverEfficiency = 0f; 112 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f; 113 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 114 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. 115 // 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) 116 private float m_VehicleBuoyancy = 0f;
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 117 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 118
116 //Attractor properties 119 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); 120 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
@@ -121,74 +124,95 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
121 private float m_verticalAttractionTimescale = 510f; 124 private float m_verticalAttractionTimescale = 510f;
122 125
123 // Just some recomputed constants: 126 // Just some recomputed constants:
127#pragma warning disable 414
128 static readonly float TwoPI = ((float)Math.PI) * 2f;
129 static readonly float FourPI = ((float)Math.PI) * 4f;
124 static readonly float PIOverFour = ((float)Math.PI) / 4f; 130 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f; 131 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
132#pragma warning restore 414
126 133
127 public BSDynamics(BSScene myScene, BSPrim myPrim) 134 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
135 : base(myScene, myPrim, actorName)
128 { 136 {
129 PhysicsScene = myScene;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE; 137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
139
140 ControllingPrim = myPrim as BSPrimLinkable;
141 if (ControllingPrim == null)
142 {
143 // THIS CANNOT HAPPEN!!
144 }
145 VDetailLog("{0},Creation", ControllingPrim.LocalID);
132 } 146 }
133 147
134 // Return 'true' if this vehicle is doing vehicle things 148 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive 149 public bool IsActive
136 { 150 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } 151 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
152 }
153
154 // Return 'true' if this a vehicle that should be sitting on the ground
155 public bool IsGroundVehicle
156 {
157 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
138 } 158 }
139 159
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 160 #region Vehicle parameter setting
161 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 { 162 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 163 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
164 float clampTemp;
165
143 switch (pParam) 166 switch (pParam)
144 { 167 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 168 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
146 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 169 m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
147 break; 170 break;
148 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 171 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 172 m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120);
150 break; 173 break;
151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 174 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); 175 m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; 176 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
154 break; 177 break;
155 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 178 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
156 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 179 m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120);
157 m_angularMotor.TimeScale = m_angularMotorTimescale; 180 m_angularMotor.TimeScale = m_angularMotorTimescale;
158 break; 181 break;
159 case Vehicle.BANKING_EFFICIENCY: 182 case Vehicle.BANKING_EFFICIENCY:
160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); 183 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
161 break; 184 break;
162 case Vehicle.BANKING_MIX: 185 case Vehicle.BANKING_MIX:
163 m_bankingMix = Math.Max(pValue, 0.01f); 186 m_bankingMix = ClampInRange(0.01f, pValue, 1);
164 break; 187 break;
165 case Vehicle.BANKING_TIMESCALE: 188 case Vehicle.BANKING_TIMESCALE:
166 m_bankingTimescale = Math.Max(pValue, 0.01f); 189 m_bankingTimescale = ClampInRange(0.25f, pValue, 120);
167 break; 190 break;
168 case Vehicle.BUOYANCY: 191 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); 192 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
193 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
170 break; 194 break;
171 case Vehicle.HOVER_EFFICIENCY: 195 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); 196 m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f);
173 break; 197 break;
174 case Vehicle.HOVER_HEIGHT: 198 case Vehicle.HOVER_HEIGHT:
175 m_VhoverHeight = pValue; 199 m_VhoverHeight = ClampInRange(0f, pValue, 1000000f);
176 break; 200 break;
177 case Vehicle.HOVER_TIMESCALE: 201 case Vehicle.HOVER_TIMESCALE:
178 m_VhoverTimescale = Math.Max(pValue, 0.01f); 202 m_VhoverTimescale = ClampInRange(0.01f, pValue, 120);
179 break; 203 break;
180 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 204 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
181 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 205 m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
182 break; 206 break;
183 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 207 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 208 m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120);
185 break; 209 break;
186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 210 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); 211 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; 212 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 213 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 214 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 215 m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120);
192 m_linearMotor.TimeScale = m_linearMotorTimescale; 216 m_linearMotor.TimeScale = m_linearMotorTimescale;
193 break; 217 break;
194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 218 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
@@ -196,31 +220,35 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; 220 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
197 break; 221 break;
198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 222 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 223 m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; 224 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
201 break; 225 break;
202 226
203 // These are vector properties but the engine lets you use a single float value to 227 // These are vector properties but the engine lets you use a single float value to
204 // set all of the components to the same value 228 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 229 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 230 clampTemp = ClampInRange(0.01f, pValue, 120);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; 231 m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
208 break; 232 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION: 233 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 234 clampTemp = ClampInRange(-TwoPI, pValue, TwoPI);
235 m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
236 m_angularMotor.Zero();
211 m_angularMotor.SetTarget(m_angularMotorDirection); 237 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break; 238 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE: 239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 240 clampTemp = ClampInRange(0.01f, pValue, 120);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; 241 m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
216 break; 242 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION: 243 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 244 clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity);
219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 245 m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
246 m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp);
220 m_linearMotor.SetTarget(m_linearMotorDirection); 247 m_linearMotor.SetTarget(m_linearMotorDirection);
221 break; 248 break;
222 case Vehicle.LINEAR_MOTOR_OFFSET: 249 case Vehicle.LINEAR_MOTOR_OFFSET:
223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 250 clampTemp = ClampInRange(-1000, pValue, 1000);
251 m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp);
224 break; 252 break;
225 253
226 } 254 }
@@ -228,34 +256,50 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
228 256
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 257 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 { 258 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 259 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
232 switch (pParam) 260 switch (pParam)
233 { 261 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 262 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
263 pValue.X = ClampInRange(0.25f, pValue.X, 120);
264 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
265 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 266 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break; 267 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION: 268 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec 269 // Limit requested angular speed to 2 rps= 4 pi rads/sec
240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); 270 pValue.X = ClampInRange(-FourPI, pValue.X, FourPI);
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); 271 pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); 272 pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 273 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
274 m_angularMotor.Zero();
244 m_angularMotor.SetTarget(m_angularMotorDirection); 275 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break; 276 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE: 277 case Vehicle.LINEAR_FRICTION_TIMESCALE:
278 pValue.X = ClampInRange(0.25f, pValue.X, 120);
279 pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
280 pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 281 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break; 282 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION: 283 case Vehicle.LINEAR_MOTOR_DIRECTION:
284 pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity);
285 pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity);
286 pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity);
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 287 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 288 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection); 289 m_linearMotor.SetTarget(m_linearMotorDirection);
254 break; 290 break;
255 case Vehicle.LINEAR_MOTOR_OFFSET: 291 case Vehicle.LINEAR_MOTOR_OFFSET:
292 // Not sure the correct range to limit this variable
293 pValue.X = ClampInRange(-1000, pValue.X, 1000);
294 pValue.Y = ClampInRange(-1000, pValue.Y, 1000);
295 pValue.Z = ClampInRange(-1000, pValue.Z, 1000);
256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 296 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break; 297 break;
258 case Vehicle.BLOCK_EXIT: 298 case Vehicle.BLOCK_EXIT:
299 // Not sure the correct range to limit this variable
300 pValue.X = ClampInRange(-10000, pValue.X, 10000);
301 pValue.Y = ClampInRange(-10000, pValue.Y, 10000);
302 pValue.Z = ClampInRange(-10000, pValue.Z, 10000);
259 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 303 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break; 304 break;
261 } 305 }
@@ -263,7 +307,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
263 307
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 308 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 { 309 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 310 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
267 switch (pParam) 311 switch (pParam)
268 { 312 {
269 case Vehicle.REFERENCE_FRAME: 313 case Vehicle.REFERENCE_FRAME:
@@ -277,7 +321,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
277 321
278 internal void ProcessVehicleFlags(int pParam, bool remove) 322 internal void ProcessVehicleFlags(int pParam, bool remove)
279 { 323 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 324 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam; 325 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1) 326 if (pParam == -1)
283 m_flags = (VehicleFlag)0; 327 m_flags = (VehicleFlag)0;
@@ -290,9 +334,9 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
290 } 334 }
291 } 335 }
292 336
293 internal void ProcessTypeChange(Vehicle pType) 337 public void ProcessTypeChange(Vehicle pType)
294 { 338 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 339 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
296 // Set Defaults For Type 340 // Set Defaults For Type
297 Type = pType; 341 Type = pType;
298 switch (pType) 342 switch (pType)
@@ -526,81 +570,144 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
526 break; 570 break;
527 } 571 }
528 572
529 // Update any physical parameters based on this type. 573 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
530 Refresh(); 574 // 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 575
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 576 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 577 // 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 578
579 /* Not implemented
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, 580 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector, 581 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency); 582 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y 583 // 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) 584 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
585 */
586
587 if (this.Type == Vehicle.TYPE_NONE)
588 {
589 UnregisterForSceneEvents();
590 }
591 else
592 {
593 RegisterForSceneEvents();
594 }
595
596 // Update any physical parameters based on this type.
597 Refresh();
598 }
599 #endregion // Vehicle parameter setting
600
601 // BSActor.Refresh()
602 public override void Refresh()
603 {
604 // If asking for a refresh, reset the physical parameters before the next simulation step.
605 // Called whether active or not since the active state may be updated before the next step.
606 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
607 {
608 SetPhysicalParameters();
609 });
548 } 610 }
549 611
550 // Some of the properties of this prim may have changed. 612 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle 613 // Do any updating needed for a vehicle
552 public void Refresh() 614 private void SetPhysicalParameters()
553 { 615 {
554 if (IsActive) 616 if (IsActive)
555 { 617 {
556 // Remember the mass so we don't have to fetch it every step 618 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass; 619 m_vehicleMass = ControllingPrim.TotalMass;
558 620
559 // Friction affects are handled by this vehicle code 621 // Friction affects are handled by this vehicle code
560 float friction = 0f; 622 // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
561 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); 623 // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
624 ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
625 ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
562 626
563 // Moderate angular movement introduced by Bullet. 627 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 628 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params. 629 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping; 630 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
567 BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); 631 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
632 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
568 633
569 // Vehicles report collision events so we know when it's on the ground 634 // Vehicles report collision events so we know when it's on the ground
570 BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); 635 // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
636 ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
637
638 // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
639 // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
640 // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
641 // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
642 ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
643
644 // Set the gravity for the vehicle depending on the buoyancy
645 // TODO: what should be done if prim and vehicle buoyancy differ?
646 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
647 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
648 // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
649 ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
650
651 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
652 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
653 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
654 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
655 );
656 }
657 else
658 {
659 if (ControllingPrim.PhysBody.HasPhysicalBody)
660 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
661 // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
662 }
663 }
571 664
572 Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); 665 // BSActor.RemoveBodyDependencies
573 BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); 666 public override void RemoveDependencies()
574 BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); 667 {
668 Refresh();
669 }
575 670
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); 671 // BSActor.Release()
577 BulletSimAPI.SetGravity2(Prim.PhysBody.ptr, grav); 672 public override void Dispose()
673 {
674 VDetailLog("{0},Dispose", ControllingPrim.LocalID);
675 UnregisterForSceneEvents();
676 Type = Vehicle.TYPE_NONE;
677 Enabled = false;
678 return;
679 }
578 680
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", 681 private void RegisterForSceneEvents()
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); 682 {
581 } 683 if (!m_haveRegisteredForSceneEvents)
582 else
583 { 684 {
584 BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); 685 m_physicsScene.BeforeStep += this.Step;
686 m_physicsScene.AfterStep += this.PostStep;
687 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
688 m_haveRegisteredForSceneEvents = true;
585 } 689 }
586 } 690 }
587 691
588 public bool RemoveBodyDependencies(BSPhysObject prim) 692 private void UnregisterForSceneEvents()
589 { 693 {
590 // If active, we need to add our properties back when the body is rebuilt. 694 if (m_haveRegisteredForSceneEvents)
591 return IsActive; 695 {
696 m_physicsScene.BeforeStep -= this.Step;
697 m_physicsScene.AfterStep -= this.PostStep;
698 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
699 m_haveRegisteredForSceneEvents = false;
700 }
592 } 701 }
593 702
594 public void RestoreBodyDependencies(BSPhysObject prim) 703 private void PreUpdateProperty(ref EntityProperties entprop)
595 { 704 {
596 if (Prim.LocalID != prim.LocalID) 705 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
706 // TODO: handle physics introduced by Bullet with computed vehicle physics.
707 if (IsActive)
597 { 708 {
598 // The call should be on us by our prim. Error if not. 709 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 } 710 }
603 Refresh();
604 } 711 }
605 712
606 #region Known vehicle value functions 713 #region Known vehicle value functions
@@ -617,70 +724,85 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
617 private Vector3 m_knownPosition; 724 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity; 725 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce; 726 private Vector3 m_knownForce;
727 private Vector3 m_knownForceImpulse;
620 private Quaternion m_knownOrientation; 728 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity; 729 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce; 730 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed 731 private Vector3 m_knownRotationalImpulse;
624 732
625 private const int m_knownChangedPosition = 1 << 0; 733 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1; 734 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2; 735 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3; 736 private const int m_knownChangedForceImpulse = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4; 737 private const int m_knownChangedOrientation = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5; 738 private const int m_knownChangedRotationalVelocity = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6; 739 private const int m_knownChangedRotationalForce = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7; 740 private const int m_knownChangedRotationalImpulse = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8; 741 private const int m_knownChangedTerrainHeight = 1 << 8;
634 742 private const int m_knownChangedWaterLevel = 1 << 9;
635 private void ForgetKnownVehicleProperties() 743
744 public void ForgetKnownVehicleProperties()
636 { 745 {
637 m_knownHas = 0; 746 m_knownHas = 0;
638 m_knownChanged = 0; 747 m_knownChanged = 0;
639 } 748 }
640 // Push all the changed values back into the physics engine 749 // Push all the changed values back into the physics engine
641 private void PushKnownChanged() 750 public void PushKnownChanged()
642 { 751 {
643 if (m_knownChanged != 0) 752 if (m_knownChanged != 0)
644 { 753 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0) 754 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition; 755 ControllingPrim.ForcePosition = m_knownPosition;
647 756
648 if ((m_knownChanged & m_knownChangedOrientation) != 0) 757 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation; 758 ControllingPrim.ForceOrientation = m_knownOrientation;
650 759
651 if ((m_knownChanged & m_knownChangedVelocity) != 0) 760 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 { 761 {
653 Prim.ForceVelocity = m_knownVelocity; 762 ControllingPrim.ForceVelocity = m_knownVelocity;
654 BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); 763 // Fake out Bullet by making it think the velocity is the same as last time.
764 // Bullet does a bunch of smoothing for changing parameters.
765 // Since the vehicle is demanding this setting, we override Bullet's smoothing
766 // by telling Bullet the value was the same last time.
767 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
655 } 768 }
656 769
657 if ((m_knownChanged & m_knownChangedForce) != 0) 770 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true); 771 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
772
773 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
774 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
659 775
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) 776 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 { 777 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity; 778 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time. 779 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
664 BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity);
665 } 780 }
666 781
782 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
783 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
784
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) 785 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); 786 {
787 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
788 }
669 789
670 // If we set one of the values (ie, the physics engine didn't do it) we must force 790 // 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. 791 // an UpdateProperties event to send the changes up to the simulator.
672 BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); 792 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
673 } 793 }
674 m_knownChanged = 0; 794 m_knownChanged = 0;
675 } 795 }
676 796
677 // Since the computation of terrain height can be a little involved, this routine 797 // 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. 798 // is used to fetch the height only once for each vehicle simulation step.
799 Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
679 private float GetTerrainHeight(Vector3 pos) 800 private float GetTerrainHeight(Vector3 pos)
680 { 801 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0) 802 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
682 { 803 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 804 lastRememberedHeightPos = pos;
805 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight; 806 m_knownHas |= m_knownChangedTerrainHeight;
685 } 807 }
686 return m_knownTerrainHeight; 808 return m_knownTerrainHeight;
@@ -688,14 +810,16 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
688 810
689 // Since the computation of water level can be a little involved, this routine 811 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step. 812 // is used ot fetch the level only once for each vehicle simulation step.
813 Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
691 private float GetWaterLevel(Vector3 pos) 814 private float GetWaterLevel(Vector3 pos)
692 { 815 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 816 if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
694 { 817 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 818 lastRememberedWaterHeightPos = pos;
819 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel; 820 m_knownHas |= m_knownChangedWaterLevel;
697 } 821 }
698 return (float)m_knownWaterLevel; 822 return m_knownWaterLevel;
699 } 823 }
700 824
701 private Vector3 VehiclePosition 825 private Vector3 VehiclePosition
@@ -704,7 +828,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
704 { 828 {
705 if ((m_knownHas & m_knownChangedPosition) == 0) 829 if ((m_knownHas & m_knownChangedPosition) == 0)
706 { 830 {
707 m_knownPosition = Prim.ForcePosition; 831 m_knownPosition = ControllingPrim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition; 832 m_knownHas |= m_knownChangedPosition;
709 } 833 }
710 return m_knownPosition; 834 return m_knownPosition;
@@ -723,7 +847,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
723 { 847 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0) 848 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 { 849 {
726 m_knownOrientation = Prim.ForceOrientation; 850 m_knownOrientation = ControllingPrim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation; 851 m_knownHas |= m_knownChangedOrientation;
728 } 852 }
729 return m_knownOrientation; 853 return m_knownOrientation;
@@ -742,10 +866,10 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
742 { 866 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0) 867 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 { 868 {
745 m_knownVelocity = Prim.ForceVelocity; 869 m_knownVelocity = ControllingPrim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity; 870 m_knownHas |= m_knownChangedVelocity;
747 } 871 }
748 return (Vector3)m_knownVelocity; 872 return m_knownVelocity;
749 } 873 }
750 set 874 set
751 { 875 {
@@ -755,15 +879,26 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
755 } 879 }
756 } 880 }
757 881
758 private void VehicleAddForce(Vector3 aForce) 882 private void VehicleAddForce(Vector3 pForce)
759 { 883 {
760 if ((m_knownHas & m_knownChangedForce) == 0) 884 if ((m_knownHas & m_knownChangedForce) == 0)
761 { 885 {
762 m_knownForce = Vector3.Zero; 886 m_knownForce = Vector3.Zero;
887 m_knownHas |= m_knownChangedForce;
763 } 888 }
764 m_knownForce += aForce; 889 m_knownForce += pForce;
765 m_knownChanged |= m_knownChangedForce; 890 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce; 891 }
892
893 private void VehicleAddForceImpulse(Vector3 pImpulse)
894 {
895 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
896 {
897 m_knownForceImpulse = Vector3.Zero;
898 m_knownHas |= m_knownChangedForceImpulse;
899 }
900 m_knownForceImpulse += pImpulse;
901 m_knownChanged |= m_knownChangedForceImpulse;
767 } 902 }
768 903
769 private Vector3 VehicleRotationalVelocity 904 private Vector3 VehicleRotationalVelocity
@@ -772,7 +907,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
772 { 907 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) 908 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 { 909 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity; 910 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity; 911 m_knownHas |= m_knownChangedRotationalVelocity;
777 } 912 }
778 return (Vector3)m_knownRotationalVelocity; 913 return (Vector3)m_knownRotationalVelocity;
@@ -794,19 +929,26 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
794 m_knownChanged |= m_knownChangedRotationalForce; 929 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce; 930 m_knownHas |= m_knownChangedRotationalForce;
796 } 931 }
932 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
933 {
934 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
935 {
936 m_knownRotationalImpulse = Vector3.Zero;
937 m_knownHas |= m_knownChangedRotationalImpulse;
938 }
939 m_knownRotationalImpulse += pImpulse;
940 m_knownChanged |= m_knownChangedRotationalImpulse;
941 }
942
797 // Vehicle relative forward velocity 943 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity 944 private Vector3 VehicleForwardVelocity
799 { 945 {
800 get 946 get
801 { 947 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0) 948 return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation));
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 } 949 }
809 } 950 }
951
810 private float VehicleForwardSpeed 952 private float VehicleForwardSpeed
811 { 953 {
812 get 954 get
@@ -814,6 +956,13 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
814 return VehicleForwardVelocity.X; 956 return VehicleForwardVelocity.X;
815 } 957 }
816 } 958 }
959 private Quaternion VehicleFrameOrientation
960 {
961 get
962 {
963 return VehicleOrientation * m_referenceFrame;
964 }
965 }
817 966
818 #endregion // Known vehicle value functions 967 #endregion // Known vehicle value functions
819 968
@@ -836,106 +985,170 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
836 // for the physics engine to note the changes so an UpdateProperties event will happen. 985 // for the physics engine to note the changes so an UpdateProperties event will happen.
837 PushKnownChanged(); 986 PushKnownChanged();
838 987
839 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 988 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
840 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); 989 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
990
991 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
992 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
993 }
994
995 // Called after the simulation step
996 internal void PostStep(float pTimestep)
997 {
998 if (!IsActive) return;
999
1000 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
1001 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
841 } 1002 }
842 1003
843 // Apply the effect of the linear motor and other linear motions (like hover and float). 1004 // Apply the effect of the linear motor and other linear motions (like hover and float).
844 private void MoveLinear(float pTimestep) 1005 private void MoveLinear(float pTimestep)
845 { 1006 {
846 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); 1007 ComputeLinearVelocity(pTimestep);
847 1008
848 // The movement computed in the linear motor is relative to the vehicle 1009 ComputeLinearDeflection(pTimestep);
849 // coordinates. Rotate the movement to world coordinates.
850 linearMotorContribution *= VehicleOrientation;
851 1010
852 // ================================================================== 1011 ComputeLinearTerrainHeightCorrection(pTimestep);
853 // Buoyancy: force to overcome gravity.
854 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
855 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
856 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
857
858 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
859 1012
860 Vector3 hoverContribution = ComputeLinearHover(pTimestep); 1013 ComputeLinearHover(pTimestep);
861 1014
862 ComputeLinearBlockingEndPoint(pTimestep); 1015 ComputeLinearBlockingEndPoint(pTimestep);
863 1016
864 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); 1017 ComputeLinearMotorUp(pTimestep);
865
866 // ==================================================================
867 Vector3 newVelocity = linearMotorContribution
868 + terrainHeightContribution
869 + hoverContribution
870 + limitMotorUpContribution;
871 1018
872 Vector3 newForce = buoyancyContribution; 1019 ApplyGravity(pTimestep);
873 1020
874 // If not changing some axis, reduce out velocity 1021 // If not changing some axis, reduce out velocity
875 if ((m_flags & (VehicleFlag.NO_X)) != 0) 1022 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
876 newVelocity.X = 0; 1023 {
877 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 1024 Vector3 vel = VehicleVelocity;
878 newVelocity.Y = 0; 1025 if ((m_flags & (VehicleFlag.NO_X)) != 0)
879 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 1026 {
880 newVelocity.Z = 0; 1027 vel.X = 0;
1028 }
1029 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
1030 {
1031 vel.Y = 0;
1032 }
1033 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
1034 {
1035 vel.Z = 0;
1036 }
1037 VehicleVelocity = vel;
1038 }
881 1039
882 // ================================================================== 1040 // ==================================================================
883 // Clamp high or low velocities 1041 // Clamp high or low velocities
884 float newVelocityLengthSq = newVelocity.LengthSquared(); 1042 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
885 if (newVelocityLengthSq > 1000f) 1043 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
886 { 1044 {
887 newVelocity /= newVelocity.Length(); 1045 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
888 newVelocity *= 1000f; 1046 VehicleVelocity /= VehicleVelocity.Length();
1047 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1048 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1049 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
1050 }
1051 else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
1052 {
1053 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
1054 VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
1055 ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
1056 VehicleVelocity = Vector3.Zero;
889 } 1057 }
890 else if (newVelocityLengthSq < 0.001f)
891 newVelocity = Vector3.Zero;
892 1058
893 // ================================================================== 1059 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
894 // Stuff new linear velocity into the vehicle. 1060
895 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. 1061 } // end MoveLinear()
896 VehicleVelocity = newVelocity; 1062
1063 public void ComputeLinearVelocity(float pTimestep)
1064 {
1065 // Step the motor from the current value. Get the correction needed this step.
1066 Vector3 origVelW = VehicleVelocity; // DEBUG
1067 Vector3 currentVelV = VehicleForwardVelocity;
1068 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1069
1070 // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
1071 Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1072 linearMotorCorrectionV -= (currentVelV * frictionFactorV);
1073
1074 // Motor is vehicle coordinates. Rotate it to world coordinates
1075 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation;
897 1076
898 // Other linear forces are applied as forces. 1077 // If we're a ground vehicle, don't add any upward Z movement
899 Vector3 totalDownForce = newForce * m_vehicleMass; 1078 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
900 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
901 { 1079 {
902 VehicleAddForce(totalDownForce); 1080 if (linearMotorVelocityW.Z > 0f)
1081 linearMotorVelocityW.Z = 0f;
903 } 1082 }
904 1083
905 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", 1084 // Add this correction to the velocity to make it faster/slower.
906 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); 1085 VehicleVelocity += linearMotorVelocityW;
907 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
908 Prim.LocalID,
909 linearMotorContribution, terrainHeightContribution, hoverContribution,
910 limitMotorUpContribution, buoyancyContribution
911 );
912 1086
913 } // end MoveLinear() 1087 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
1088 ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
1089 linearMotorVelocityW, VehicleVelocity, frictionFactorV);
1090 }
1091
1092 //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
1093 //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
1094 private void ComputeLinearDeflection(float pTimestep)
1095 {
1096 Vector3 linearDeflectionV = Vector3.Zero;
1097 Vector3 velocityV = VehicleForwardVelocity;
1098
1099 if (BSParam.VehicleEnableLinearDeflection)
1100 {
1101 // Velocity in Y and Z dimensions is movement to the side or turning.
1102 // Compute deflection factor from the to the side and rotational velocity
1103 linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
1104 linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
1105
1106 // Velocity to the side and around is corrected and moved into the forward direction
1107 linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
1108 linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
1109
1110 // Scale the deflection to the fractional simulation time
1111 linearDeflectionV *= pTimestep;
1112
1113 // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
1114 linearDeflectionV *= new Vector3(1, -1, -1);
1115
1116 // Correction is vehicle relative. Convert to world coordinates.
1117 Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation;
1118
1119 // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
1120 if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
1121 {
1122 linearDeflectionW.Z = 0f;
1123 }
1124
1125 VehicleVelocity += linearDeflectionW;
1126
1127 VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
1128 ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
1129 }
1130 }
914 1131
915 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) 1132 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
916 { 1133 {
917 Vector3 ret = Vector3.Zero;
918 // If below the terrain, move us above the ground a little. 1134 // If below the terrain, move us above the ground a little.
919 // TODO: Consider taking the rotated size of the object or possibly casting a ray. 1135 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
920 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) 1136 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
921 { 1137 {
922 // TODO: correct position by applying force rather than forcing position. 1138 // Force position because applying force won't get the vehicle through the terrain
923 Vector3 newPosition = VehiclePosition; 1139 Vector3 newPosition = VehiclePosition;
924 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; 1140 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
925 VehiclePosition = newPosition; 1141 VehiclePosition = newPosition;
926 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", 1142 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
927 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); 1143 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
928 } 1144 }
929 return ret;
930 } 1145 }
931 1146
932 public Vector3 ComputeLinearHover(float pTimestep) 1147 public void ComputeLinearHover(float pTimestep)
933 { 1148 {
934 Vector3 ret = Vector3.Zero;
935
936 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1149 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
937 // m_VhoverTimescale: time to achieve height 1150 // m_VhoverTimescale: time to achieve height
938 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1151 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300))
939 { 1152 {
940 // We should hover, get the target height 1153 // We should hover, get the target height
941 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 1154 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
@@ -950,14 +1163,25 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
950 { 1163 {
951 m_VhoverTargetHeight = m_VhoverHeight; 1164 m_VhoverTargetHeight = m_VhoverHeight;
952 } 1165 }
953
954 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 1166 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
955 { 1167 {
956 // If body is already heigher, use its height as target height 1168 // If body is already heigher, use its height as target height
957 if (VehiclePosition.Z > m_VhoverTargetHeight) 1169 if (VehiclePosition.Z > m_VhoverTargetHeight)
1170 {
958 m_VhoverTargetHeight = VehiclePosition.Z; 1171 m_VhoverTargetHeight = VehiclePosition.Z;
1172
1173 // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
1174 // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
1175 // scripts that it could not be changed.
1176 // So, if above the height, reapply gravity if buoyancy had it turned off.
1177 if (m_VehicleBuoyancy != 0)
1178 {
1179 Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
1180 VehicleAddForce(appliedGravity);
1181 }
1182 }
959 } 1183 }
960 1184
961 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1185 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
962 { 1186 {
963 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1187 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -965,26 +1189,41 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
965 Vector3 pos = VehiclePosition; 1189 Vector3 pos = VehiclePosition;
966 pos.Z = m_VhoverTargetHeight; 1190 pos.Z = m_VhoverTargetHeight;
967 VehiclePosition = pos; 1191 VehiclePosition = pos;
1192
1193 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
968 } 1194 }
969 } 1195 }
970 else 1196 else
971 { 1197 {
972 // Error is positive if below the target and negative if above. 1198 // Error is positive if below the target and negative if above.
973 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; 1199 Vector3 hpos = VehiclePosition;
1200 float verticalError = m_VhoverTargetHeight - hpos.Z;
1201 float verticalCorrection = verticalError / m_VhoverTimescale;
1202 verticalCorrection *= m_VhoverEfficiency;
1203
1204 hpos.Z += verticalCorrection;
1205 VehiclePosition = hpos;
1206
1207 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
1208 Vector3 vel = VehicleVelocity;
1209 vel.Z = 0f;
1210 VehicleVelocity = vel;
1211
1212 /*
974 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; 1213 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
1214 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1215 verticalCorrection *= m_vehicleMass;
975 1216
976 // TODO: implement m_VhoverEfficiency correctly 1217 // TODO: implement m_VhoverEfficiency correctly
977 if (Math.Abs(verticalError) > m_VhoverEfficiency) 1218 VehicleAddForceImpulse(verticalCorrection);
978 { 1219 */
979 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
980 }
981 }
982 1220
983 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", 1221 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
984 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); 1222 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1223 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1224 verticalError, verticalCorrection);
1225 }
985 } 1226 }
986
987 return ret;
988 } 1227 }
989 1228
990 public bool ComputeLinearBlockingEndPoint(float pTimestep) 1229 public bool ComputeLinearBlockingEndPoint(float pTimestep)
@@ -1024,7 +1263,7 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1024 { 1263 {
1025 VehiclePosition = pos; 1264 VehiclePosition = pos;
1026 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1265 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1027 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1266 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1028 } 1267 }
1029 } 1268 }
1030 return changed; 1269 return changed;
@@ -1035,34 +1274,75 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1035 // used with conjunction with banking: the strength of the banking will decay when the 1274 // used with conjunction with banking: the strength of the banking will decay when the
1036 // vehicle no longer experiences collisions. The decay timescale is the same as 1275 // vehicle no longer experiences collisions. The decay timescale is the same as
1037 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1276 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1038 // when they are in mid jump. 1277 // when they are in mid jump.
1039 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1278 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1040 // This is just using the ground and a general collision check. Should really be using 1279 // This is just using the ground and a general collision check. Should really be using
1041 // a downward raycast to find what is below. 1280 // a downward raycast to find what is below.
1042 public Vector3 ComputeLinearMotorUp(float pTimestep) 1281 public void ComputeLinearMotorUp(float pTimestep)
1043 { 1282 {
1044 Vector3 ret = Vector3.Zero;
1045 float distanceAboveGround = 0f;
1046
1047 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1283 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1048 { 1284 {
1285 // This code tries to decide if the object is not on the ground and then pushing down
1286 /*
1049 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); 1287 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1050 distanceAboveGround = VehiclePosition.Z - targetHeight; 1288 distanceAboveGround = VehiclePosition.Z - targetHeight;
1051 // Not colliding if the vehicle is off the ground 1289 // Not colliding if the vehicle is off the ground
1052 if (!Prim.IsColliding) 1290 if (!Prim.HasSomeCollision)
1053 { 1291 {
1054 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1292 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1055 ret = new Vector3(0, 0, -distanceAboveGround); 1293 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
1056 } 1294 }
1057 // TODO: this calculation is wrong. From the description at 1295 // TODO: this calculation is wrong. From the description at
1058 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1296 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1059 // has a decay factor. This says this force should 1297 // has a decay factor. This says this force should
1060 // be computed with a motor. 1298 // be computed with a motor.
1061 // TODO: add interaction with banking. 1299 // TODO: add interaction with banking.
1300 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1301 Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
1302 */
1303
1304 // Another approach is to measure if we're going up. If going up and not colliding,
1305 // the vehicle is in the air. Fix that by pushing down.
1306 if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
1307 {
1308 // Get rid of any of the velocity vector that is pushing us up.
1309 float upVelocity = VehicleVelocity.Z;
1310 VehicleVelocity += new Vector3(0, 0, -upVelocity);
1311
1312 /*
1313 // If we're pointed up into the air, we should nose down
1314 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1315 // The rotation around the Y axis is pitch up or down
1316 if (pointingDirection.Y > 0.01f)
1317 {
1318 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1319 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1320 // Rotate into world coordinates and apply to vehicle
1321 angularCorrectionVector *= VehicleOrientation;
1322 VehicleAddAngularForce(angularCorrectionVector);
1323 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1324 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1325 }
1326 */
1327 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1328 ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
1329 }
1062 } 1330 }
1063 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", 1331 }
1064 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); 1332
1065 return ret; 1333 private void ApplyGravity(float pTimeStep)
1334 {
1335 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1336
1337 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1338 if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
1339 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1340
1341 VehicleAddForce(appliedGravity);
1342
1343 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
1344 ControllingPrim.LocalID, m_VehicleGravity,
1345 ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1066 } 1346 }
1067 1347
1068 // ======================================================================= 1348 // =======================================================================
@@ -1073,55 +1353,24 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1073 // set directly on the vehicle. 1353 // set directly on the vehicle.
1074 private void MoveAngular(float pTimestep) 1354 private void MoveAngular(float pTimestep)
1075 { 1355 {
1076 // The user wants this many radians per second angular change? 1356 ComputeAngularTurning(pTimestep);
1077 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1078
1079 // ==================================================================
1080 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1081 // This flag prevents linear deflection parallel to world z-axis. This is useful
1082 // for preventing ground vehicles with large linear deflection, like bumper cars,
1083 // from climbing their linear deflection into the sky.
1084 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1085 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1086 {
1087 angularMotorContribution.X = 0f;
1088 angularMotorContribution.Y = 0f;
1089 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1090 }
1091
1092 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1093 1357
1094 Vector3 deflectionContribution = ComputeAngularDeflection(); 1358 ComputeAngularVerticalAttraction();
1095 1359
1096 Vector3 bankingContribution = ComputeAngularBanking(); 1360 ComputeAngularDeflection();
1097 1361
1098 // ================================================================== 1362 ComputeAngularBanking();
1099 m_lastVertAttractor = verticalAttractionContribution;
1100
1101 m_lastAngularVelocity = angularMotorContribution
1102 + verticalAttractionContribution
1103 + deflectionContribution
1104 + bankingContribution;
1105 1363
1106 // ================================================================== 1364 // ==================================================================
1107 // Apply the correction velocity. 1365 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
1108 // TODO: Should this be applied as an angular force (torque)?
1109 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1110 { 1366 {
1111 VehicleRotationalVelocity = m_lastAngularVelocity; 1367 // The vehicle is not adding anything angular wise.
1112 1368 VehicleRotationalVelocity = Vector3.Zero;
1113 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", 1369 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1114 Prim.LocalID,
1115 angularMotorContribution, verticalAttractionContribution,
1116 bankingContribution, deflectionContribution,
1117 m_lastAngularVelocity
1118 );
1119 } 1370 }
1120 else 1371 else
1121 { 1372 {
1122 // The vehicle is not adding anything angular wise. 1373 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1123 VehicleRotationalVelocity = Vector3.Zero;
1124 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1125 } 1374 }
1126 1375
1127 // ================================================================== 1376 // ==================================================================
@@ -1152,10 +1401,43 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1152 torqueFromOffset.Z = 0; 1401 torqueFromOffset.Z = 0;
1153 1402
1154 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); 1403 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1155 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1404 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1156 } 1405 }
1157 1406
1158 } 1407 }
1408
1409 private void ComputeAngularTurning(float pTimestep)
1410 {
1411 // The user wants this many radians per second angular change?
1412 Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
1413 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation);
1414 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1415
1416 // ==================================================================
1417 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1418 // This flag prevents linear deflection parallel to world z-axis. This is useful
1419 // for preventing ground vehicles with large linear deflection, like bumper cars,
1420 // from climbing their linear deflection into the sky.
1421 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1422 // TODO: This is here because this is where ODE put it but documentation says it
1423 // is a linear effect. Where should this check go?
1424 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1425 // {
1426 // angularMotorContributionV.X = 0f;
1427 // angularMotorContributionV.Y = 0f;
1428 // }
1429
1430 // Reduce any velocity by friction.
1431 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1432 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1433
1434 Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation;
1435 VehicleRotationalVelocity += angularMotorContributionW;
1436
1437 VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
1438 ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
1439 }
1440
1159 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1441 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1160 // Some vehicles, like boats, should always keep their up-side up. This can be done by 1442 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1161 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to 1443 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
@@ -1164,77 +1446,183 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1164 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An 1446 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1165 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an 1447 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1166 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1448 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1167 public Vector3 ComputeAngularVerticalAttraction() 1449 public void ComputeAngularVerticalAttraction()
1168 { 1450 {
1169 Vector3 ret = Vector3.Zero;
1170 1451
1171 // If vertical attaction timescale is reasonable 1452 // If vertical attaction timescale is reasonable
1172 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1453 if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1173 { 1454 {
1174 // Take a vector pointing up and convert it from world to vehicle relative coords. 1455 Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation;
1175 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1456 switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
1176
1177 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1178 // is now:
1179 // leaning to one side: rotated around the X axis with the Y value going
1180 // from zero (nearly straight up) to one (completely to the side)) or
1181 // leaning front-to-back: rotated around the Y axis with the value of X being between
1182 // zero and one.
1183 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1184
1185 // Y error means needed rotation around X axis and visa versa.
1186 // Since the error goes from zero to one, the asin is the corresponding angle.
1187 ret.X = (float)Math.Asin(verticalError.Y);
1188 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1189 ret.Y = -(float)Math.Asin(verticalError.X);
1190
1191 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1192 if (verticalError.Z < 0f)
1193 { 1457 {
1194 ret.X += PIOverFour; 1458 case 0:
1195 ret.Y += PIOverFour; 1459 {
1460 //Another formula to try got from :
1461 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1462
1463 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1464 // since only computing half the distance between the angles.
1465 float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1466
1467 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1468 // this makes for a smoother adjustment and less fighting between the various forces.
1469 Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1470
1471 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1472 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1473
1474 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0)
1475 {
1476 Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation;
1477 torqueVector = ProjectVector(torqueVector, vehicleForwardAxis);
1478 }
1479
1480 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1481 Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
1482
1483 VehicleRotationalVelocity += vertContributionV;
1484
1485 VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
1486 ControllingPrim.LocalID,
1487 verticalAttractionSpeed,
1488 vehicleUpAxis,
1489 predictedUp,
1490 torqueVector,
1491 vertContributionV);
1492 break;
1493 }
1494 case 1:
1495 {
1496 // Possible solution derived from a discussion at:
1497 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1498
1499 // Create a rotation that is only the vehicle's rotation around Z
1500 Vector3 currentEulerW = Vector3.Zero;
1501 VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
1502 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
1503
1504 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1505 Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation);
1506 // Compute the angle between those to vectors.
1507 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation)));
1508 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1509
1510 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1511 // TODO: add 'efficiency'.
1512 // differenceAngle /= m_verticalAttractionTimescale;
1513
1514 // Create the quaterian representing the correction angle
1515 Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
1516
1517 // Turn that quaternion into Euler values to make it into velocities to apply.
1518 Vector3 vertContributionW = Vector3.Zero;
1519 correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
1520 vertContributionW *= -1f;
1521 vertContributionW /= m_verticalAttractionTimescale;
1522
1523 VehicleRotationalVelocity += vertContributionW;
1524
1525 VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
1526 ControllingPrim.LocalID,
1527 vehicleUpAxis,
1528 differenceAxisW,
1529 differenceAngle,
1530 correctionRotationW,
1531 vertContributionW);
1532 break;
1533 }
1534 case 2:
1535 {
1536 Vector3 vertContributionV = Vector3.Zero;
1537 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1538
1539 // Take a vector pointing up and convert it from world to vehicle relative coords.
1540 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation);
1541
1542 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1543 // is now:
1544 // leaning to one side: rotated around the X axis with the Y value going
1545 // from zero (nearly straight up) to one (completely to the side)) or
1546 // leaning front-to-back: rotated around the Y axis with the value of X being between
1547 // zero and one.
1548 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1549
1550 // Y error means needed rotation around X axis and visa versa.
1551 // Since the error goes from zero to one, the asin is the corresponding angle.
1552 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1553 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1554 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1555
1556 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1557 if (verticalError.Z < 0f)
1558 {
1559 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1560 // vertContribution.Y -= PIOverFour;
1561 }
1562
1563 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1564 // Correction happens over a number of seconds.
1565 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1566
1567 // The correction happens over the user's time period
1568 vertContributionV /= m_verticalAttractionTimescale;
1569
1570 // Rotate the vehicle rotation to the world coordinates.
1571 VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation);
1572
1573 VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
1574 ControllingPrim.LocalID,
1575 vehicleUpAxis,
1576 origRotVelW,
1577 verticalError,
1578 unscaledContribVerticalErrorV,
1579 m_verticalAttractionEfficiency,
1580 m_verticalAttractionTimescale,
1581 vertContributionV);
1582 break;
1583 }
1584 default:
1585 {
1586 break;
1587 }
1196 } 1588 }
1197
1198 // 'ret' is now the necessary velocity to correct tilt in one second.
1199 // Correction happens over a number of seconds.
1200 Vector3 unscaledContrib = ret;
1201 ret /= m_verticalAttractionTimescale;
1202
1203 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1204 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1205 } 1589 }
1206 return ret;
1207 } 1590 }
1208 1591
1209 // Return the angular correction to correct the direction the vehicle is pointing to be 1592 // Angular correction to correct the direction the vehicle is pointing to be
1210 // the direction is should want to be pointing. 1593 // the direction is should want to be pointing.
1211 // The vehicle is moving in some direction and correct its orientation to it is pointing 1594 // The vehicle is moving in some direction and correct its orientation to it is pointing
1212 // in that direction. 1595 // in that direction.
1213 // TODO: implement reference frame. 1596 // TODO: implement reference frame.
1214 public Vector3 ComputeAngularDeflection() 1597 public void ComputeAngularDeflection()
1215 { 1598 {
1216 Vector3 ret = Vector3.Zero; 1599
1217 return ret; // DEBUG DEBUG DEBUG 1600 if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1218 // Disable angular deflection for the moment.
1219 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1220 // approximately the same X or Y correction. When added together (when contributions are combined)
1221 // this creates an over-correction and then wabbling as the target is overshot.
1222 // TODO: rethink how the different correction computations inter-relate.
1223
1224 if (m_angularDeflectionEfficiency != 0)
1225 { 1601 {
1602 Vector3 deflectContributionV = Vector3.Zero;
1603
1226 // The direction the vehicle is moving 1604 // The direction the vehicle is moving
1227 Vector3 movingDirection = VehicleVelocity; 1605 Vector3 movingDirection = VehicleVelocity;
1228 movingDirection.Normalize(); 1606 movingDirection.Normalize();
1229 1607
1608 // If the vehicle is going backward, it is still pointing forward
1609 movingDirection *= Math.Sign(VehicleForwardSpeed);
1610
1230 // The direction the vehicle is pointing 1611 // The direction the vehicle is pointing
1231 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; 1612 Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation;
1232 pointingDirection.Normalize(); 1613 //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
1614 // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
1615 Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1616 predictedPointingDirection.Normalize();
1233 1617
1234 // The difference between what is and what should be. 1618 // The difference between what is and what should be.
1235 Vector3 deflectionError = movingDirection - pointingDirection; 1619 // Vector3 deflectionError = movingDirection - predictedPointingDirection;
1620 Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
1236 1621
1237 // Don't try to correct very large errors (not our job) 1622 // Don't try to correct very large errors (not our job)
1623 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1624 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1625 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1238 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; 1626 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1239 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; 1627 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1240 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; 1628 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
@@ -1242,18 +1630,19 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1242 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); 1630 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1243 1631
1244 // Scale the correction by recovery timescale and efficiency 1632 // Scale the correction by recovery timescale and efficiency
1245 ret = (-deflectionError) * m_angularDeflectionEfficiency; 1633 // Not modeling a spring so clamp the scale to no more then the arc
1246 ret /= m_angularDeflectionTimescale; 1634 deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
1635 //deflectContributionV /= m_angularDeflectionTimescale;
1247 1636
1637 VehicleRotationalVelocity += deflectContributionV;
1248 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1638 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1249 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); 1639 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1250 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1640 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
1251 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1641 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
1252 } 1642 }
1253 return ret;
1254 } 1643 }
1255 1644
1256 // Return an angular change to rotate the vehicle around the Z axis when the vehicle 1645 // Angular change to rotate the vehicle around the Z axis when the vehicle
1257 // is tipped around the X axis. 1646 // is tipped around the X axis.
1258 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1647 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1259 // The vertical attractor feature must be enabled in order for the banking behavior to 1648 // The vertical attractor feature must be enabled in order for the banking behavior to
@@ -1261,13 +1650,13 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1261 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1650 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1262 // of the yaw effect will be proportional to the 1651 // of the yaw effect will be proportional to the
1263 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1652 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1264 // velocity along its preferred axis of motion. 1653 // velocity along its preferred axis of motion.
1265 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1654 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1266 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1655 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1267 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1656 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1268 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1657 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1269 // Negating the banking coefficient will make it so that the vehicle leans to the 1658 // Negating the banking coefficient will make it so that the vehicle leans to the
1270 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1659 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1271 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1660 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1272 // banking vehicles do what you want rather than what the laws of physics allow. 1661 // banking vehicles do what you want rather than what the laws of physics allow.
1273 // For example, consider a real motorcycle...it must be moving forward in order for 1662 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1279,46 +1668,43 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1279 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1668 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1280 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1669 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1281 // to "dynamic" where the banking is also proportional to its velocity along its 1670 // to "dynamic" where the banking is also proportional to its velocity along its
1282 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1671 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1283 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1672 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1284 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1673 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1285 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1674 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1286 // make a sluggish vehicle by giving it a timescale of several seconds. 1675 // make a sluggish vehicle by giving it a timescale of several seconds.
1287 public Vector3 ComputeAngularBanking() 1676 public void ComputeAngularBanking()
1288 { 1677 {
1289 Vector3 ret = Vector3.Zero; 1678 if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1290
1291 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1292 { 1679 {
1293 // This works by rotating a unit vector to the orientation of the vehicle. The 1680 Vector3 bankingContributionV = Vector3.Zero;
1294 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1295 // up to one for full over).
1296 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1297 1681
1298 // Figure out the yaw value for this much roll. 1682 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1299 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; 1683 // As the vehicle rolls to the right or left, the Y value will increase from
1300 // Keep the sign 1684 // zero (straight up) to 1 or -1 (full tilt right or left)
1301 if (rollComponents.Y < 0f) 1685 Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation;
1302 turnComponent = -turnComponent;
1303
1304 // TODO: there must be a better computation of the banking force.
1305 float bankingTurnForce = turnComponent;
1306 1686
1687 // Figure out the yaw value for this much roll.
1688 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1307 // actual error = static turn error + dynamic turn error 1689 // actual error = static turn error + dynamic turn error
1308 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; 1690 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1691
1309 // TODO: the banking effect should not go to infinity but what to limit it to? 1692 // TODO: the banking effect should not go to infinity but what to limit it to?
1310 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); 1693 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1694 mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI);
1311 1695
1312 // Build the force vector to change rotation from what it is to what it should be 1696 // Build the force vector to change rotation from what it is to what it should be
1313 ret.Z = -mixedBankingError; 1697 bankingContributionV.Z = -mixedYawAngle;
1698
1699 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1700 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1701
1702 VehicleRotationalVelocity += bankingContributionV;
1314 1703
1315 // Don't do it all at once.
1316 ret /= m_bankingTimescale;
1317 1704
1318 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", 1705 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1319 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); 1706 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1320 } 1707 }
1321 return ret;
1322 } 1708 }
1323 1709
1324 // This is from previous instantiations of XXXDynamics.cs. 1710 // This is from previous instantiations of XXXDynamics.cs.
@@ -1356,8 +1742,45 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1356 if (rotq != m_rot) 1742 if (rotq != m_rot)
1357 { 1743 {
1358 VehicleOrientation = m_rot; 1744 VehicleOrientation = m_rot;
1359 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1745 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1746 }
1747
1748 }
1749
1750 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1751 // some value by to apply this friction.
1752 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1753 {
1754 Vector3 frictionFactor = Vector3.Zero;
1755 if (friction != BSMotor.InfiniteVector)
1756 {
1757 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1758 // Individual friction components can be 'infinite' so compute each separately.
1759 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1760 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1761 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1762 frictionFactor *= pTimestep;
1763 }
1764 return frictionFactor;
1765 }
1766
1767 private float SortedClampInRange(float clampa, float val, float clampb)
1768 {
1769 if (clampa > clampb)
1770 {
1771 float temp = clampa;
1772 clampa = clampb;
1773 clampb = temp;
1360 } 1774 }
1775 return ClampInRange(clampa, val, clampb);
1776
1777 }
1778
1779 //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit.
1780 private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal)
1781 {
1782 float vectorDot = Vector3.Dot(vector, onNormal);
1783 return onNormal * vectorDot;
1361 1784
1362 } 1785 }
1363 1786
@@ -1370,8 +1793,8 @@ namespace OpenSim.Region.Physics.BulletSNPlugin
1370 // Invoke the detailed logger and output something if it's enabled. 1793 // Invoke the detailed logger and output something if it's enabled.
1371 private void VDetailLog(string msg, params Object[] args) 1794 private void VDetailLog(string msg, params Object[] args)
1372 { 1795 {
1373 if (Prim.PhysicsScene.VehicleLoggingEnabled) 1796 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1374 Prim.PhysicsScene.DetailLog(msg, args); 1797 ControllingPrim.PhysScene.DetailLog(msg, args);
1375 } 1798 }
1376 } 1799 }
1377} 1800}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
new file mode 100755
index 0000000..8312239
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
@@ -0,0 +1,503 @@
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
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.PhysicsModule.BulletS
34{
35
36public abstract class BSLinkset
37{
38 // private static string LogHeader = "[BULLETSIM LINKSET]";
39
40 public enum LinksetImplementation
41 {
42 Constraint = 0, // linkset tied together with constraints
43 Compound = 1, // linkset tied together as a compound object
44 Manual = 2 // linkset tied together manually (code moves all the pieces)
45 }
46 // Create the correct type of linkset for this child
47 public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
48 {
49 BSLinkset ret = null;
50
51 switch (parent.LinksetType)
52 {
53 case LinksetImplementation.Constraint:
54 ret = new BSLinksetConstraints(physScene, parent);
55 break;
56 case LinksetImplementation.Compound:
57 ret = new BSLinksetCompound(physScene, parent);
58 break;
59 case LinksetImplementation.Manual:
60 // ret = new BSLinksetManual(physScene, parent);
61 break;
62 default:
63 ret = new BSLinksetCompound(physScene, parent);
64 break;
65 }
66 if (ret == null)
67 {
68 physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
69 }
70 return ret;
71 }
72
73 public class BSLinkInfo
74 {
75 public BSPrimLinkable member;
76 public BSLinkInfo(BSPrimLinkable pMember)
77 {
78 member = pMember;
79 }
80 public virtual void ResetLink() { }
81 public virtual void SetLinkParameters(BSConstraint constrain) { }
82 // Returns 'true' if physical property updates from the child should be reported to the simulator
83 public virtual bool ShouldUpdateChildProperties() { return false; }
84 }
85
86 public LinksetImplementation LinksetImpl { get; protected set; }
87
88 public BSPrimLinkable LinksetRoot { get; protected set; }
89
90 protected BSScene m_physicsScene { get; private set; }
91
92 static int m_nextLinksetID = 1;
93 public int LinksetID { get; private set; }
94
95 // The children under the root in this linkset.
96 // protected HashSet<BSPrimLinkable> m_children;
97 protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
98
99 // We lock the diddling of linkset classes to prevent any badness.
100 // This locks the modification of the instances of this class. Changes
101 // to the physical representation is done via the tainting mechenism.
102 protected object m_linksetActivityLock = new Object();
103
104 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
105 public float LinksetMass { get; protected set; }
106
107 public virtual bool LinksetIsColliding { get { return false; } }
108
109 public OMV.Vector3 CenterOfMass
110 {
111 get { return ComputeLinksetCenterOfMass(); }
112 }
113
114 public OMV.Vector3 GeometricCenter
115 {
116 get { return ComputeLinksetGeometricCenter(); }
117 }
118
119 protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120 {
121 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++;
123 // We create LOTS of linksets.
124 if (m_nextLinksetID <= 0)
125 m_nextLinksetID = 1;
126 m_physicsScene = scene;
127 LinksetRoot = parent;
128 m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
129 LinksetMass = parent.RawMass;
130 Rebuilding = false;
131 RebuildScheduled = false;
132
133 parent.ClearDisplacement();
134 }
135
136 // Link to a linkset where the child knows the parent.
137 // Parent changing should not happen so do some sanity checking.
138 // We return the parent's linkset so the child can track its membership.
139 // Called at runtime.
140 public BSLinkset AddMeToLinkset(BSPrimLinkable child)
141 {
142 lock (m_linksetActivityLock)
143 {
144 // Don't add the root to its own linkset
145 if (!IsRoot(child))
146 AddChildToLinkset(child);
147 LinksetMass = ComputeLinksetMass();
148 }
149 return this;
150 }
151
152 // Remove a child from a linkset.
153 // Returns a new linkset for the child which is a linkset of one (just the
154 // orphened child).
155 // Called at runtime.
156 public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
157 {
158 lock (m_linksetActivityLock)
159 {
160 if (IsRoot(child))
161 {
162 // Cannot remove the root from a linkset.
163 return this;
164 }
165 RemoveChildFromLinkset(child, inTaintTime);
166 LinksetMass = ComputeLinksetMass();
167 }
168
169 // The child is down to a linkset of just itself
170 return BSLinkset.Factory(m_physicsScene, child);
171 }
172
173 // Return 'true' if the passed object is the root object of this linkset
174 public bool IsRoot(BSPrimLinkable requestor)
175 {
176 return (requestor.LocalID == LinksetRoot.LocalID);
177 }
178
179 public int NumberOfChildren { get { return m_children.Count; } }
180
181 // Return 'true' if this linkset has any children (more than the root member)
182 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
183
184 // Return 'true' if this child is in this linkset
185 public bool HasChild(BSPrimLinkable child)
186 {
187 bool ret = false;
188 lock (m_linksetActivityLock)
189 {
190 ret = m_children.ContainsKey(child);
191 }
192 return ret;
193 }
194
195 // Perform an action on each member of the linkset including root prim.
196 // Depends on the action on whether this should be done at taint time.
197 public delegate bool ForEachMemberAction(BSPrimLinkable obj);
198 public virtual bool ForEachMember(ForEachMemberAction action)
199 {
200 bool ret = false;
201 lock (m_linksetActivityLock)
202 {
203 action(LinksetRoot);
204 foreach (BSPrimLinkable po in m_children.Keys)
205 {
206 if (action(po))
207 break;
208 }
209 }
210 return ret;
211 }
212
213 public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
214 {
215 bool ret = false;
216 BSLinkInfo found = null;
217 lock (m_linksetActivityLock)
218 {
219 ret = m_children.TryGetValue(child, out found);
220 }
221 foundInfo = found;
222 return ret;
223 }
224 // Perform an action on each member of the linkset including root prim.
225 // Depends on the action on whether this should be done at taint time.
226 public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
227 public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
228 {
229 bool ret = false;
230 lock (m_linksetActivityLock)
231 {
232 foreach (BSLinkInfo po in m_children.Values)
233 {
234 if (action(po))
235 break;
236 }
237 }
238 return ret;
239 }
240
241 // Check the type of the link and return 'true' if the link is flexible and the
242 // updates from the child should be sent to the simulator so things change.
243 public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
244 {
245 bool ret = false;
246
247 BSLinkInfo linkInfo;
248 if (m_children.TryGetValue(child, out linkInfo))
249 {
250 ret = linkInfo.ShouldUpdateChildProperties();
251 }
252
253 return ret;
254 }
255
256 // Called after a simulation step to post a collision with this object.
257 // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
258 // anything to add for the collision and it should be passed through normal processing.
259 // Default processing for a linkset.
260 public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
261 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
262 {
263 bool ret = false;
264
265 // prims in the same linkset cannot collide with each other
266 BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
267 if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
268 {
269 // By returning 'true', we tell the caller the collision has been 'handled' so it won't
270 // do anything about this collision and thus, effectivily, ignoring the collision.
271 ret = true;
272 }
273 else
274 {
275 // Not a collision between members of the linkset. Must be a real collision.
276 // So the linkset root can know if there is a collision anywhere in the linkset.
277 LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
278 }
279
280 return ret;
281 }
282
283 // I am the root of a linkset and a new child is being added
284 // Called while LinkActivity is locked.
285 protected abstract void AddChildToLinkset(BSPrimLinkable child);
286
287 // I am the root of a linkset and one of my children is being removed.
288 // Safe to call even if the child is not really in my linkset.
289 protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
290
291 // When physical properties are changed the linkset needs to recalculate
292 // its internal properties.
293 // May be called at runtime or taint-time.
294 public virtual void Refresh(BSPrimLinkable requestor)
295 {
296 LinksetMass = ComputeLinksetMass();
297 }
298
299 // Flag denoting the linkset is in the process of being rebuilt.
300 // Used to know not the schedule a rebuild in the middle of a rebuild.
301 // Because of potential update calls that could want to schedule another rebuild.
302 protected bool Rebuilding { get; set; }
303
304 // Flag saying a linkset rebuild has been scheduled.
305 // This is turned on when the rebuild is requested and turned off when
306 // the rebuild is complete. Used to limit modifications to the
307 // linkset parameters while the linkset is in an intermediate state.
308 // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
309 public bool RebuildScheduled { get; protected set; }
310
311 // The object is going dynamic (physical). Do any setup necessary
312 // for a dynamic linkset.
313 // Only the state of the passed object can be modified. The rest of the linkset
314 // has not yet been fully constructed.
315 // Return 'true' if any properties updated on the passed object.
316 // Called at taint-time!
317 public abstract bool MakeDynamic(BSPrimLinkable child);
318
319 public virtual bool AllPartsComplete
320 {
321 get {
322 bool ret = true;
323 this.ForEachMember((member) =>
324 {
325 if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
326 {
327 ret = false;
328 return true; // exit loop
329 }
330 return false; // continue loop
331 });
332 return ret;
333 }
334 }
335
336 // The object is going static (non-physical). Do any setup necessary
337 // for a static linkset.
338 // Return 'true' if any properties updated on the passed object.
339 // Called at taint-time!
340 public abstract bool MakeStatic(BSPrimLinkable child);
341
342 // Called when a parameter update comes from the physics engine for any object
343 // of the linkset is received.
344 // Passed flag is update came from physics engine (true) or the user (false).
345 // Called at taint-time!!
346 public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
347
348 // Routine used when rebuilding the body of the root of the linkset
349 // Destroy all the constraints have have been made to root.
350 // This is called when the root body is changing.
351 // Returns 'true' of something was actually removed and would need restoring
352 // Called at taint-time!!
353 public abstract bool RemoveDependencies(BSPrimLinkable child);
354
355 // ================================================================
356 // Some physical setting happen to all members of the linkset
357 public virtual void SetPhysicalFriction(float friction)
358 {
359 ForEachMember((member) =>
360 {
361 if (member.PhysBody.HasPhysicalBody)
362 m_physicsScene.PE.SetFriction(member.PhysBody, friction);
363 return false; // 'false' says to continue looping
364 }
365 );
366 }
367 public virtual void SetPhysicalRestitution(float restitution)
368 {
369 ForEachMember((member) =>
370 {
371 if (member.PhysBody.HasPhysicalBody)
372 m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
373 return false; // 'false' says to continue looping
374 }
375 );
376 }
377 public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
378 {
379 ForEachMember((member) =>
380 {
381 if (member.PhysBody.HasPhysicalBody)
382 m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
383 return false; // 'false' says to continue looping
384 }
385 );
386 }
387 public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
388 {
389 ForEachMember((member) =>
390 {
391 if (member.PhysBody.HasPhysicalBody)
392 {
393 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
394 member.Inertia = inertia * inertiaFactor;
395 m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
396 m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
397 DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
398
399 }
400 return false; // 'false' says to continue looping
401 }
402 );
403 }
404 public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
405 {
406 ForEachMember((member) =>
407 {
408 if (member.PhysBody.HasPhysicalBody)
409 m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
410 return false; // 'false' says to continue looping
411 }
412 );
413 }
414 public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
415 {
416 ForEachMember((member) =>
417 {
418 if (member.PhysBody.HasPhysicalBody)
419 m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
420 return false; // 'false' says to continue looping
421 }
422 );
423 }
424 public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
425 {
426 ForEachMember((member) =>
427 {
428 if (member.PhysBody.HasPhysicalBody)
429 m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
430 return false; // 'false' says to continue looping
431 }
432 );
433 }
434 // ================================================================
435 protected virtual float ComputeLinksetMass()
436 {
437 float mass = LinksetRoot.RawMass;
438 if (HasAnyChildren)
439 {
440 lock (m_linksetActivityLock)
441 {
442 foreach (BSPrimLinkable bp in m_children.Keys)
443 {
444 mass += bp.RawMass;
445 }
446 }
447 }
448 return mass;
449 }
450
451 // Computes linkset's center of mass in world coordinates.
452 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
453 {
454 OMV.Vector3 com;
455 lock (m_linksetActivityLock)
456 {
457 com = LinksetRoot.Position * LinksetRoot.RawMass;
458 float totalMass = LinksetRoot.RawMass;
459
460 foreach (BSPrimLinkable bp in m_children.Keys)
461 {
462 com += bp.Position * bp.RawMass;
463 totalMass += bp.RawMass;
464 }
465 if (totalMass != 0f)
466 com /= totalMass;
467 }
468
469 return com;
470 }
471
472 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
473 {
474 OMV.Vector3 com;
475 lock (m_linksetActivityLock)
476 {
477 com = LinksetRoot.Position;
478
479 foreach (BSPrimLinkable bp in m_children.Keys)
480 {
481 com += bp.Position;
482 }
483 com /= (m_children.Count + 1);
484 }
485
486 return com;
487 }
488
489 #region Extension
490 public virtual object Extension(string pFunct, params object[] pParams)
491 {
492 return null;
493 }
494 #endregion // Extension
495
496 // Invoke the detailed logger and output something if it's enabled.
497 protected void DetailLog(string msg, params Object[] args)
498 {
499 if (m_physicsScene.PhysicsLogging.Enabled)
500 m_physicsScene.DetailLog(msg, args);
501 }
502}
503}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
new file mode 100755
index 0000000..953ddee
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
@@ -0,0 +1,477 @@
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
31using OpenSim.Framework;
32
33using OMV = OpenMetaverse;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37
38public sealed class BSLinksetCompound : BSLinkset
39{
40#pragma warning disable 414
41 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
42#pragma warning restore 414
43
44 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
45 : base(scene, parent)
46 {
47 LinksetImpl = LinksetImplementation.Compound;
48 }
49
50 // ================================================================
51 // Changing the physical property of the linkset only needs to change the root
52 public override void SetPhysicalFriction(float friction)
53 {
54 if (LinksetRoot.PhysBody.HasPhysicalBody)
55 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
56 }
57 public override void SetPhysicalRestitution(float restitution)
58 {
59 if (LinksetRoot.PhysBody.HasPhysicalBody)
60 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
61 }
62 public override void SetPhysicalGravity(OMV.Vector3 gravity)
63 {
64 if (LinksetRoot.PhysBody.HasPhysicalBody)
65 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
66 }
67 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
68 {
69 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
70 LinksetRoot.Inertia = inertia * inertiaFactor;
71 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
72 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
73 }
74 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
75 {
76 if (LinksetRoot.PhysBody.HasPhysicalBody)
77 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
78 }
79 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
80 {
81 if (LinksetRoot.PhysBody.HasPhysicalBody)
82 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
83 }
84 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
85 {
86 if (LinksetRoot.PhysBody.HasPhysicalBody)
87 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
88 }
89 // ================================================================
90
91 // When physical properties are changed the linkset needs to recalculate
92 // its internal properties.
93 public override void Refresh(BSPrimLinkable requestor)
94 {
95 // Something changed so do the rebuilding thing
96 ScheduleRebuild(requestor);
97 base.Refresh(requestor);
98 }
99
100 // Schedule a refresh to happen after all the other taint processing.
101 private void ScheduleRebuild(BSPrimLinkable requestor)
102 {
103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // 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.
106 lock (m_linksetActivityLock)
107 {
108 if (!RebuildScheduled && !Rebuilding && HasAnyChildren)
109 {
110 InternalScheduleRebuild(requestor);
111 }
112 }
113 }
114
115 // Must be called with m_linksetActivityLock or race conditions will haunt you.
116 private void InternalScheduleRebuild(BSPrimLinkable requestor)
117 {
118 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}",
119 requestor.LocalID, Rebuilding, HasAnyChildren);
120 RebuildScheduled = true;
121 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
122 {
123 if (HasAnyChildren)
124 {
125 if (this.AllPartsComplete)
126 {
127 RecomputeLinksetCompound();
128 }
129 else
130 {
131 DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete",
132 requestor.LocalID);
133 InternalScheduleRebuild(requestor);
134 }
135 }
136 RebuildScheduled = false;
137 });
138 }
139
140 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
141 // Only the state of the passed object can be modified. The rest of the linkset
142 // has not yet been fully constructed.
143 // Return 'true' if any properties updated on the passed object.
144 // Called at taint-time!
145 public override bool MakeDynamic(BSPrimLinkable child)
146 {
147 bool ret = false;
148 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
149 if (IsRoot(child))
150 {
151 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
152 Refresh(LinksetRoot);
153 }
154 return ret;
155 }
156
157 // The object is going static (non-physical). We do not do anything for static linksets.
158 // Return 'true' if any properties updated on the passed object.
159 // Called at taint-time!
160 public override bool MakeStatic(BSPrimLinkable child)
161 {
162 bool ret = false;
163
164 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
165 child.ClearDisplacement();
166 if (IsRoot(child))
167 {
168 // Schedule a rebuild to verify that the root shape is set to the real shape.
169 Refresh(LinksetRoot);
170 }
171 return ret;
172 }
173
174 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
175 // Called at taint-time.
176 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
177 {
178 if (!LinksetRoot.IsPhysicallyActive)
179 {
180 // No reason to do this physical stuff for static linksets.
181 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
182 return;
183 }
184
185 // The user moving a child around requires the rebuilding of the linkset compound shape
186 // One problem is this happens when a border is crossed -- the simulator implementation
187 // stores the position into the group which causes the move of the object
188 // but it also means all the child positions get updated.
189 // What would cause an unnecessary rebuild so we make sure the linkset is in a
190 // region before bothering to do a rebuild.
191 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
192 {
193 // If a child of the linkset is updating only the position or rotation, that can be done
194 // without rebuilding the linkset.
195 // If a handle for the child can be fetch, we update the child here. If a rebuild was
196 // scheduled by someone else, the rebuild will just replace this setting.
197
198 bool updatedChild = false;
199 // Anything other than updating position or orientation usually means a physical update
200 // and that is caused by us updating the object.
201 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
202 {
203 // Find the physical instance of the child
204 if (!RebuildScheduled // if rebuilding, let the rebuild do it
205 && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change
206 && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned
207 && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
208 {
209 // It is possible that the linkset is still under construction and the child is not yet
210 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
211 // build the whole thing with the new position or rotation.
212 // The index must be checked because Bullet references the child array but does no validity
213 // checking of the child index passed.
214 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
215 if (updated.LinksetChildIndex < numLinksetChildren)
216 {
217 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
218 if (linksetChildShape.HasPhysicalShape)
219 {
220 // Found the child shape within the compound shape
221 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
222 updated.RawPosition - LinksetRoot.RawPosition,
223 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
224 true /* shouldRecalculateLocalAabb */);
225 updatedChild = true;
226 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
227 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
228 }
229 else // DEBUG DEBUG
230 { // DEBUG DEBUG
231 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
232 updated.LocalID, linksetChildShape);
233 } // DEBUG DEBUG
234 }
235 else // DEBUG DEBUG
236 { // DEBUG DEBUG
237 // the child is not yet in the compound shape. This is non-fatal.
238 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
239 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
240 } // DEBUG DEBUG
241 }
242 else // DEBUG DEBUG
243 { // DEBUG DEBUG
244 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
245 } // DEBUG DEBUG
246
247 if (!updatedChild)
248 {
249 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
250 // Note: there are several ways through this code that will not update the child if
251 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
252 // there will already be a rebuild scheduled.
253 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
254 updated.LocalID, whichUpdated);
255 Refresh(updated);
256 }
257 }
258 }
259 }
260
261 // Routine called when rebuilding the body of some member of the linkset.
262 // If one of the bodies is being changed, the linkset needs rebuilding.
263 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
264 // Returns 'true' of something was actually removed and would need restoring
265 // Called at taint-time!!
266 public override bool RemoveDependencies(BSPrimLinkable child)
267 {
268 bool ret = false;
269
270 DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
271 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
272
273 Refresh(child);
274
275 return ret;
276 }
277
278 // ================================================================
279
280 // Add a new child to the linkset.
281 // Called while LinkActivity is locked.
282 protected override void AddChildToLinkset(BSPrimLinkable child)
283 {
284 if (!HasChild(child))
285 {
286 m_children.Add(child, new BSLinkInfo(child));
287
288 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
289
290 // Rebuild the compound shape with the new child shape included
291 Refresh(child);
292 }
293 return;
294 }
295
296 // Remove the specified child from the linkset.
297 // Safe to call even if the child is not really in the linkset.
298 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
299 {
300 child.ClearDisplacement();
301
302 if (m_children.Remove(child))
303 {
304 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
305 child.LocalID,
306 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
307 child.LocalID, child.PhysBody.AddrString);
308
309 // Cause the child's body to be rebuilt and thus restored to normal operation
310 child.ForceBodyShapeRebuild(inTaintTime);
311
312 if (!HasAnyChildren)
313 {
314 // The linkset is now empty. The root needs rebuilding.
315 LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
316 }
317 else
318 {
319 // Rebuild the compound shape with the child removed
320 Refresh(LinksetRoot);
321 }
322 }
323 return;
324 }
325
326 // Called before the simulation step to make sure the compound based linkset
327 // is all initialized.
328 // Constraint linksets are rebuilt every time.
329 // Note that this works for rebuilding just the root after a linkset is taken apart.
330 // Called at taint time!!
331 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
332 private void RecomputeLinksetCompound()
333 {
334 try
335 {
336 Rebuilding = true;
337
338 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
339 // to what they should be as if the root was not in a linkset.
340 // Not that bad since we only get into this routine if there are children in the linkset and
341 // something has been updated/changed.
342 // Have to do the rebuild before checking for physical because this might be a linkset
343 // being destructed and going non-physical.
344 LinksetRoot.ForceBodyShapeRebuild(true);
345
346 // There is no reason to build all this physical stuff for a non-physical or empty linkset.
347 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
348 {
349 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
350 return; // Note the 'finally' clause at the botton which will get executed.
351 }
352
353 // Get a new compound shape to build the linkset shape in.
354 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
355
356 // Compute a displacement for each component so it is relative to the center-of-mass.
357 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
358 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
359
360 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
361 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
362
363 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
364 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
365 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
366 {
367 // Zero everything if center-of-mass displacement is not being done.
368 centerDisplacementV = OMV.Vector3.Zero;
369 LinksetRoot.ClearDisplacement();
370 }
371 else
372 {
373 // The actual center-of-mass could have been set by the user.
374 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
375 }
376
377 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
378 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
379
380 // Add the shapes of all the components of the linkset
381 int memberIndex = 1;
382 ForEachMember((cPrim) =>
383 {
384 if (IsRoot(cPrim))
385 {
386 // Root shape is always index zero.
387 cPrim.LinksetChildIndex = 0;
388 }
389 else
390 {
391 cPrim.LinksetChildIndex = memberIndex;
392 memberIndex++;
393 }
394
395 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
396 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
397
398 // Offset the child shape from the center-of-mass and rotate it to root relative.
399 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
400 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
401
402 // Add the child shape to the compound shape being built
403 if (childShape.physShapeInfo.HasPhysicalShape)
404 {
405 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
406 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
407 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
408
409 // Since we are borrowing the shape of the child, disable the origional child body
410 if (!IsRoot(cPrim))
411 {
412 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
413 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
414 // We don't want collisions from the old linkset children.
415 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
416 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
417 }
418 }
419 else
420 {
421 // The linkset must be in an intermediate state where all the children have not yet
422 // been constructed. This sometimes happens on startup when everything is getting
423 // built and some shapes have to wait for assets to be read in.
424 // Just skip this linkset for the moment and cause the shape to be rebuilt next tick.
425 // One problem might be that the shape is broken somehow and it never becomes completely
426 // available. This might cause the rebuild to happen over and over.
427 InternalScheduleRebuild(LinksetRoot);
428 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}",
429 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
430 // Output an annoying warning. It should only happen once but if it keeps coming out,
431 // the user knows there is something wrong and will report it.
432 m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader);
433 m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}",
434 LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape);
435
436 // This causes the loop to bail on building the rest of this linkset.
437 // The rebuild operation will fix it up next tick or declare the object unbuildable.
438 return true;
439 }
440
441 return false; // 'false' says to move onto the next child in the list
442 });
443
444 // Replace the root shape with the built compound shape.
445 // Object removed and added to world to get collision cache rebuilt for new shape.
446 LinksetRoot.PhysShape.Dereference(m_physicsScene);
447 LinksetRoot.PhysShape = linksetShape;
448 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
449 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
450 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
451 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
452 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
453
454 // With all of the linkset packed into the root prim, it has the mass of everyone.
455 LinksetMass = ComputeLinksetMass();
456 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
457
458 if (UseBulletSimRootOffsetHack)
459 {
460 // Enable the physical position updator to return the position and rotation of the root shape.
461 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
462 // compound shape. This aleviates the need to offset the returned physical position by the
463 // center-of-mass offset.
464 // TODO: either debug this feature or remove it.
465 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
466 }
467 }
468 finally
469 {
470 Rebuilding = false;
471 }
472
473 // See that the Aabb surrounds the new shape
474 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
475 }
476}
477} \ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
new file mode 100755
index 0000000..c4b4c86
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
@@ -0,0 +1,852 @@
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
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.PhysicsModule.BulletS
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public class BSLinkInfoConstraint : BSLinkInfo
40 {
41 public ConstraintType constraintType;
42 public BSConstraint constraint;
43 public OMV.Vector3 linearLimitLow;
44 public OMV.Vector3 linearLimitHigh;
45 public OMV.Vector3 angularLimitLow;
46 public OMV.Vector3 angularLimitHigh;
47 public bool useFrameOffset;
48 public bool enableTransMotor;
49 public float transMotorMaxVel;
50 public float transMotorMaxForce;
51 public float cfm;
52 public float erp;
53 public float solverIterations;
54 //
55 public OMV.Vector3 frameInAloc;
56 public OMV.Quaternion frameInArot;
57 public OMV.Vector3 frameInBloc;
58 public OMV.Quaternion frameInBrot;
59 public bool useLinearReferenceFrameA;
60 // Spring
61 public bool[] springAxisEnable;
62 public float[] springDamping;
63 public float[] springStiffness;
64 public OMV.Vector3 springLinearEquilibriumPoint;
65 public OMV.Vector3 springAngularEquilibriumPoint;
66
67 public BSLinkInfoConstraint(BSPrimLinkable pMember)
68 : base(pMember)
69 {
70 constraint = null;
71 ResetLink();
72 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
73 }
74
75 // Set all the parameters for this constraint to a fixed, non-movable constraint.
76 public override void ResetLink()
77 {
78 // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
79 constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE;
80 linearLimitLow = OMV.Vector3.Zero;
81 linearLimitHigh = OMV.Vector3.Zero;
82 angularLimitLow = OMV.Vector3.Zero;
83 angularLimitHigh = OMV.Vector3.Zero;
84 useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
85 enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
86 transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
87 transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
88 cfm = BSParam.LinkConstraintCFM;
89 erp = BSParam.LinkConstraintERP;
90 solverIterations = BSParam.LinkConstraintSolverIterations;
91 frameInAloc = OMV.Vector3.Zero;
92 frameInArot = OMV.Quaternion.Identity;
93 frameInBloc = OMV.Vector3.Zero;
94 frameInBrot = OMV.Quaternion.Identity;
95 useLinearReferenceFrameA = true;
96 springAxisEnable = new bool[6];
97 springDamping = new float[6];
98 springStiffness = new float[6];
99 for (int ii = 0; ii < springAxisEnable.Length; ii++)
100 {
101 springAxisEnable[ii] = false;
102 springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
103 springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
104 }
105 springLinearEquilibriumPoint = OMV.Vector3.Zero;
106 springAngularEquilibriumPoint = OMV.Vector3.Zero;
107 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
108 }
109
110 // Given a constraint, apply the current constraint parameters to same.
111 public override void SetLinkParameters(BSConstraint constrain)
112 {
113 member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
114 switch (constraintType)
115 {
116 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
117 case ConstraintType.D6_CONSTRAINT_TYPE:
118 BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
119 if (constrain6dof != null)
120 {
121 // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
122 // zero linear and angular limits makes the objects unable to move in relation to each other
123 constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
124 constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
125
126 // tweek the constraint to increase stability
127 constrain6dof.UseFrameOffset(useFrameOffset);
128 constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
129 constrain6dof.SetCFMAndERP(cfm, erp);
130 if (solverIterations != 0f)
131 {
132 constrain6dof.SetSolverIterations(solverIterations);
133 }
134 }
135 break;
136 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
137 BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
138 if (constrainSpring != null)
139 {
140 // zero linear and angular limits makes the objects unable to move in relation to each other
141 constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
142 constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
143
144 // tweek the constraint to increase stability
145 constrainSpring.UseFrameOffset(useFrameOffset);
146 constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
147 constrainSpring.SetCFMAndERP(cfm, erp);
148 if (solverIterations != 0f)
149 {
150 constrainSpring.SetSolverIterations(solverIterations);
151 }
152 for (int ii = 0; ii < springAxisEnable.Length; ii++)
153 {
154 constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
155 if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
156 constrainSpring.SetDamping(ii, springDamping[ii]);
157 if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
158 constrainSpring.SetStiffness(ii, springStiffness[ii]);
159 }
160 constrainSpring.CalculateTransforms();
161
162 if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
163 constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
164 else
165 constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
166 }
167 break;
168 default:
169 break;
170 }
171 }
172
173 // Return 'true' if the property updates from the physics engine should be reported
174 // to the simulator.
175 // If the constraint is fixed, we don't need to report as the simulator and viewer will
176 // report the right things.
177 public override bool ShouldUpdateChildProperties()
178 {
179 bool ret = true;
180 if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE)
181 ret = false;
182
183 return ret;
184 }
185 }
186
187 public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
188 {
189 LinksetImpl = LinksetImplementation.Constraint;
190 }
191
192 private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
193
194 // When physical properties are changed the linkset needs to recalculate
195 // its internal properties.
196 // This is queued in the 'post taint' queue so the
197 // refresh will happen once after all the other taints are applied.
198 public override void Refresh(BSPrimLinkable requestor)
199 {
200 ScheduleRebuild(requestor);
201 base.Refresh(requestor);
202
203 }
204
205 private void ScheduleRebuild(BSPrimLinkable requestor)
206 {
207 DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
208 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
209
210 // When rebuilding, it is possible to set properties that would normally require a rebuild.
211 // If already rebuilding, don't request another rebuild.
212 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
213 lock (this)
214 {
215 if (!RebuildScheduled)
216 {
217 if (!Rebuilding && HasAnyChildren)
218 {
219 RebuildScheduled = true;
220 // Queue to happen after all the other taint processing
221 m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
222 {
223 if (HasAnyChildren)
224 {
225 // Constraints that have not been changed are not rebuild but make sure
226 // the constraint of the requestor is rebuilt.
227 PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
228 // Rebuild the linkset and all its constraints.
229 RecomputeLinksetConstraints();
230 }
231 RebuildScheduled = false;
232 });
233 }
234 }
235 }
236 }
237
238 // The object is going dynamic (physical). Do any setup necessary
239 // for a dynamic linkset.
240 // Only the state of the passed object can be modified. The rest of the linkset
241 // has not yet been fully constructed.
242 // Return 'true' if any properties updated on the passed object.
243 // Called at taint-time!
244 public override bool MakeDynamic(BSPrimLinkable child)
245 {
246 bool ret = false;
247 DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
248 if (IsRoot(child))
249 {
250 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
251 Refresh(LinksetRoot);
252 }
253 return ret;
254 }
255
256 // The object is going static (non-physical). Do any setup necessary for a static linkset.
257 // Return 'true' if any properties updated on the passed object.
258 // This doesn't normally happen -- OpenSim removes the objects from the physical
259 // world if it is a static linkset.
260 // Called at taint-time!
261 public override bool MakeStatic(BSPrimLinkable child)
262 {
263 bool ret = false;
264
265 DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
266 child.ClearDisplacement();
267 if (IsRoot(child))
268 {
269 // Schedule a rebuild to verify that the root shape is set to the real shape.
270 Refresh(LinksetRoot);
271 }
272 return ret;
273 }
274
275 // Called at taint-time!!
276 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
277 {
278 // Nothing to do for constraints on property updates
279 }
280
281 // Routine called when rebuilding the body of some member of the linkset.
282 // Destroy all the constraints have have been made to root and set
283 // up to rebuild the constraints before the next simulation step.
284 // Returns 'true' of something was actually removed and would need restoring
285 // Called at taint-time!!
286 public override bool RemoveDependencies(BSPrimLinkable child)
287 {
288 bool ret = false;
289
290 DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
291 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
292
293 lock (m_linksetActivityLock)
294 {
295 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
296 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
297 // Cause the constraints, et al to be rebuilt before the next simulation step.
298 Refresh(LinksetRoot);
299 }
300 return ret;
301 }
302
303 // ================================================================
304
305 // Add a new child to the linkset.
306 // Called while LinkActivity is locked.
307 protected override void AddChildToLinkset(BSPrimLinkable child)
308 {
309 if (!HasChild(child))
310 {
311 m_children.Add(child, new BSLinkInfoConstraint(child));
312
313 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
314
315 // Cause constraints and assorted properties to be recomputed before the next simulation step.
316 Refresh(LinksetRoot);
317 }
318 return;
319 }
320
321 // Remove the specified child from the linkset.
322 // Safe to call even if the child is not really in my linkset.
323 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
324 {
325 if (m_children.Remove(child))
326 {
327 BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
328 BSPrimLinkable childx = child;
329
330 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
331 childx.LocalID,
332 rootx.LocalID, rootx.PhysBody.AddrString,
333 childx.LocalID, childx.PhysBody.AddrString);
334
335 m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
336 {
337 PhysicallyUnlinkAChildFromRoot(rootx, childx);
338 });
339 // See that the linkset parameters are recomputed at the end of the taint time.
340 Refresh(LinksetRoot);
341 }
342 else
343 {
344 // Non-fatal occurance.
345 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
346 }
347 return;
348 }
349
350 // Create a constraint between me (root of linkset) and the passed prim (the child).
351 // Called at taint time!
352 private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
353 {
354 // Don't build the constraint when asked. Put it off until just before the simulation step.
355 Refresh(rootPrim);
356 }
357
358 // Create a static constraint between the two passed objects
359 private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
360 {
361 BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
362 if (linkInfo == null)
363 return null;
364
365 // Zero motion for children so they don't interpolate
366 li.member.ZeroMotion(true);
367
368 BSConstraint constrain = null;
369
370 switch (linkInfo.constraintType)
371 {
372 case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
373 case ConstraintType.D6_CONSTRAINT_TYPE:
374 // Relative position normalized to the root prim
375 // Essentually a vector pointing from center of rootPrim to center of li.member
376 OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
377
378 // real world coordinate of midpoint between the two objects
379 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
380
381 DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
382 rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
383 rootPrim.Position, linkInfo.member.Position, midPoint);
384
385 // create a constraint that allows no freedom of movement between the two objects
386 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
387
388 constrain = new BSConstraint6Dof(
389 m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
390
391 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
392 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
393 * of the objects.
394 * Code left for future programmers.
395 // ==================================================================================
396 // relative position normalized to the root prim
397 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
398 OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
399
400 // relative rotation of the child to the parent
401 OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
402 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
403
404 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
405 constrain = new BS6DofConstraint(
406 PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
407 OMV.Vector3.Zero,
408 OMV.Quaternion.Inverse(rootPrim.Orientation),
409 OMV.Vector3.Zero,
410 OMV.Quaternion.Inverse(liConstraint.member.Orientation),
411 true,
412 true
413 );
414 // ==================================================================================
415 */
416
417 break;
418 case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
419 constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
420 linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
421 linkInfo.useLinearReferenceFrameA,
422 true /*disableCollisionsBetweenLinkedBodies*/);
423 DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
424 rootPrim.LocalID,
425 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
426 linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
427 rootPrim.Position, linkInfo.member.Position);
428
429 break;
430 default:
431 break;
432 }
433
434 linkInfo.SetLinkParameters(constrain);
435
436 m_physicsScene.Constraints.AddConstraint(constrain);
437
438 return constrain;
439 }
440
441 // Remove linkage between the linkset root and a particular child
442 // The root and child bodies are passed in because we need to remove the constraint between
443 // the bodies that were present at unlink time.
444 // Called at taint time!
445 private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
446 {
447 bool ret = false;
448 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
449 rootPrim.LocalID,
450 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
451 childPrim.LocalID, childPrim.PhysBody.AddrString);
452
453 // If asked to unlink root from root, just remove all the constraints
454 if (rootPrim == childPrim || childPrim == LinksetRoot)
455 {
456 PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
457 ret = true;
458 }
459 else
460 {
461 // Find the constraint for this link and get rid of it from the overall collection and from my list
462 if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
463 {
464 // Make the child refresh its location
465 m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
466 ret = true;
467 }
468 }
469
470 return ret;
471 }
472
473 // Remove linkage between myself and any possible children I might have.
474 // Returns 'true' of any constraints were destroyed.
475 // Called at taint time!
476 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
477 {
478 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
479
480 return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
481 }
482
483 // Call each of the constraints that make up this linkset and recompute the
484 // various transforms and variables. Create constraints of not created yet.
485 // Called before the simulation step to make sure the constraint based linkset
486 // is all initialized.
487 // Called at taint time!!
488 private void RecomputeLinksetConstraints()
489 {
490 float linksetMass = LinksetMass;
491 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
492
493 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
494 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
495
496 try
497 {
498 Rebuilding = true;
499
500 // There is no reason to build all this physical stuff for a non-physical linkset.
501 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
502 {
503 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
504 return; // Note the 'finally' clause at the botton which will get executed.
505 }
506
507 ForEachLinkInfo((li) =>
508 {
509 // A child in the linkset physically shows the mass of the whole linkset.
510 // This allows Bullet to apply enough force on the child to move the whole linkset.
511 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
512 li.member.UpdatePhysicalMassProperties(linksetMass, true);
513
514 BSConstraint constrain;
515 if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
516 {
517 // If constraint doesn't exist yet, create it.
518 constrain = BuildConstraint(LinksetRoot, li);
519 }
520 li.SetLinkParameters(constrain);
521 constrain.RecomputeConstraintVariables(linksetMass);
522
523 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
524 return false; // 'false' says to keep processing other members
525 });
526 }
527 finally
528 {
529 Rebuilding = false;
530 }
531 }
532
533 #region Extension
534 public override object Extension(string pFunct, params object[] pParams)
535 {
536 object ret = null;
537 switch (pFunct)
538 {
539 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
540 case ExtendedPhysics.PhysFunctChangeLinkType:
541 if (pParams.Length > 2)
542 {
543 int requestedType = (int)pParams[2];
544 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
545 if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE
546 || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
547 || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
548 || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
549 || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
550 || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
551 {
552 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
553 if (child != null)
554 {
555 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
556 LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
557 m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
558 {
559 // Pick up all the constraints currently created.
560 RemoveDependencies(child);
561
562 BSLinkInfo linkInfo = null;
563 if (TryGetLinkInfo(child, out linkInfo))
564 {
565 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
566 if (linkInfoC != null)
567 {
568 linkInfoC.constraintType = (ConstraintType)requestedType;
569 ret = (object)true;
570 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
571 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
572 }
573 else
574 {
575 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
576 }
577 }
578 else
579 {
580 DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
581 }
582 // Cause the whole linkset to be rebuilt in post-taint time.
583 Refresh(child);
584 });
585 }
586 else
587 {
588 DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
589 }
590 }
591 else
592 {
593 DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
594 LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
595 }
596 }
597 break;
598 // pParams = [ BSPhysObject root, BSPhysObject child ]
599 case ExtendedPhysics.PhysFunctGetLinkType:
600 if (pParams.Length > 0)
601 {
602 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
603 if (child != null)
604 {
605 BSLinkInfo linkInfo = null;
606 if (TryGetLinkInfo(child, out linkInfo))
607 {
608 BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
609 if (linkInfoC != null)
610 {
611 ret = (object)(int)linkInfoC.constraintType;
612 DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
613 linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
614
615 }
616 }
617 }
618 }
619 break;
620 // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
621 case ExtendedPhysics.PhysFunctChangeLinkParams:
622 // There should be two parameters: the childActor and a list of parameters to set
623 if (pParams.Length > 2)
624 {
625 BSPrimLinkable child = pParams[1] as BSPrimLinkable;
626 BSLinkInfo baseLinkInfo = null;
627 if (TryGetLinkInfo(child, out baseLinkInfo))
628 {
629 BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
630 if (linkInfo != null)
631 {
632 int valueInt;
633 float valueFloat;
634 bool valueBool;
635 OMV.Vector3 valueVector;
636 OMV.Vector3 valueVector2;
637 OMV.Quaternion valueQuaternion;
638 int axisLow, axisHigh;
639
640 int opIndex = 2;
641 while (opIndex < pParams.Length)
642 {
643 int thisOp = 0;
644 string errMsg = "";
645 try
646 {
647 thisOp = (int)pParams[opIndex];
648 DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
649 linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
650 switch (thisOp)
651 {
652 case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
653 valueInt = (int)pParams[opIndex + 1];
654 ConstraintType valueType = (ConstraintType)valueInt;
655 if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE
656 || valueType == ConstraintType.D6_CONSTRAINT_TYPE
657 || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
658 || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
659 || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
660 || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
661 {
662 linkInfo.constraintType = valueType;
663 }
664 opIndex += 2;
665 break;
666 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
667 errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
668 valueVector = (OMV.Vector3)pParams[opIndex + 1];
669 linkInfo.frameInAloc = valueVector;
670 opIndex += 2;
671 break;
672 case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
673 errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
674 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
675 linkInfo.frameInArot = valueQuaternion;
676 opIndex += 2;
677 break;
678 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
679 errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
680 valueVector = (OMV.Vector3)pParams[opIndex + 1];
681 linkInfo.frameInBloc = valueVector;
682 opIndex += 2;
683 break;
684 case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
685 errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
686 valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
687 linkInfo.frameInBrot = valueQuaternion;
688 opIndex += 2;
689 break;
690 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
691 errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
692 valueVector = (OMV.Vector3)pParams[opIndex + 1];
693 linkInfo.linearLimitLow = valueVector;
694 opIndex += 2;
695 break;
696 case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
697 errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
698 valueVector = (OMV.Vector3)pParams[opIndex + 1];
699 linkInfo.linearLimitHigh = valueVector;
700 opIndex += 2;
701 break;
702 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
703 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
704 valueVector = (OMV.Vector3)pParams[opIndex + 1];
705 linkInfo.angularLimitLow = valueVector;
706 opIndex += 2;
707 break;
708 case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
709 errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
710 valueVector = (OMV.Vector3)pParams[opIndex + 1];
711 linkInfo.angularLimitHigh = valueVector;
712 opIndex += 2;
713 break;
714 case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
715 errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
716 valueBool = ((int)pParams[opIndex + 1]) != 0;
717 linkInfo.useFrameOffset = valueBool;
718 opIndex += 2;
719 break;
720 case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
721 errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
722 valueBool = ((int)pParams[opIndex + 1]) != 0;
723 linkInfo.enableTransMotor = valueBool;
724 opIndex += 2;
725 break;
726 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
727 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
728 valueFloat = (float)pParams[opIndex + 1];
729 linkInfo.transMotorMaxVel = valueFloat;
730 opIndex += 2;
731 break;
732 case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
733 errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
734 valueFloat = (float)pParams[opIndex + 1];
735 linkInfo.transMotorMaxForce = valueFloat;
736 opIndex += 2;
737 break;
738 case ExtendedPhysics.PHYS_PARAM_CFM:
739 errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
740 valueFloat = (float)pParams[opIndex + 1];
741 linkInfo.cfm = valueFloat;
742 opIndex += 2;
743 break;
744 case ExtendedPhysics.PHYS_PARAM_ERP:
745 errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
746 valueFloat = (float)pParams[opIndex + 1];
747 linkInfo.erp = valueFloat;
748 opIndex += 2;
749 break;
750 case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
751 errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
752 valueFloat = (float)pParams[opIndex + 1];
753 linkInfo.solverIterations = valueFloat;
754 opIndex += 2;
755 break;
756 case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
757 errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
758 valueInt = (int)pParams[opIndex + 1];
759 valueBool = ((int)pParams[opIndex + 2]) != 0;
760 GetAxisRange(valueInt, out axisLow, out axisHigh);
761 for (int ii = axisLow; ii <= axisHigh; ii++)
762 linkInfo.springAxisEnable[ii] = valueBool;
763 opIndex += 3;
764 break;
765 case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
766 errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
767 valueInt = (int)pParams[opIndex + 1];
768 valueFloat = (float)pParams[opIndex + 2];
769 GetAxisRange(valueInt, out axisLow, out axisHigh);
770 for (int ii = axisLow; ii <= axisHigh; ii++)
771 linkInfo.springDamping[ii] = valueFloat;
772 opIndex += 3;
773 break;
774 case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
775 errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
776 valueInt = (int)pParams[opIndex + 1];
777 valueFloat = (float)pParams[opIndex + 2];
778 GetAxisRange(valueInt, out axisLow, out axisHigh);
779 for (int ii = axisLow; ii <= axisHigh; ii++)
780 linkInfo.springStiffness[ii] = valueFloat;
781 opIndex += 3;
782 break;
783 case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
784 errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
785 valueVector = (OMV.Vector3)pParams[opIndex + 1];
786 valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
787 linkInfo.springLinearEquilibriumPoint = valueVector;
788 linkInfo.springAngularEquilibriumPoint = valueVector2;
789 opIndex += 3;
790 break;
791 case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
792 errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
793 valueBool = ((int)pParams[opIndex + 1]) != 0;
794 linkInfo.useLinearReferenceFrameA = valueBool;
795 opIndex += 2;
796 break;
797 default:
798 break;
799 }
800 }
801 catch (InvalidCastException e)
802 {
803 m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
804 LogHeader, errMsg, e);
805 }
806 catch (Exception e)
807 {
808 m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
809 }
810 }
811 }
812 // Something changed so a rebuild is in order
813 Refresh(child);
814 }
815 }
816 break;
817 default:
818 ret = base.Extension(pFunct, pParams);
819 break;
820 }
821 return ret;
822 }
823
824 // Bullet constraints keep some limit parameters for each linear and angular axis.
825 // Setting same is easier if there is an easy way to see all or types.
826 // This routine returns the array limits for the set of axis.
827 private void GetAxisRange(int rangeSpec, out int low, out int high)
828 {
829 switch (rangeSpec)
830 {
831 case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
832 low = 0;
833 high = 2;
834 break;
835 case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
836 low = 3;
837 high = 5;
838 break;
839 case ExtendedPhysics.PHYS_AXIS_ALL:
840 low = 0;
841 high = 5;
842 break;
843 default:
844 low = high = rangeSpec;
845 break;
846 }
847 return;
848 }
849 #endregion // Extension
850
851}
852}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
index 92d62ff..0e44d03 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
@@ -30,7 +30,7 @@ using System.Text;
30using System.Reflection; 30using System.Reflection;
31using Nini.Config; 31using Nini.Config;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.PhysicsModule.BulletS
34{ 34{
35 35
36public struct MaterialAttributes 36public struct MaterialAttributes
@@ -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/PhysicsModules/BulletS/BSMotors.cs
index 817a5f7..2faf2d4 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
@@ -31,7 +31,7 @@ using System.Text;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33 33
34namespace OpenSim.Region.Physics.BulletSPlugin 34namespace OpenSim.Region.PhysicsModule.BulletS
35{ 35{
36public abstract class BSMotor 36public abstract class BSMotor
37{ 37{
@@ -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,9 @@ 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 if (!ErrorIsZero(error))
152 { 148 {
153 correction = Step(timeStep, error); 149 correction = StepError(timeStep, error);
154 150
155 CurrentValue += correction; 151 CurrentValue += correction;
156 152
@@ -163,44 +159,43 @@ public class BSVMotor : BSMotor
163 TargetValue *= (1f - decayFactor); 159 TargetValue *= (1f - decayFactor);
164 } 160 }
165 161
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}", 162 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, 163 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction); 164 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}", 165 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
183 BSScene.DetailLogZero, UseName, 166 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 } 167 }
187 else 168 else
188 { 169 {
189 // Difference between what we have and target is small. Motor is done. 170 // Difference between what we have and target is small. Motor is done.
171 if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
172 {
173 // The target can step down to nearly zero but not get there. If close to zero
174 // it is really zero.
175 TargetValue = Vector3.Zero;
176 }
190 CurrentValue = TargetValue; 177 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", 178 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); 179 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
193 } 180 }
181 LastError = error;
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 // Given and error, computer a correction for this step.
192 // Simple scaling of the error by the timestep.
193 public virtual Vector3 StepError(float timeStep, Vector3 error)
198 { 194 {
199 if (!Enabled) return Vector3.Zero; 195 if (!Enabled) return Vector3.Zero;
200 196
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero; 197 Vector3 returnCorrection = Vector3.Zero;
203 if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 198 if (!ErrorIsZero(error))
204 { 199 {
205 // correction = error / secondsItShouldTakeToCorrect 200 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount; 201 Vector3 correctionAmount;
@@ -222,57 +217,155 @@ public class BSVMotor : BSMotor
222 // maximum number of outputs to generate. 217 // maximum number of outputs to generate.
223 int maxOutput = 50; 218 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); 219 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}", 220 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
226 BSScene.DetailLogZero, UseName, 221 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency, 222 TimeScale, TargetValueDecayTimeScale, Efficiency,
228 CurrentValue, TargetValue); 223 CurrentValue, TargetValue);
229 224
230 LastError = BSMotor.InfiniteVector; 225 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) 226 while (maxOutput-- > 0 && !ErrorIsZero())
232 { 227 {
233 Vector3 lastStep = Step(timeStep); 228 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", 229 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); 230 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 } 231 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); 232 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238 233
239 234
240 } 235 }
241 236
242 public override string ToString() 237 public override string ToString()
243 { 238 {
244 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>", 239 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
245 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale); 240 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
246 } 241 }
247} 242}
248 243
244// ============================================================================
245// ============================================================================
249public class BSFMotor : BSMotor 246public class BSFMotor : BSMotor
250{ 247{
251 public float TimeScale { get; set; } 248 public virtual float TimeScale { get; set; }
252 public float DecayTimeScale { get; set; } 249 public virtual float TargetValueDecayTimeScale { get; set; }
253 public float Friction { get; set; } 250 public virtual float Efficiency { get; set; }
254 public float Efficiency { get; set; } 251
252 public virtual float ErrorZeroThreshold { get; set; }
253
254 public virtual float TargetValue { get; protected set; }
255 public virtual float CurrentValue { get; protected set; }
256 public virtual float LastError { get; protected set; }
255 257
256 public float Target { get; private set; } 258 public virtual bool ErrorIsZero()
257 public float CurrentValue { get; private set; } 259 {
260 return ErrorIsZero(LastError);
261 }
262 public virtual bool ErrorIsZero(float err)
263 {
264 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
265 }
258 266
259 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) 267 public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
260 : base(useName) 268 : base(useName)
261 { 269 {
270 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
271 Efficiency = 1f;
272 CurrentValue = TargetValue = 0f;
273 ErrorZeroThreshold = 0.01f;
262 } 274 }
263 public void SetCurrent(float target) 275 public void SetCurrent(float current)
264 { 276 {
277 CurrentValue = current;
265 } 278 }
266 public void SetTarget(float target) 279 public void SetTarget(float target)
267 { 280 {
281 TargetValue = target;
282 }
283 public override void Zero()
284 {
285 base.Zero();
286 CurrentValue = TargetValue = 0f;
268 } 287 }
288
269 public virtual float Step(float timeStep) 289 public virtual float Step(float timeStep)
270 { 290 {
271 return 0f; 291 if (!Enabled) return TargetValue;
292
293 float origTarget = TargetValue; // DEBUG
294 float origCurrVal = CurrentValue; // DEBUG
295
296 float correction = 0f;
297 float error = TargetValue - CurrentValue;
298 if (!ErrorIsZero(error))
299 {
300 correction = StepError(timeStep, error);
301
302 CurrentValue += correction;
303
304 // The desired value reduces to zero which also reduces the difference with current.
305 // If the decay time is infinite, don't decay at all.
306 float decayFactor = 0f;
307 if (TargetValueDecayTimeScale != BSMotor.Infinite)
308 {
309 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
310 TargetValue *= (1f - decayFactor);
311 }
312
313 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
314 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
315 timeStep, error, correction);
316 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
317 BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
318 }
319 else
320 {
321 // Difference between what we have and target is small. Motor is done.
322 if (Util.InRange<float>(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
323 {
324 // The target can step down to nearly zero but not get there. If close to zero
325 // it is really zero.
326 TargetValue = 0f;
327 }
328 CurrentValue = TargetValue;
329 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
330 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
331 }
332 LastError = error;
333
334 return CurrentValue;
272 } 335 }
336
337 public virtual float StepError(float timeStep, float error)
338 {
339 if (!Enabled) return 0f;
340
341 float returnCorrection = 0f;
342 if (!ErrorIsZero(error))
343 {
344 // correction = error / secondsItShouldTakeToCorrect
345 float correctionAmount;
346 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
347 correctionAmount = error * timeStep;
348 else
349 correctionAmount = error / TimeScale * timeStep;
350
351 returnCorrection = correctionAmount;
352 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
353 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
354 }
355 return returnCorrection;
356 }
357
358 public override string ToString()
359 {
360 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
361 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
362 }
363
273} 364}
274 365
275// Proportional, Integral, Derivitive Motor 366// ============================================================================
367// ============================================================================
368// Proportional, Integral, Derivitive ("PID") Motor
276// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. 369// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
277public class BSPIDVMotor : BSVMotor 370public class BSPIDVMotor : BSVMotor
278{ 371{
@@ -281,6 +374,11 @@ public class BSPIDVMotor : BSVMotor
281 public Vector3 integralFactor { get; set; } 374 public Vector3 integralFactor { get; set; }
282 public Vector3 derivFactor { get; set; } 375 public Vector3 derivFactor { get; set; }
283 376
377 // The factors are vectors for the three dimensions. This is the proportional of each
378 // that is applied. This could be multiplied through the actual factors but it
379 // is sometimes easier to manipulate the factors and their mix separately.
380 public Vector3 FactorMix;
381
284 // Arbritrary factor range. 382 // Arbritrary factor range.
285 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. 383 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
286 public float EfficiencyHigh = 0.4f; 384 public float EfficiencyHigh = 0.4f;
@@ -295,6 +393,7 @@ public class BSPIDVMotor : BSVMotor
295 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); 393 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
296 integralFactor = new Vector3(1.00f, 1.00f, 1.00f); 394 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
297 derivFactor = new Vector3(1.00f, 1.00f, 1.00f); 395 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
396 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
298 RunningIntegration = Vector3.Zero; 397 RunningIntegration = Vector3.Zero;
299 LastError = Vector3.Zero; 398 LastError = Vector3.Zero;
300 } 399 }
@@ -310,20 +409,24 @@ public class BSPIDVMotor : BSVMotor
310 set 409 set
311 { 410 {
312 base.Efficiency = Util.Clamp(value, 0f, 1f); 411 base.Efficiency = Util.Clamp(value, 0f, 1f);
412
313 // Compute factors based on efficiency. 413 // 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. 414 // 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. 415 // If efficiency is low (0f), use a factor value that overcorrects.
316 // TODO: might want to vary contribution of different factor depending on efficiency. 416 // TODO: might want to vary contribution of different factor depending on efficiency.
317 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; 417 // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
318 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; 418 float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
419
319 proportionFactor = new Vector3(factor, factor, factor); 420 proportionFactor = new Vector3(factor, factor, factor);
320 integralFactor = new Vector3(factor, factor, factor); 421 integralFactor = new Vector3(factor, factor, factor);
321 derivFactor = new Vector3(factor, factor, factor); 422 derivFactor = new Vector3(factor, factor, factor);
423
424 MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
322 } 425 }
323 } 426 }
324 427
325 // Ignore Current and Target Values and just advance the PID computation on this error. 428 // Advance the PID computation on this error.
326 public override Vector3 Step(float timeStep, Vector3 error) 429 public override Vector3 StepError(float timeStep, Vector3 error)
327 { 430 {
328 if (!Enabled) return Vector3.Zero; 431 if (!Enabled) return Vector3.Zero;
329 432
@@ -331,15 +434,16 @@ public class BSPIDVMotor : BSVMotor
331 RunningIntegration += error * timeStep; 434 RunningIntegration += error * timeStep;
332 435
333 // A simple derivitive is the rate of change from the last error. 436 // A simple derivitive is the rate of change from the last error.
334 Vector3 derivFactor = (error - LastError) * timeStep; 437 Vector3 derivitive = (error - LastError) * timeStep;
335 LastError = error; 438
439 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
440 Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X
441 + RunningIntegration / TimeScale * integralFactor * FactorMix.Y
442 + derivitive / TimeScale * derivFactor * FactorMix.Z
443 ;
336 444
337 // Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) 445 MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
338 Vector3 ret = -( 446 BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
339 error * proportionFactor
340 + RunningIntegration * integralFactor
341 + derivFactor * derivFactor
342 );
343 447
344 return ret; 448 return ret;
345 } 449 }
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
new file mode 100755
index 0000000..c296008
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
@@ -0,0 +1,927 @@
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.Reflection;
30using System.Text;
31
32using OpenSim.Region.PhysicsModules.SharedBase;
33
34using OpenMetaverse;
35using Nini.Config;
36
37namespace OpenSim.Region.PhysicsModule.BulletS
38{
39public static class BSParam
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
57 /// <summary>
58 /// Set whether physics is active or not.
59 /// </summary>
60 /// <remarks>
61 /// Can be enabled and disabled to start and stop physics.
62 /// </remarks>
63 public static bool Active { get; private set; }
64
65 public static bool UseSeparatePhysicsThread { get; private set; }
66 public static float PhysicsTimeStep { get; private set; }
67
68 // Level of Detail values kept as float because that's what the Meshmerizer wants
69 public static float MeshLOD { get; private set; }
70 public static float MeshCircularLOD { get; private set; }
71 public static float MeshMegaPrimLOD { get; private set; }
72 public static float MeshMegaPrimThreshold { get; private set; }
73 public static float SculptLOD { get; private set; }
74
75 public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
76 public static float UpdateVelocityChangeThreshold { get; private set; }
77
78 public static float MinimumObjectMass { get; private set; }
79 public static float MaximumObjectMass { get; private set; }
80 public static float MaxLinearVelocity { get; private set; }
81 public static float MaxLinearVelocitySquared { get; private set; }
82 public static float MaxAngularVelocity { get; private set; }
83 public static float MaxAngularVelocitySquared { get; private set; }
84 public static float MaxAddForceMagnitude { get; private set; }
85 public static float MaxAddForceMagnitudeSquared { get; private set; }
86 public static float DensityScaleFactor { get; private set; }
87
88 public static float LinearDamping { get; private set; }
89 public static float AngularDamping { get; private set; }
90 public static float DeactivationTime { get; private set; }
91 public static float LinearSleepingThreshold { get; private set; }
92 public static float AngularSleepingThreshold { get; private set; }
93 public static float CcdMotionThreshold { get; private set; }
94 public static float CcdSweptSphereRadius { get; private set; }
95 public static float ContactProcessingThreshold { get; private set; }
96
97 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
98 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
99 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
100 public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
101 public static bool ShouldUseBulletHACD { get; set; }
102 public static bool ShouldUseSingleConvexHullForPrims { get; set; }
103 public static bool ShouldUseGImpactShapeForPrims { get; set; }
104 public static bool ShouldUseAssetHulls { get; set; }
105
106 public static float TerrainImplementation { get; set; }
107 public static int TerrainMeshMagnification { get; private set; }
108 public static float TerrainGroundPlane { get; private set; }
109 public static float TerrainFriction { get; private set; }
110 public static float TerrainHitFraction { get; private set; }
111 public static float TerrainRestitution { get; private set; }
112 public static float TerrainContactProcessingThreshold { get; private set; }
113 public static float TerrainCollisionMargin { get; private set; }
114
115 public static float DefaultFriction { get; private set; }
116 public static float DefaultDensity { get; private set; }
117 public static float DefaultRestitution { get; private set; }
118 public static float CollisionMargin { get; private set; }
119 public static float Gravity { get; private set; }
120
121 // Physics Engine operation
122 public static float MaxPersistantManifoldPoolSize { get; private set; }
123 public static float MaxCollisionAlgorithmPoolSize { get; private set; }
124 public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
125 public static bool ShouldForceUpdateAllAabbs { get; private set; }
126 public static bool ShouldRandomizeSolverOrder { get; private set; }
127 public static bool ShouldSplitSimulationIslands { get; private set; }
128 public static bool ShouldEnableFrictionCaching { get; private set; }
129 public static float NumberOfSolverIterations { get; private set; }
130 public static bool UseSingleSidedMeshes { get; private set; }
131 public static float GlobalContactBreakingThreshold { get; private set; }
132 public static float PhysicsUnmanLoggingFrames { get; private set; }
133
134 // Avatar parameters
135 public static bool AvatarToAvatarCollisionsByDefault { get; private set; }
136 public static float AvatarFriction { get; private set; }
137 public static float AvatarStandingFriction { get; private set; }
138 public static float AvatarAlwaysRunFactor { get; private set; }
139 public static float AvatarDensity { get; private set; }
140 public static float AvatarRestitution { get; private set; }
141 public static int AvatarShape { get; private set; }
142 public static float AvatarCapsuleWidth { get; private set; }
143 public static float AvatarCapsuleDepth { get; private set; }
144 public static float AvatarCapsuleHeight { get; private set; }
145 public static float AvatarHeightLowFudge { get; private set; }
146 public static float AvatarHeightMidFudge { get; private set; }
147 public static float AvatarHeightHighFudge { get; private set; }
148 public static float AvatarFlyingGroundMargin { get; private set; }
149 public static float AvatarFlyingGroundUpForce { get; private set; }
150 public static float AvatarTerminalVelocity { get; private set; }
151 public static float AvatarContactProcessingThreshold { get; private set; }
152 public static float AvatarStopZeroThreshold { get; private set; }
153 public static int AvatarJumpFrames { get; private set; }
154 public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
155 public static float AvatarStepHeight { get; private set; }
156 public static float AvatarStepAngle { get; private set; }
157 public static float AvatarStepGroundFudge { get; private set; }
158 public static float AvatarStepApproachFactor { get; private set; }
159 public static float AvatarStepForceFactor { get; private set; }
160 public static float AvatarStepUpCorrectionFactor { get; private set; }
161 public static int AvatarStepSmoothingSteps { get; private set; }
162
163 // Vehicle parameters
164 public static float VehicleMaxLinearVelocity { get; private set; }
165 public static float VehicleMaxLinearVelocitySquared { get; private set; }
166 public static float VehicleMinLinearVelocity { get; private set; }
167 public static float VehicleMinLinearVelocitySquared { get; private set; }
168 public static float VehicleMaxAngularVelocity { get; private set; }
169 public static float VehicleMaxAngularVelocitySq { get; private set; }
170 public static float VehicleAngularDamping { get; private set; }
171 public static float VehicleFriction { get; private set; }
172 public static float VehicleRestitution { get; private set; }
173 public static Vector3 VehicleLinearFactor { get; private set; }
174 public static Vector3 VehicleAngularFactor { get; private set; }
175 public static Vector3 VehicleInertiaFactor { get; private set; }
176 public static float VehicleGroundGravityFudge { get; private set; }
177 public static float VehicleAngularBankingTimescaleFudge { get; private set; }
178 public static bool VehicleEnableLinearDeflection { get; private set; }
179 public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; }
180 public static bool VehicleEnableAngularVerticalAttraction { get; private set; }
181 public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; }
182 public static bool VehicleEnableAngularDeflection { get; private set; }
183 public static bool VehicleEnableAngularBanking { get; private set; }
184
185 // Convex Hulls
186 // Parameters for convex hull routine that ships with Bullet
187 public static int CSHullMaxDepthSplit { get; private set; }
188 public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
189 public static float CSHullConcavityThresholdPercent { get; private set; }
190 public static float CSHullVolumeConservationThresholdPercent { get; private set; }
191 public static int CSHullMaxVertices { get; private set; }
192 public static float CSHullMaxSkinWidth { get; private set; }
193 public static float BHullMaxVerticesPerHull { get; private set; } // 100
194 public static float BHullMinClusters { get; private set; } // 2
195 public static float BHullCompacityWeight { get; private set; } // 0.1
196 public static float BHullVolumeWeight { get; private set; } // 0.0
197 public static float BHullConcavity { get; private set; } // 100
198 public static bool BHullAddExtraDistPoints { get; private set; } // false
199 public static bool BHullAddNeighboursDistPoints { get; private set; } // false
200 public static bool BHullAddFacesPoints { get; private set; } // false
201 public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
202 public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD
203 // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd
204 // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1
205 // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
206 public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage
207 public static float VHACDdepth { get; private set; } // 20 max number of clipping stages
208 public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity
209 public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane
210 public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process
211 public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes
212 public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis
213 public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging
214 public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp
215 public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based
216 public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull
217 public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls
218
219 // Linkset implementation parameters
220 public static float LinksetImplementation { get; private set; }
221 public static bool LinksetOffsetCenterOfMass { get; private set; }
222 public static bool LinkConstraintUseFrameOffset { get; private set; }
223 public static bool LinkConstraintEnableTransMotor { get; private set; }
224 public static float LinkConstraintTransMotorMaxVel { get; private set; }
225 public static float LinkConstraintTransMotorMaxForce { get; private set; }
226 public static float LinkConstraintERP { get; private set; }
227 public static float LinkConstraintCFM { get; private set; }
228 public static float LinkConstraintSolverIterations { get; private set; }
229
230 public static float PID_D { get; private set; } // derivative
231 public static float PID_P { get; private set; } // proportional
232
233 // Various constants that come from that other virtual world that shall not be named.
234 public const float MinGravityZ = -1f;
235 public const float MaxGravityZ = 28f;
236 public const float MinFriction = 0f;
237 public const float MaxFriction = 255f;
238 public const float MinDensity = 0.01f;
239 public const float MaxDensity = 22587f;
240 public const float MinRestitution = 0f;
241 public const float MaxRestitution = 1f;
242
243 // =====================================================================================
244 // =====================================================================================
245
246 // Base parameter definition that gets and sets parameter values via a string
247 public abstract class ParameterDefnBase
248 {
249 public string name; // string name of the parameter
250 public string desc; // a short description of what the parameter means
251 public ParameterDefnBase(string pName, string pDesc)
252 {
253 name = pName;
254 desc = pDesc;
255 }
256 // Set the parameter value to the default
257 public abstract void AssignDefault(BSScene s);
258 // Get the value as a string
259 public abstract string GetValue(BSScene s);
260 // Set the value to this string value
261 public abstract void SetValue(BSScene s, string valAsString);
262 // set the value on a particular object (usually sets in physics engine)
263 public abstract void SetOnObject(BSScene s, BSPhysObject obj);
264 public abstract bool HasSetOnObject { get; }
265 }
266
267 // Specific parameter definition for a parameter of a specific type.
268 public delegate T PGetValue<T>(BSScene s);
269 public delegate void PSetValue<T>(BSScene s, T val);
270 public delegate void PSetOnObject<T>(BSScene scene, BSPhysObject obj);
271 public sealed class ParameterDefn<T> : ParameterDefnBase
272 {
273 private T defaultValue;
274 private PSetValue<T> setter;
275 private PGetValue<T> getter;
276 private PSetOnObject<T> objectSet;
277 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter)
278 : base(pName, pDesc)
279 {
280 defaultValue = pDefault;
281 setter = pSetter;
282 getter = pGetter;
283 objectSet = null;
284 }
285 public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue<T> pGetter, PSetValue<T> pSetter, PSetOnObject<T> pObjSetter)
286 : base(pName, pDesc)
287 {
288 defaultValue = pDefault;
289 setter = pSetter;
290 getter = pGetter;
291 objectSet = pObjSetter;
292 }
293 // Simple parameter variable where property name is the same as the INI file name
294 // and the value is only a simple get and set.
295 public ParameterDefn(string pName, string pDesc, T pDefault)
296 : base(pName, pDesc)
297 {
298 defaultValue = pDefault;
299 setter = (s, v) => { SetValueByName(s, name, v); };
300 getter = (s) => { return GetValueByName(s, name); };
301 objectSet = null;
302 }
303 // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
304 private void SetValueByName(BSScene s, string pName, T val)
305 {
306 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
307 if (prop == null)
308 {
309 // This should only be output when someone adds a new INI parameter and misspells the name.
310 s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
311 }
312 else
313 {
314 prop.SetValue(null, val, null);
315 }
316 }
317 // Use reflection to find the property named 'pName' in BSParam and return the value in same.
318 private T GetValueByName(BSScene s, string pName)
319 {
320 PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
321 if (prop == null)
322 {
323 // This should only be output when someone adds a new INI parameter and misspells the name.
324 s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
325 }
326 return (T)prop.GetValue(null, null);
327 }
328 public override void AssignDefault(BSScene s)
329 {
330 setter(s, defaultValue);
331 }
332 public override string GetValue(BSScene s)
333 {
334 return getter(s).ToString();
335 }
336 public override void SetValue(BSScene s, string valAsString)
337 {
338 // Get the generic type of the setter
339 Type genericType = setter.GetType().GetGenericArguments()[0];
340 // Find the 'Parse' method on that type
341 System.Reflection.MethodInfo parser = null;
342 try
343 {
344 parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
345 }
346 catch (Exception e)
347 {
348 s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
349 parser = null;
350 }
351 if (parser != null)
352 {
353 // Parse the input string
354 try
355 {
356 T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
357 // Store the parsed value
358 setter(s, setValue);
359 // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
360 }
361 catch
362 {
363 s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
364 }
365 }
366 else
367 {
368 s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
369 }
370 }
371 public override bool HasSetOnObject
372 {
373 get { return objectSet != null; }
374 }
375 public override void SetOnObject(BSScene s, BSPhysObject obj)
376 {
377 if (objectSet != null)
378 objectSet(s, obj);
379 }
380 }
381
382 // List of all of the externally visible parameters.
383 // For each parameter, this table maps a text name to getter and setters.
384 // To add a new externally referencable/settable parameter, add the paramter storage
385 // location somewhere in the program and make an entry in this table with the
386 // getters and setters.
387 // It is easiest to find an existing definition and copy it.
388 //
389 // A ParameterDefn<T>() takes the following parameters:
390 // -- the text name of the parameter. This is used for console input and ini file.
391 // -- a short text description of the parameter. This shows up in the console listing.
392 // -- a default value
393 // -- a delegate for getting the value
394 // -- a delegate for setting the value
395 // -- an optional delegate to update the value in the world. Most often used to
396 // push the new value to an in-world object.
397 //
398 // The single letter parameters for the delegates are:
399 // s = BSScene
400 // o = BSPhysObject
401 // v = value (appropriate type)
402 private static ParameterDefnBase[] ParameterDefinitions =
403 {
404 new ParameterDefn<bool>("Active", "If 'true', false then physics is not active",
405 false ),
406 new ParameterDefn<bool>("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
407 false ),
408 new ParameterDefn<float>("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
409 0.089f ),
410
411 new ParameterDefn<bool>("MeshSculptedPrim", "Whether to create meshes for sculpties",
412 true,
413 (s) => { return ShouldMeshSculptedPrim; },
414 (s,v) => { ShouldMeshSculptedPrim = v; } ),
415 new ParameterDefn<bool>("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
416 false,
417 (s) => { return ShouldForceSimplePrimMeshing; },
418 (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
419 new ParameterDefn<bool>("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
420 true,
421 (s) => { return ShouldUseHullsForPhysicalObjects; },
422 (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
423 new ParameterDefn<bool>("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
424 true ),
425 new ParameterDefn<bool>("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
426 false ),
427 new ParameterDefn<bool>("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
428 true ),
429 new ParameterDefn<bool>("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
430 false ),
431 new ParameterDefn<bool>("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
432 true ),
433
434 new ParameterDefn<int>("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
435 5 ),
436 new ParameterDefn<float>("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
437 0.1f ),
438
439 new ParameterDefn<float>("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
440 32f,
441 (s) => { return MeshLOD; },
442 (s,v) => { MeshLOD = v; } ),
443 new ParameterDefn<float>("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
444 32f,
445 (s) => { return MeshCircularLOD; },
446 (s,v) => { MeshCircularLOD = v; } ),
447 new ParameterDefn<float>("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
448 10f,
449 (s) => { return MeshMegaPrimThreshold; },
450 (s,v) => { MeshMegaPrimThreshold = v; } ),
451 new ParameterDefn<float>("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
452 32f,
453 (s) => { return MeshMegaPrimLOD; },
454 (s,v) => { MeshMegaPrimLOD = v; } ),
455 new ParameterDefn<float>("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
456 32f,
457 (s) => { return SculptLOD; },
458 (s,v) => { SculptLOD = v; } ),
459
460 new ParameterDefn<int>("MaxSubStep", "In simulation step, maximum number of substeps",
461 10,
462 (s) => { return s.m_maxSubSteps; },
463 (s,v) => { s.m_maxSubSteps = (int)v; } ),
464 new ParameterDefn<float>("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
465 1f / 60f,
466 (s) => { return s.m_fixedTimeStep; },
467 (s,v) => { s.m_fixedTimeStep = v; } ),
468 new ParameterDefn<float>("NominalFrameRate", "The base frame rate we claim",
469 55f,
470 (s) => { return s.NominalFrameRate; },
471 (s,v) => { s.NominalFrameRate = (int)v; } ),
472 new ParameterDefn<int>("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
473 2048,
474 (s) => { return s.m_maxCollisionsPerFrame; },
475 (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
476 new ParameterDefn<int>("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
477 8000,
478 (s) => { return s.m_maxUpdatesPerFrame; },
479 (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
480
481 new ParameterDefn<float>("MinObjectMass", "Minimum object mass (0.0001)",
482 0.0001f,
483 (s) => { return MinimumObjectMass; },
484 (s,v) => { MinimumObjectMass = v; } ),
485 new ParameterDefn<float>("MaxObjectMass", "Maximum object mass (10000.01)",
486 10000.01f,
487 (s) => { return MaximumObjectMass; },
488 (s,v) => { MaximumObjectMass = v; } ),
489 new ParameterDefn<float>("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
490 1000.0f,
491 (s) => { return MaxLinearVelocity; },
492 (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
493 new ParameterDefn<float>("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
494 1000.0f,
495 (s) => { return MaxAngularVelocity; },
496 (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
497 // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
498 new ParameterDefn<float>("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
499 20000.0f,
500 (s) => { return MaxAddForceMagnitude; },
501 (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
502 // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
503 // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
504 new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
505 0.01f ),
506
507 new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
508 2200f ),
509 new ParameterDefn<float>("PID_P", "Parameteric factor for motion smoothing",
510 900f ),
511
512 new ParameterDefn<float>("DefaultFriction", "Friction factor used on new objects",
513 0.2f,
514 (s) => { return DefaultFriction; },
515 (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
516 // For historical reasons, the viewer and simulator multiply the density by 100
517 new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
518 1000.0006836f, // Aluminum g/cm3 * 100
519 (s) => { return DefaultDensity; },
520 (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
521 new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
522 0f,
523 (s) => { return DefaultRestitution; },
524 (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
525 new ParameterDefn<float>("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
526 0.04f,
527 (s) => { return CollisionMargin; },
528 (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
529 new ParameterDefn<float>("Gravity", "Vertical force of gravity (negative means down)",
530 -9.80665f,
531 (s) => { return Gravity; },
532 (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
533 (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
534
535
536 new ParameterDefn<float>("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
537 0f,
538 (s) => { return LinearDamping; },
539 (s,v) => { LinearDamping = v; },
540 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
541 new ParameterDefn<float>("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
542 0f,
543 (s) => { return AngularDamping; },
544 (s,v) => { AngularDamping = v; },
545 (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
546 new ParameterDefn<float>("DeactivationTime", "Seconds before considering an object potentially static",
547 0.2f,
548 (s) => { return DeactivationTime; },
549 (s,v) => { DeactivationTime = v; },
550 (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
551 new ParameterDefn<float>("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
552 0.8f,
553 (s) => { return LinearSleepingThreshold; },
554 (s,v) => { LinearSleepingThreshold = v;},
555 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
556 new ParameterDefn<float>("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
557 1.0f,
558 (s) => { return AngularSleepingThreshold; },
559 (s,v) => { AngularSleepingThreshold = v;},
560 (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
561 new ParameterDefn<float>("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
562 0.0f, // set to zero to disable
563 (s) => { return CcdMotionThreshold; },
564 (s,v) => { CcdMotionThreshold = v;},
565 (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
566 new ParameterDefn<float>("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
567 0.2f,
568 (s) => { return CcdSweptSphereRadius; },
569 (s,v) => { CcdSweptSphereRadius = v;},
570 (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
571 new ParameterDefn<float>("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
572 0.0f,
573 (s) => { return ContactProcessingThreshold; },
574 (s,v) => { ContactProcessingThreshold = v;},
575 (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
576
577 new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
578 (float)BSTerrainPhys.TerrainImplementation.Heightmap ),
579 new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
580 2 ),
581 new ParameterDefn<float>("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" ,
582 -500.0f ),
583 new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
584 0.3f ),
585 new ParameterDefn<float>("TerrainHitFraction", "Distance to measure hit collisions" ,
586 0.8f ),
587 new ParameterDefn<float>("TerrainRestitution", "Bouncyness" ,
588 0f ),
589 new ParameterDefn<float>("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
590 0.0f ),
591 new ParameterDefn<float>("TerrainCollisionMargin", "Margin where collision checking starts" ,
592 0.04f ),
593
594 new ParameterDefn<bool>("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?",
595 true),
596 new ParameterDefn<float>("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
597 0.2f ),
598 new ParameterDefn<float>("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
599 0.95f ),
600 new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
601 1.3f ),
602 // For historical reasons, density is reported * 100
603 new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
604 3500f) , // 3.5 * 100
605 new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
606 0f ),
607 new ParameterDefn<int>("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh",
608 BSShapeCollection.AvatarShapeCube ) ,
609 new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
610 0.6f ) ,
611 new ParameterDefn<float>("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
612 0.45f ),
613 new ParameterDefn<float>("AvatarCapsuleHeight", "Default height of space around avatar",
614 1.5f ),
615 new ParameterDefn<float>("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
616 0f ),
617 new ParameterDefn<float>("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
618 0f ),
619 new ParameterDefn<float>("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
620 0f ),
621 new ParameterDefn<float>("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying",
622 5f ),
623 new ParameterDefn<float>("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin",
624 2.0f ),
625 new ParameterDefn<float>("AvatarTerminalVelocity", "Terminal Velocity of falling avatar",
626 -54.0f ),
627 new ParameterDefn<float>("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
628 0.1f ),
629 new ParameterDefn<float>("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
630 0.1f ),
631 new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
632 1.0f ),
633 new ParameterDefn<int>("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
634 4 ),
635 new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
636 0.999f ) ,
637 new ParameterDefn<float>("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step",
638 0.3f ) ,
639 new ParameterDefn<float>("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height",
640 0.1f ) ,
641 new ParameterDefn<float>("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
642 2f ),
643 new ParameterDefn<float>("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
644 0f ),
645 new ParameterDefn<float>("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
646 0.8f ),
647 new ParameterDefn<int>("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
648 1 ),
649
650 new ParameterDefn<float>("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
651 1000.0f,
652 (s) => { return (float)VehicleMaxLinearVelocity; },
653 (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
654 new ParameterDefn<float>("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
655 0.001f,
656 (s) => { return (float)VehicleMinLinearVelocity; },
657 (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ),
658 new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
659 12.0f,
660 (s) => { return (float)VehicleMaxAngularVelocity; },
661 (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
662 new ParameterDefn<float>("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
663 0.0f ),
664 new ParameterDefn<Vector3>("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
665 new Vector3(1f, 1f, 1f) ),
666 new ParameterDefn<Vector3>("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
667 new Vector3(1f, 1f, 1f) ),
668 new ParameterDefn<Vector3>("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
669 new Vector3(1f, 1f, 1f) ),
670 new ParameterDefn<float>("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
671 0.0f ),
672 new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
673 0.0f ),
674 new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
675 0.2f ),
676 new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
677 60.0f ),
678 new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
679 true ),
680 new ParameterDefn<bool>("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles",
681 true ),
682 new ParameterDefn<bool>("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect",
683 true ),
684 new ParameterDefn<int>("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.",
685 0 ),
686 new ParameterDefn<bool>("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect",
687 true ),
688 new ParameterDefn<bool>("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect",
689 true ),
690
691 new ParameterDefn<float>("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
692 0f,
693 (s) => { return MaxPersistantManifoldPoolSize; },
694 (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
695 new ParameterDefn<float>("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
696 0f,
697 (s) => { return MaxCollisionAlgorithmPoolSize; },
698 (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
699 new ParameterDefn<bool>("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
700 false,
701 (s) => { return ShouldDisableContactPoolDynamicAllocation; },
702 (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
703 s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
704 new ParameterDefn<bool>("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
705 false,
706 (s) => { return ShouldForceUpdateAllAabbs; },
707 (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
708 new ParameterDefn<bool>("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
709 true,
710 (s) => { return ShouldRandomizeSolverOrder; },
711 (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
712 new ParameterDefn<bool>("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
713 true,
714 (s) => { return ShouldSplitSimulationIslands; },
715 (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
716 new ParameterDefn<bool>("ShouldEnableFrictionCaching", "Enable friction computation caching",
717 true,
718 (s) => { return ShouldEnableFrictionCaching; },
719 (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
720 new ParameterDefn<float>("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
721 0f, // zero says use Bullet default
722 (s) => { return NumberOfSolverIterations; },
723 (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
724 new ParameterDefn<bool>("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
725 true,
726 (s) => { return UseSingleSidedMeshes; },
727 (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
728 new ParameterDefn<float>("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
729 0f,
730 (s) => { return GlobalContactBreakingThreshold; },
731 (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
732 new ParameterDefn<float>("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics",
733 0f,
734 (s) => { return PhysicsUnmanLoggingFrames; },
735 (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ),
736
737 new ParameterDefn<int>("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
738 7 ),
739 new ParameterDefn<int>("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
740 2 ),
741 new ParameterDefn<float>("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
742 5f ),
743 new ParameterDefn<float>("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
744 5f ),
745 new ParameterDefn<int>("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
746 32 ),
747 new ParameterDefn<float>("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
748 0f ),
749
750 new ParameterDefn<float>("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
751 200f ),
752 new ParameterDefn<float>("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
753 10f ),
754 new ParameterDefn<float>("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
755 20f ),
756 new ParameterDefn<float>("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
757 0.1f ),
758 new ParameterDefn<float>("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
759 10f ),
760 new ParameterDefn<bool>("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
761 true ),
762 new ParameterDefn<bool>("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
763 true ),
764 new ParameterDefn<bool>("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
765 true ),
766 new ParameterDefn<bool>("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
767 false ),
768
769 new ParameterDefn<float>("WhichHACD", "zero if Bullet HACD, non-zero says VHACD",
770 0f ),
771 new ParameterDefn<float>("VHACDresolution", "max number of voxels generated during voxelization stage",
772 100000f ),
773 new ParameterDefn<float>("VHACDdepth", "max number of clipping stages",
774 20f ),
775 new ParameterDefn<float>("VHACDconcavity", "maximum concavity",
776 0.0025f ),
777 new ParameterDefn<float>("VHACDplaneDownsampling", "granularity of search for best clipping plane",
778 4f ),
779 new ParameterDefn<float>("VHACDconvexHullDownsampling", "precision of hull gen process",
780 4f ),
781 new ParameterDefn<float>("VHACDalpha", "bias toward clipping along symmetry planes",
782 0.05f ),
783 new ParameterDefn<float>("VHACDbeta", "bias toward clipping along revolution axis",
784 0.05f ),
785 new ParameterDefn<float>("VHACDgamma", "max concavity when merging",
786 0.00125f ),
787 new ParameterDefn<float>("VHACDpca", "on/off normalizing mesh before decomp",
788 0f ),
789 new ParameterDefn<float>("VHACDmode", "0:voxel based, 1: tetrahedron based",
790 0f ),
791 new ParameterDefn<float>("VHACDmaxNumVerticesPerCH", "max triangles per convex hull",
792 64f ),
793 new ParameterDefn<float>("VHACDminVolumePerCH", "sampling of generated convex hulls",
794 0.0001f ),
795
796 new ParameterDefn<float>("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
797 (float)BSLinkset.LinksetImplementation.Compound ),
798 new ParameterDefn<bool>("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
799 true ),
800 new ParameterDefn<bool>("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
801 false ),
802 new ParameterDefn<bool>("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
803 true ),
804 new ParameterDefn<float>("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
805 5.0f ),
806 new ParameterDefn<float>("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
807 0.1f ),
808 new ParameterDefn<float>("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
809 0.1f ),
810 new ParameterDefn<float>("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
811 0.1f ),
812 new ParameterDefn<float>("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
813 40 ),
814
815 new ParameterDefn<int>("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
816 0,
817 (s) => { return s.PhysicsMetricDumpFrames; },
818 (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
819 new ParameterDefn<float>("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
820 0f,
821 (s) => { return 0f; },
822 (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ),
823 new ParameterDefn<float>("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
824 0f,
825 (s) => { return 0f; },
826 (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
827 };
828
829 // Convert a boolean to our numeric true and false values
830 public static float NumericBool(bool b)
831 {
832 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
833 }
834
835 // Convert numeric true and false values to a boolean
836 public static bool BoolNumeric(float b)
837 {
838 return (b == ConfigurationParameters.numericTrue ? true : false);
839 }
840
841 // Search through the parameter definitions and return the matching
842 // ParameterDefn structure.
843 // Case does not matter as names are compared after converting to lower case.
844 // Returns 'false' if the parameter is not found.
845 internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
846 {
847 bool ret = false;
848 ParameterDefnBase foundDefn = null;
849 string pName = paramName.ToLower();
850
851 foreach (ParameterDefnBase parm in ParameterDefinitions)
852 {
853 if (pName == parm.name.ToLower())
854 {
855 foundDefn = parm;
856 ret = true;
857 break;
858 }
859 }
860 defn = foundDefn;
861 return ret;
862 }
863
864 // Pass through the settable parameters and set the default values
865 internal static void SetParameterDefaultValues(BSScene physicsScene)
866 {
867 foreach (ParameterDefnBase parm in ParameterDefinitions)
868 {
869 parm.AssignDefault(physicsScene);
870 }
871 }
872
873 // Get user set values out of the ini file.
874 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
875 {
876 foreach (ParameterDefnBase parm in ParameterDefinitions)
877 {
878 parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
879 }
880 }
881
882 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
883
884 // This creates an array in the correct format for returning the list of
885 // parameters. This is used by the 'list' option of the 'physics' command.
886 internal static void BuildParameterTable()
887 {
888 if (SettableParameters.Length < ParameterDefinitions.Length)
889 {
890 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
891 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
892 {
893 ParameterDefnBase pd = ParameterDefinitions[ii];
894 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
895 }
896
897 // make the list alphabetical for ease of finding anything
898 entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
899
900 SettableParameters = entries.ToArray();
901 }
902 }
903
904 // =====================================================================
905 // =====================================================================
906 // There are parameters that, when set, cause things to happen in the physics engine.
907 // This causes the broadphase collision cache to be cleared.
908 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime)
909 {
910 BSScene physScene = pPhysScene;
911 physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate()
912 {
913 physScene.PE.ResetBroadphasePool(physScene.World);
914 });
915 }
916
917 // This causes the constraint solver cache to be cleared and reset.
918 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
919 {
920 BSScene physScene = pPhysScene;
921 physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
922 {
923 physScene.PE.ResetConstraintSolver(physScene.World);
924 });
925 }
926}
927}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
new file mode 100755
index 0000000..da3fc18
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
@@ -0,0 +1,620 @@
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
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
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.
46 * The last one should only be referenced in taint-time.
47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
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}
68public abstract class BSPhysObject : PhysicsActor
69{
70 protected BSPhysObject()
71 {
72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 {
75 IsInitialized = false;
76
77 PhysScene = parentScene;
78 LocalID = localID;
79 PhysObjectName = name;
80 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
81 TypeName = typeName;
82
83 // Oddity if object is destroyed and recreated very quickly it could still have the old body.
84 if (!PhysBody.HasPhysicalBody)
85 PhysBody = new BulletBody(localID);
86
87 // Clean out anything that might be in the physical actor list.
88 // Again, a workaround for destroying and recreating an object very quickly.
89 PhysicalActors.Dispose();
90
91 UserSetCenterOfMassDisplacement = null;
92
93 PrimAssetState = PrimAssetCondition.Unknown;
94
95 // Initialize variables kept in base.
96 // Beware that these cause taints to be queued whch can cause race conditions on startup.
97 GravModifier = 1.0f;
98 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
99 HoverActive = false;
100
101 // Default material type. Also sets Friction, Restitution and Density.
102 SetMaterial((int)MaterialAttributes.Material.Wood);
103
104 CollisionsLastTickStep = -1;
105
106 SubscribedEventsMs = 0;
107 // Crazy values that will never be true
108 CollidingStep = BSScene.NotASimulationStep;
109 CollidingGroundStep = BSScene.NotASimulationStep;
110 CollisionAccumulation = BSScene.NotASimulationStep;
111 ColliderIsMoving = false;
112 CollisionScore = 0;
113
114 // All axis free.
115 LockedLinearAxis = LockedAxisFree;
116 LockedAngularAxis = LockedAxisFree;
117 }
118
119 // Tell the object to clean up.
120 public virtual void Destroy()
121 {
122 PhysicalActors.Enable(false);
123 PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
124 {
125 PhysicalActors.Dispose();
126 });
127 }
128
129 public BSScene PhysScene { get; protected set; }
130 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
131 public string PhysObjectName { get; protected set; }
132 public string TypeName { get; protected set; }
133
134 // Set to 'true' when the object is completely initialized.
135 // This mostly prevents property updates and collisions until the object is completely here.
136 public bool IsInitialized { get; protected set; }
137
138 // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed.
139 // This test is used to prevent some updates to the object when it only partially exists.
140 // There are several reasons and object might be incomplete:
141 // Its underlying mesh/sculpty is an asset which must be fetched from the asset store
142 // It is a linkset who is being added to or removed from
143 // It is changing state (static to physical, for instance) which requires rebuilding
144 // This is a computed value based on the underlying physical object construction
145 abstract public bool IsIncomplete { get; }
146
147 // Return the object mass without calculating it or having side effects
148 public abstract float RawMass { get; }
149 // Set the raw mass but also update physical mass properties (inertia, ...)
150 // 'inWorld' true if the object has already been added to the dynamic world.
151 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
152
153 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
154 public virtual OMV.Vector3 Gravity { get; set; }
155 // The last value calculated for the prim's inertia
156 public OMV.Vector3 Inertia { get; set; }
157
158 // Reference to the physical body (btCollisionObject) of this object
159 public BulletBody PhysBody = new BulletBody(0);
160 // Reference to the physical shape (btCollisionShape) of this object
161 public BSShape PhysShape = new BSShapeNull();
162
163 // The physical representation of the prim might require an asset fetch.
164 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
165 public enum PrimAssetCondition
166 {
167 Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
168 }
169 public PrimAssetCondition PrimAssetState { get; set; }
170 public virtual bool AssetFailed()
171 {
172 return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch)
173 || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) );
174 }
175
176 // The objects base shape information. Null if not a prim type shape.
177 public PrimitiveBaseShape BaseShape { get; protected set; }
178
179 // When the physical properties are updated, an EntityProperty holds the update values.
180 // Keep the current and last EntityProperties to enable computation of differences
181 // between the current update and the previous values.
182 public EntityProperties CurrentEntityProperties { get; set; }
183 public EntityProperties LastEntityProperties { get; set; }
184
185 public virtual OMV.Vector3 Scale { get; set; }
186
187 // It can be confusing for an actor to know if it should move or update an object
188 // depeneding on the setting of 'selected', 'physical, ...
189 // This flag is the true test -- if true, the object is being acted on in the physical world
190 public abstract bool IsPhysicallyActive { get; }
191
192 // Detailed state of the object.
193 public abstract bool IsSolid { get; }
194 public abstract bool IsStatic { get; }
195 public abstract bool IsSelected { get; }
196 public abstract bool IsVolumeDetect { get; }
197
198 // Materialness
199 public MaterialAttributes.Material Material { get; private set; }
200 public override void SetMaterial(int material)
201 {
202 Material = (MaterialAttributes.Material)material;
203
204 // Setting the material sets the material attributes also.
205 // TODO: decide if this is necessary -- the simulator does this.
206 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
207 Friction = matAttrib.friction;
208 Restitution = matAttrib.restitution;
209 Density = matAttrib.density;
210 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
211 }
212
213 public override float Density
214 {
215 get
216 {
217 return base.Density;
218 }
219 set
220 {
221 DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
222 base.Density = value;
223 }
224 }
225
226 // Stop all physical motion.
227 public abstract void ZeroMotion(bool inTaintTime);
228 public abstract void ZeroAngularMotion(bool inTaintTime);
229
230 // Update the physical location and motion of the object. Called with data from Bullet.
231 public abstract void UpdateProperties(EntityProperties entprop);
232
233 public virtual OMV.Vector3 RawPosition { get; set; }
234 public abstract OMV.Vector3 ForcePosition { get; set; }
235
236 public virtual OMV.Quaternion RawOrientation { get; set; }
237 public abstract OMV.Quaternion ForceOrientation { get; set; }
238
239 public virtual OMV.Vector3 RawVelocity { get; set; }
240 public abstract OMV.Vector3 ForceVelocity { get; set; }
241
242 public OMV.Vector3 RawForce { get; set; }
243 public OMV.Vector3 RawTorque { get; set; }
244 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
245 {
246 AddAngularForce(force, pushforce, false);
247 }
248 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
249 public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
250
251 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
252
253 public abstract float ForceBuoyancy { get; set; }
254
255 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
256
257 public override bool PIDActive
258 {
259 get { return MoveToTargetActive; }
260 set { MoveToTargetActive = value; }
261 }
262
263 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
264 public override float PIDTau { set { MoveToTargetTau = value; } }
265
266 public bool MoveToTargetActive { get; set; }
267 public OMV.Vector3 MoveToTargetTarget { get; set; }
268 public float MoveToTargetTau { get; set; }
269
270 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
271 public override bool PIDHoverActive { set { HoverActive = value; } }
272 public override float PIDHoverHeight { set { HoverHeight = value; } }
273 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
274 public override float PIDHoverTau { set { HoverTau = value; } }
275
276 public bool HoverActive { get; set; }
277 public float HoverHeight { get; set; }
278 public PIDHoverType HoverType { get; set; }
279 public float HoverTau { get; set; }
280
281 // For RotLookAt
282 public override OMV.Quaternion APIDTarget { set { return; } }
283 public override bool APIDActive { set { return; } }
284 public override float APIDStrength { set { return; } }
285 public override float APIDDamping { set { return; } }
286
287 // The current velocity forward
288 public virtual float ForwardSpeed
289 {
290 get
291 {
292 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
293 return characterOrientedVelocity.X;
294 }
295 }
296 // The forward speed we are trying to achieve (TargetVelocity)
297 public virtual float TargetVelocitySpeed
298 {
299 get
300 {
301 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
302 return characterOrientedVelocity.X;
303 }
304 }
305
306 // The user can optionally set the center of mass. The user's setting will override any
307 // computed center-of-mass (like in linksets).
308 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
309 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
310
311 public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
312 public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
313 public const float FreeAxis = 1f;
314 public const float LockedAxis = 0f;
315 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
316
317 // If an axis is locked (flagged above) then the limits of that axis are specified here.
318 // Linear axis limits are relative to the object's starting coordinates.
319 // Angular limits are limited to -PI to +PI
320 public OMV.Vector3 LockedLinearAxisLow;
321 public OMV.Vector3 LockedLinearAxisHigh;
322 public OMV.Vector3 LockedAngularAxisLow;
323 public OMV.Vector3 LockedAngularAxisHigh;
324
325 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
326 // they need waking up when parameters are changed.
327 // Called in taint-time!!
328 public void ActivateIfPhysical(bool forceIt)
329 {
330 if (PhysBody.HasPhysicalBody)
331 {
332 if (IsPhysical)
333 {
334 // Physical objects might need activating
335 PhysScene.PE.Activate(PhysBody, forceIt);
336 }
337 else
338 {
339 // Clear the collision cache since we've changed some properties.
340 PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
341 }
342 }
343 }
344
345 // 'actors' act on the physical object to change or constrain its motion. These can range from
346 // hovering to complex vehicle motion.
347 // May be called at non-taint time as this just adds the actor to the action list and the real
348 // work is done during the simulation step.
349 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
350 // in the list disabled.
351 public delegate BSActor CreateActor();
352 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
353 {
354 lock (PhysicalActors)
355 {
356 BSActor theActor;
357 if (PhysicalActors.TryGetActor(actorName, out theActor))
358 {
359 // The actor already exists so just turn it on or off
360 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
361 theActor.Enabled = enableActor;
362 }
363 else
364 {
365 // The actor does not exist. If it should, create it.
366 if (enableActor)
367 {
368 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
369 theActor = creator();
370 PhysicalActors.Add(actorName, theActor);
371 theActor.Enabled = true;
372 }
373 else
374 {
375 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
376 }
377 }
378 }
379 }
380
381 #region Collisions
382
383 // Requested number of milliseconds between collision events. Zero means disabled.
384 protected int SubscribedEventsMs { get; set; }
385 // Given subscription, the time that a collision may be passed up
386 protected int NextCollisionOkTime { get; set; }
387 // The simulation step that last had a collision
388 protected long CollidingStep { get; set; }
389 // The simulation step that last had a collision with the ground
390 protected long CollidingGroundStep { get; set; }
391 // The simulation step that last collided with an object
392 protected long CollidingObjectStep { get; set; }
393 // The collision flags we think are set in Bullet
394 protected CollisionFlags CurrentCollisionFlags { get; set; }
395 // On a collision, check the collider and remember if the last collider was moving
396 // Used to modify the standing of avatars (avatars on stationary things stand still)
397 public bool ColliderIsMoving;
398 // 'true' if the last collider was a volume detect object
399 public bool ColliderIsVolumeDetect;
400 // Used by BSCharacter to manage standing (and not slipping)
401 public bool IsStationary;
402
403 // Count of collisions for this object
404 protected long CollisionAccumulation { get; set; }
405
406 public override bool IsColliding {
407 get { return (CollidingStep == PhysScene.SimulationStep); }
408 set {
409 if (value)
410 CollidingStep = PhysScene.SimulationStep;
411 else
412 CollidingStep = BSScene.NotASimulationStep;
413 }
414 }
415 // Complex objects (like linksets) need to know if there is a collision on any part of
416 // their shape. 'IsColliding' has an existing definition of reporting a collision on
417 // only this specific prim or component of linksets.
418 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
419 // the complex body that this prim is the root of.
420 public virtual bool HasSomeCollision
421 {
422 get { return IsColliding; }
423 set { IsColliding = value; }
424 }
425 public override bool CollidingGround {
426 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
427 set
428 {
429 if (value)
430 CollidingGroundStep = PhysScene.SimulationStep;
431 else
432 CollidingGroundStep = BSScene.NotASimulationStep;
433 }
434 }
435 public override bool CollidingObj {
436 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
437 set {
438 if (value)
439 CollidingObjectStep = PhysScene.SimulationStep;
440 else
441 CollidingObjectStep = BSScene.NotASimulationStep;
442 }
443 }
444
445 // The collisions that have been collected for the next collision reporting (throttled by subscription)
446 protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
447 // This is the collision collection last reported to the Simulator.
448 public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
449 // Remember the collisions recorded in the last tick for fancy collision checking
450 // (like a BSCharacter walking up stairs).
451 public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
452 private long CollisionsLastTickStep = -1;
453
454 // The simulation step is telling this object about a collision.
455 // Return 'true' if a collision was processed and should be sent up.
456 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
457 // Called at taint time from within the Step() function
458 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
459 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
460 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
461 {
462 bool ret = false;
463
464 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
465 CollidingStep = PhysScene.SimulationStep;
466 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
467 {
468 CollidingGroundStep = PhysScene.SimulationStep;
469 }
470 else
471 {
472 CollidingObjectStep = PhysScene.SimulationStep;
473 }
474
475 CollisionAccumulation++;
476
477 // For movement tests, remember if we are colliding with an object that is moving.
478 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
479 ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
480
481 // Make a collection of the collisions that happened the last simulation tick.
482 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
483 if (CollisionsLastTickStep != PhysScene.SimulationStep)
484 {
485 CollisionsLastTick = new CollisionEventUpdate();
486 CollisionsLastTickStep = PhysScene.SimulationStep;
487 }
488 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
489
490 // If someone has subscribed for collision events log the collision so it will be reported up
491 if (SubscribedEvents()) {
492 lock (PhysScene.CollisionLock)
493 {
494 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
495 }
496 DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
497 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
498
499 ret = true;
500 }
501 return ret;
502 }
503
504 // Send the collected collisions into the simulator.
505 // Called at taint time from within the Step() function thus no locking problems
506 // with CollisionCollection and ObjectsWithNoMoreCollisions.
507 // Called with BSScene.CollisionLock locked to protect the collision lists.
508 // Return 'true' if there were some actual collisions passed up
509 public virtual bool SendCollisions()
510 {
511 bool ret = true;
512
513 // If no collisions this call but there were collisions last call, force the collision
514 // event to be happen right now so quick collision_end.
515 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
516
517 // throttle the collisions to the number of milliseconds specified in the subscription
518 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
519 {
520 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
521
522 // We are called if we previously had collisions. If there are no collisions
523 // this time, send up one last empty event so OpenSim can sense collision end.
524 if (CollisionCollection.Count == 0)
525 {
526 // If I have no collisions this time, remove me from the list of objects with collisions.
527 ret = false;
528 }
529
530 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
531 base.SendCollisionUpdate(CollisionCollection);
532
533 // Remember the collisions from this tick for some collision specific processing.
534 CollisionsLastReported = CollisionCollection;
535
536 // The CollisionCollection instance is passed around in the simulator.
537 // Make sure we don't have a handle to that one and that a new one is used for next time.
538 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
539 // a race condition is created for the other users of this instance.
540 CollisionCollection = new CollisionEventUpdate();
541 }
542 return ret;
543 }
544
545 // Subscribe for collision events.
546 // Parameter is the millisecond rate the caller wishes collision events to occur.
547 public override void SubscribeEvents(int ms) {
548 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
549 SubscribedEventsMs = ms;
550 if (ms > 0)
551 {
552 // make sure first collision happens
553 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
554
555 PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
556 {
557 if (PhysBody.HasPhysicalBody)
558 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
559 });
560 }
561 else
562 {
563 // Subscribing for zero or less is the same as unsubscribing
564 UnSubscribeEvents();
565 }
566 }
567 public override void UnSubscribeEvents() {
568 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
569 SubscribedEventsMs = 0;
570 PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
571 {
572 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
573 if (PhysBody.HasPhysicalBody)
574 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
575 });
576 }
577 // Return 'true' if the simulator wants collision events
578 public override bool SubscribedEvents() {
579 return (SubscribedEventsMs > 0);
580 }
581 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
582 // each time called. So this is built to be light weight for each collision and to do
583 // all the processing when the user asks for the info.
584 public void ComputeCollisionScore()
585 {
586 // Scale the collision count by the time since the last collision.
587 // The "+1" prevents dividing by zero.
588 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
589 CollisionScore = CollisionAccumulation / timeAgo;
590 }
591 public override float CollisionScore { get; set; }
592
593 #endregion // Collisions
594
595 #region Per Simulation Step actions
596
597 public BSActorCollection PhysicalActors = new BSActorCollection();
598
599 // When an update to the physical properties happens, this event is fired to let
600 // different actors to modify the update before it is passed around
601 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
602 public event PreUpdatePropertyAction OnPreUpdateProperty;
603 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
604 {
605 PreUpdatePropertyAction actions = OnPreUpdateProperty;
606 if (actions != null)
607 actions(ref entprop);
608 }
609
610 #endregion // Per Simulation Step actions
611
612 // High performance detailed logging routine used by the physical objects.
613 protected void DetailLog(string msg, params Object[] args)
614 {
615 if (PhysScene.PhysicsLogging.Enabled)
616 PhysScene.DetailLog(msg, args);
617 }
618
619}
620}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..6f27ac7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1895 @@
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.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.PhysicsModules.SharedBase;
36using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40
41 [Serializable]
42public class BSPrim : BSPhysObject
43{
44 protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 private static readonly string LogHeader = "[BULLETS PRIM]";
46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
49
50 private bool _grabbed;
51 private bool _isSelected;
52 private bool _isVolumeDetect;
53
54 private float _mass; // the mass of this object
55 private OMV.Vector3 _acceleration;
56 private int _physicsActorType;
57 private bool _isPhysical;
58 private bool _flying;
59 private bool _setAlwaysRun;
60 private bool _throttleUpdates;
61 private bool _floatOnWater;
62 private OMV.Vector3 _rotationalVelocity;
63 private bool _kinematic;
64 private float _buoyancy;
65
66 private int CrossingFailures { get; set; }
67
68 // Keep a handle to the vehicle actor so it is easy to set parameters on same.
69 public const string VehicleActorName = "BasicVehicle";
70
71 // Parameters for the hover actor
72 public const string HoverActorName = "BSPrim.HoverActor";
73 // Parameters for the axis lock actor
74 public const String LockedAxisActorName = "BSPrim.LockedAxis";
75 // Parameters for the move to target actor
76 public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
77 // Parameters for the setForce and setTorque actors
78 public const string SetForceActorName = "BSPrim.SetForceActor";
79 public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
80
81 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
82 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
83 : base(parent_scene, localID, primName, "BSPrim")
84 {
85 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
86 _physicsActorType = (int)ActorTypes.Prim;
87 RawPosition = pos;
88 _size = size;
89 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
90 RawOrientation = rotation;
91 _buoyancy = 0f;
92 RawVelocity = OMV.Vector3.Zero;
93 _rotationalVelocity = OMV.Vector3.Zero;
94 BaseShape = pbs;
95 _isPhysical = pisPhysical;
96 _isVolumeDetect = false;
97
98 _mass = CalculateMass();
99
100 DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
101 // DetailLog("{0},BSPrim.constructor,call", LocalID);
102 // do the actual object creation at taint time
103 PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
104 {
105 // Make sure the object is being created with some sanity.
106 ExtremeSanityCheck(true /* inTaintTime */);
107
108 CreateGeomAndObject(true);
109
110 CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
111
112 IsInitialized = true;
113 });
114 }
115
116 // called when this prim is being destroyed and we should free all the resources
117 public override void Destroy()
118 {
119 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
120 IsInitialized = false;
121
122 base.Destroy();
123
124 // Undo any vehicle properties
125 this.VehicleType = (int)Vehicle.TYPE_NONE;
126
127 PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
128 {
129 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
130 // If there are physical body and shape, release my use of same.
131 PhysScene.Shapes.DereferenceBody(PhysBody, null);
132 PhysBody.Clear();
133 PhysShape.Dereference(PhysScene);
134 PhysShape = new BSShapeNull();
135 });
136 }
137
138 // No one uses this property.
139 public override bool Stopped {
140 get { return false; }
141 }
142
143 public override bool IsIncomplete {
144 get {
145 return ShapeRebuildScheduled;
146 }
147 }
148
149 // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
150 // The prim is still available but its underlying shape will change soon.
151 // This is protected by a 'lock(this)'.
152 public bool ShapeRebuildScheduled { get; protected set; }
153
154 public override OMV.Vector3 Size {
155 get { return _size; }
156 set {
157 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built.
159 _size = value;
160 Scale = _size;
161 ForceBodyShapeRebuild(false);
162 }
163 }
164
165 public override PrimitiveBaseShape Shape {
166 set {
167 BaseShape = value;
168 DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
169 PrimAssetState = PrimAssetCondition.Unknown;
170 ForceBodyShapeRebuild(false);
171 }
172 }
173 // Cause the body and shape of the prim to be rebuilt if necessary.
174 // If there are no changes required, this is quick and does not make changes to the prim.
175 // If rebuilding is necessary (like changing from static to physical), that will happen.
176 // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
177 // The return parameter is not used by anyone.
178 public override bool ForceBodyShapeRebuild(bool inTaintTime)
179 {
180 if (inTaintTime)
181 {
182 // If called in taint time, do the operation immediately
183 _mass = CalculateMass(); // changing the shape changes the mass
184 CreateGeomAndObject(true);
185 }
186 else
187 {
188 lock (this)
189 {
190 // If a rebuild is not already in the queue
191 if (!ShapeRebuildScheduled)
192 {
193 // Remember that a rebuild is queued -- this is used to flag an incomplete object
194 ShapeRebuildScheduled = true;
195 PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
196 {
197 _mass = CalculateMass(); // changing the shape changes the mass
198 CreateGeomAndObject(true);
199 ShapeRebuildScheduled = false;
200 });
201 }
202 }
203 }
204 return true;
205 }
206 public override bool Grabbed {
207 set { _grabbed = value;
208 }
209 }
210 public override bool Selected {
211 set
212 {
213 if (value != _isSelected)
214 {
215 _isSelected = value;
216 PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
217 {
218 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
219 SetObjectDynamic(false);
220 });
221 }
222 }
223 }
224 public override bool IsSelected
225 {
226 get { return _isSelected; }
227 }
228
229 public override void CrossingFailure()
230 {
231 CrossingFailures++;
232 if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
233 {
234 base.RaiseOutOfBounds(RawPosition);
235 }
236 else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
237 {
238 m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
239 }
240 return;
241 }
242
243 // link me to the specified parent
244 public override void link(PhysicsActor obj) {
245 }
246
247 // delink me from my linkset
248 public override void delink() {
249 }
250
251 // Set motion values to zero.
252 // Do it to the properties so the values get set in the physics engine.
253 // Push the setting of the values to the viewer.
254 // Called at taint time!
255 public override void ZeroMotion(bool inTaintTime)
256 {
257 RawVelocity = OMV.Vector3.Zero;
258 _acceleration = OMV.Vector3.Zero;
259 _rotationalVelocity = OMV.Vector3.Zero;
260
261 // Zero some other properties in the physics engine
262 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
263 {
264 if (PhysBody.HasPhysicalBody)
265 PhysScene.PE.ClearAllForces(PhysBody);
266 });
267 }
268 public override void ZeroAngularMotion(bool inTaintTime)
269 {
270 _rotationalVelocity = OMV.Vector3.Zero;
271 // Zero some other properties in the physics engine
272 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
273 {
274 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
275 if (PhysBody.HasPhysicalBody)
276 {
277 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
278 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
279 }
280 });
281 }
282
283 public override void LockAngularMotion(OMV.Vector3 axis)
284 {
285 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
286
287 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
288 if (axis.X != 1)
289 {
290 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
291 }
292 if (axis.Y != 1)
293 {
294 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
295 }
296 if (axis.Z != 1)
297 {
298 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
299 }
300
301 InitializeAxisActor();
302
303 return;
304 }
305
306 public override OMV.Vector3 Position {
307 get {
308 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
309 // RawPosition = ForcePosition;
310 return RawPosition;
311 }
312 set {
313 // If the position must be forced into the physics engine, use ForcePosition.
314 // All positions are given in world positions.
315 if (RawPosition == value)
316 {
317 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
318 return;
319 }
320 RawPosition = value;
321 PositionSanityCheck(false);
322
323 PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
324 {
325 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
326 ForcePosition = RawPosition;
327 });
328 }
329 }
330
331 // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
332 public override OMV.Vector3 ForcePosition {
333 get {
334 RawPosition = PhysScene.PE.GetPosition(PhysBody);
335 return RawPosition;
336 }
337 set {
338 RawPosition = value;
339 if (PhysBody.HasPhysicalBody)
340 {
341 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
342 ActivateIfPhysical(false);
343 }
344 }
345 }
346
347 // Check that the current position is sane and, if not, modify the position to make it so.
348 // Check for being below terrain and being out of bounds.
349 // Returns 'true' of the position was made sane by some action.
350 private bool PositionSanityCheck(bool inTaintTime)
351 {
352 bool ret = false;
353
354 // We don't care where non-physical items are placed
355 if (!IsPhysicallyActive)
356 return ret;
357
358 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
359 {
360 // The physical object is out of the known/simulated area.
361 // Upper levels of code will handle the transition to other areas so, for
362 // the time, we just ignore the position.
363 return ret;
364 }
365
366 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
367 OMV.Vector3 upForce = OMV.Vector3.Zero;
368 float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
369 if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
370 {
371 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
372 float targetHeight = terrainHeight + (Size.Z / 2f);
373 // If the object is below ground it just has to be moved up because pushing will
374 // not get it through the terrain
375 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
376 if (inTaintTime)
377 {
378 ForcePosition = RawPosition;
379 }
380 // If we are throwing the object around, zero its other forces
381 ZeroMotion(inTaintTime);
382 ret = true;
383 }
384
385 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
386 {
387 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
388 // TODO: a floating motor so object will bob in the water
389 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
390 {
391 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
392 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
393
394 // Apply upforce and overcome gravity.
395 OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
396 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
397 AddForce(correctionForce, false, inTaintTime);
398 ret = true;
399 }
400 }
401
402 return ret;
403 }
404
405 // Occasionally things will fly off and really get lost.
406 // Find the wanderers and bring them back.
407 // Return 'true' if some parameter need some sanity.
408 private bool ExtremeSanityCheck(bool inTaintTime)
409 {
410 bool ret = false;
411
412 int wayOverThere = -1000;
413 int wayOutThere = 10000;
414 // There have been instances of objects getting thrown way out of bounds and crashing
415 // the border crossing code.
416 if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
417 || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
418 || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
419 {
420 RawPosition = new OMV.Vector3(10, 10, 50);
421 ZeroMotion(inTaintTime);
422 ret = true;
423 }
424 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
425 {
426 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
427 ret = true;
428 }
429 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
430 {
431 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
432 ret = true;
433 }
434
435 return ret;
436 }
437
438 // Return the effective mass of the object.
439 // The definition of this call is to return the mass of the prim.
440 // If the simulator cares about the mass of the linkset, it will sum it itself.
441 public override float Mass
442 {
443 get { return _mass; }
444 }
445 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
446 public virtual float TotalMass
447 {
448 get { return _mass; }
449 }
450 // used when we only want this prim's mass and not the linkset thing
451 public override float RawMass {
452 get { return _mass; }
453 }
454 // Set the physical mass to the passed mass.
455 // Note that this does not change _mass!
456 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
457 {
458 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
459 {
460 if (IsStatic)
461 {
462 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
463 Inertia = OMV.Vector3.Zero;
464 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
465 PhysScene.PE.UpdateInertiaTensor(PhysBody);
466 }
467 else
468 {
469 if (inWorld)
470 {
471 // Changing interesting properties doesn't change proxy and collision cache
472 // information. The Bullet solution is to re-add the object to the world
473 // after parameters are changed.
474 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
475 }
476
477 // The computation of mass props requires gravity to be set on the object.
478 Gravity = ComputeGravity(Buoyancy);
479 PhysScene.PE.SetGravity(PhysBody, Gravity);
480
481 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
482 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
483
484 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
485 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
486 PhysScene.PE.UpdateInertiaTensor(PhysBody);
487
488 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
489 LocalID, physMass, Inertia, Gravity, inWorld);
490
491 if (inWorld)
492 {
493 AddObjectToPhysicalWorld();
494 }
495 }
496 }
497 }
498
499 // Return what gravity should be set to this very moment
500 public OMV.Vector3 ComputeGravity(float buoyancy)
501 {
502 OMV.Vector3 ret = PhysScene.DefaultGravity;
503
504 if (!IsStatic)
505 {
506 ret *= (1f - buoyancy);
507 ret *= GravModifier;
508 }
509
510 return ret;
511 }
512
513 // Is this used?
514 public override OMV.Vector3 CenterOfMass
515 {
516 get { return RawPosition; }
517 }
518
519 // Is this used?
520 public override OMV.Vector3 GeometricCenter
521 {
522 get { return RawPosition; }
523 }
524
525 public override OMV.Vector3 Force {
526 get { return RawForce; }
527 set {
528 RawForce = value;
529 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
530 {
531 return new BSActorSetForce(PhysScene, this, SetForceActorName);
532 });
533
534 // Call update so actor Refresh() is called to start things off
535 PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
536 {
537 UpdatePhysicalParameters();
538 });
539 }
540 }
541
542 // Find and return a handle to the current vehicle actor.
543 // Return 'null' if there is no vehicle actor.
544 public BSDynamics GetVehicleActor(bool createIfNone)
545 {
546 BSDynamics ret = null;
547 BSActor actor;
548 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
549 {
550 ret = actor as BSDynamics;
551 }
552 else
553 {
554 if (createIfNone)
555 {
556 ret = new BSDynamics(PhysScene, this, VehicleActorName);
557 PhysicalActors.Add(ret.ActorName, ret);
558 }
559 }
560 return ret;
561 }
562
563 public override int VehicleType {
564 get {
565 int ret = (int)Vehicle.TYPE_NONE;
566 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
567 if (vehicleActor != null)
568 ret = (int)vehicleActor.Type;
569 return ret;
570 }
571 set {
572 Vehicle type = (Vehicle)value;
573
574 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
575 {
576 // Some vehicle scripts change vehicle type on the fly as an easy way to
577 // change all the parameters. Like a plane changing to CAR when on the
578 // ground. In this case, don't want to zero motion.
579 // ZeroMotion(true /* inTaintTime */);
580 if (type == Vehicle.TYPE_NONE)
581 {
582 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
583 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
584 if (vehicleActor != null)
585 {
586 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
587 }
588 }
589 else
590 {
591 // Vehicle type is not 'none' so create an actor and set it running.
592 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
593 if (vehicleActor != null)
594 {
595 vehicleActor.ProcessTypeChange(type);
596 ActivateIfPhysical(false);
597 }
598 }
599 });
600 }
601 }
602 public override void VehicleFloatParam(int param, float value)
603 {
604 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
605 {
606 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
607 if (vehicleActor != null)
608 {
609 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
610 ActivateIfPhysical(false);
611 }
612 });
613 }
614 public override void VehicleVectorParam(int param, OMV.Vector3 value)
615 {
616 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
617 {
618 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
619 if (vehicleActor != null)
620 {
621 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
622 ActivateIfPhysical(false);
623 }
624 });
625 }
626 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
627 {
628 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
629 {
630 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
631 if (vehicleActor != null)
632 {
633 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
634 ActivateIfPhysical(false);
635 }
636 });
637 }
638 public override void VehicleFlags(int param, bool remove)
639 {
640 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
641 {
642 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
643 if (vehicleActor != null)
644 {
645 vehicleActor.ProcessVehicleFlags(param, remove);
646 }
647 });
648 }
649
650 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
651 public override void SetVolumeDetect(int param) {
652 bool newValue = (param != 0);
653 if (_isVolumeDetect != newValue)
654 {
655 _isVolumeDetect = newValue;
656 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
657 {
658 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
659 SetObjectDynamic(true);
660 });
661 }
662 return;
663 }
664 public override bool IsVolumeDetect
665 {
666 get { return _isVolumeDetect; }
667 }
668 public override void SetMaterial(int material)
669 {
670 base.SetMaterial(material);
671 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
672 {
673 UpdatePhysicalParameters();
674 });
675 }
676 public override float Friction
677 {
678 get { return base.Friction; }
679 set
680 {
681 if (base.Friction != value)
682 {
683 base.Friction = value;
684 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
685 {
686 UpdatePhysicalParameters();
687 });
688 }
689 }
690 }
691 public override float Restitution
692 {
693 get { return base.Restitution; }
694 set
695 {
696 if (base.Restitution != value)
697 {
698 base.Restitution = value;
699 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
700 {
701 UpdatePhysicalParameters();
702 });
703 }
704 }
705 }
706 // The simulator/viewer keep density as 100kg/m3.
707 // Remember to use BSParam.DensityScaleFactor to create the physical density.
708 public override float Density
709 {
710 get { return base.Density; }
711 set
712 {
713 if (base.Density != value)
714 {
715 base.Density = value;
716 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
717 {
718 UpdatePhysicalParameters();
719 });
720 }
721 }
722 }
723 public override float GravModifier
724 {
725 get { return base.GravModifier; }
726 set
727 {
728 if (base.GravModifier != value)
729 {
730 base.GravModifier = value;
731 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
732 {
733 UpdatePhysicalParameters();
734 });
735 }
736 }
737 }
738 public override OMV.Vector3 Velocity {
739 get { return RawVelocity; }
740 set {
741 RawVelocity = value;
742 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
743 {
744 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
745 ForceVelocity = RawVelocity;
746 });
747 }
748 }
749 public override OMV.Vector3 ForceVelocity {
750 get { return RawVelocity; }
751 set {
752 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
753
754 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
755 if (PhysBody.HasPhysicalBody)
756 {
757 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
758 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
759 ActivateIfPhysical(false);
760 }
761 }
762 }
763 public override OMV.Vector3 Torque {
764 get { return RawTorque; }
765 set {
766 RawTorque = value;
767 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
768 {
769 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
770 });
771 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
772
773 // Call update so actor Refresh() is called to start things off
774 PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
775 {
776 UpdatePhysicalParameters();
777 });
778 }
779 }
780 public override OMV.Vector3 Acceleration {
781 get { return _acceleration; }
782 set { _acceleration = value; }
783 }
784
785 public override OMV.Quaternion Orientation {
786 get {
787 return RawOrientation;
788 }
789 set {
790 if (RawOrientation == value)
791 return;
792 RawOrientation = value;
793
794 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
795 {
796 ForceOrientation = RawOrientation;
797 });
798 }
799 }
800 // Go directly to Bullet to get/set the value.
801 public override OMV.Quaternion ForceOrientation
802 {
803 get
804 {
805 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
806 return RawOrientation;
807 }
808 set
809 {
810 RawOrientation = value;
811 if (PhysBody.HasPhysicalBody)
812 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
813 }
814 }
815 public override int PhysicsActorType {
816 get { return _physicsActorType; }
817 set { _physicsActorType = value; }
818 }
819 public override bool IsPhysical {
820 get { return _isPhysical; }
821 set {
822 if (_isPhysical != value)
823 {
824 _isPhysical = value;
825 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
826 {
827 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
828 SetObjectDynamic(true);
829 // whether phys-to-static or static-to-phys, the object is not moving.
830 ZeroMotion(true);
831
832 });
833 }
834 }
835 }
836
837 // An object is static (does not move) if selected or not physical
838 public override bool IsStatic
839 {
840 get { return _isSelected || !IsPhysical; }
841 }
842
843 // An object is solid if it's not phantom and if it's not doing VolumeDetect
844 public override bool IsSolid
845 {
846 get { return !IsPhantom && !_isVolumeDetect; }
847 }
848
849 // The object is moving and is actively being dynamic in the physical world
850 public override bool IsPhysicallyActive
851 {
852 get { return !_isSelected && IsPhysical; }
853 }
854
855 // Make gravity work if the object is physical and not selected
856 // Called at taint-time!!
857 private void SetObjectDynamic(bool forceRebuild)
858 {
859 // Recreate the physical object if necessary
860 CreateGeomAndObject(forceRebuild);
861 }
862
863 // Convert the simulator's physical properties into settings on BulletSim objects.
864 // There are four flags we're interested in:
865 // IsStatic: Object does not move, otherwise the object has mass and moves
866 // isSolid: other objects bounce off of this object
867 // isVolumeDetect: other objects pass through but can generate collisions
868 // collisionEvents: whether this object returns collision events
869 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
870 public virtual void UpdatePhysicalParameters()
871 {
872 if (!PhysBody.HasPhysicalBody)
873 {
874 // This would only happen if updates are called for during initialization when the body is not set up yet.
875 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
876 return;
877 }
878
879 // Mangling all the physical properties requires the object not be in the physical world.
880 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
881 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
882
883 // Set up the object physicalness (does gravity and collisions move this object)
884 MakeDynamic(IsStatic);
885
886 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
887 PhysicalActors.Refresh();
888
889 // Arrange for collision events if the simulator wants them
890 EnableCollisions(SubscribedEvents());
891
892 // Make solid or not (do things bounce off or pass through this object).
893 MakeSolid(IsSolid);
894
895 AddObjectToPhysicalWorld();
896
897 // Rebuild its shape
898 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
899
900 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
901 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
902 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
903 }
904
905 // "Making dynamic" means changing to and from static.
906 // When static, gravity does not effect the object and it is fixed in space.
907 // When dynamic, the object can fall and be pushed by others.
908 // This is independent of its 'solidness' which controls what passes through
909 // this object and what interacts with it.
910 protected virtual void MakeDynamic(bool makeStatic)
911 {
912 if (makeStatic)
913 {
914 // Become a Bullet 'static' object type
915 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
916 // Stop all movement
917 ZeroMotion(true);
918
919 // Set various physical properties so other object interact properly
920 PhysScene.PE.SetFriction(PhysBody, Friction);
921 PhysScene.PE.SetRestitution(PhysBody, Restitution);
922 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
923
924 // Mass is zero which disables a bunch of physics stuff in Bullet
925 UpdatePhysicalMassProperties(0f, false);
926 // Set collision detection parameters
927 if (BSParam.CcdMotionThreshold > 0f)
928 {
929 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
930 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
931 }
932
933 // The activation state is 'disabled' so Bullet will not try to act on it.
934 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
935 // Start it out sleeping and physical actions could wake it up.
936 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
937
938 // This collides like a static object
939 PhysBody.collisionType = CollisionType.Static;
940 }
941 else
942 {
943 // Not a Bullet static object
944 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
945
946 // Set various physical properties so other object interact properly
947 PhysScene.PE.SetFriction(PhysBody, Friction);
948 PhysScene.PE.SetRestitution(PhysBody, Restitution);
949 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
950
951 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
952 // Since this can be called multiple times, only zero forces when becoming physical
953 // PhysicsScene.PE.ClearAllForces(BSBody);
954
955 // For good measure, make sure the transform is set through to the motion state
956 ForcePosition = RawPosition;
957 ForceVelocity = RawVelocity;
958 ForceRotationalVelocity = _rotationalVelocity;
959
960 // A dynamic object has mass
961 UpdatePhysicalMassProperties(RawMass, false);
962
963 // Set collision detection parameters
964 if (BSParam.CcdMotionThreshold > 0f)
965 {
966 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
967 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
968 }
969
970 // Various values for simulation limits
971 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
972 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
973 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
974 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
975
976 // This collides like an object.
977 PhysBody.collisionType = CollisionType.Dynamic;
978
979 // Force activation of the object so Bullet will act on it.
980 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
981 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
982 }
983 }
984
985 // "Making solid" means that other object will not pass through this object.
986 // To make transparent, we create a Bullet ghost object.
987 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
988 // the functions after this one set up the state of a possibly newly created collision body.
989 private void MakeSolid(bool makeSolid)
990 {
991 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
992 if (makeSolid)
993 {
994 // Verify the previous code created the correct shape for this type of thing.
995 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
996 {
997 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
998 }
999 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1000 }
1001 else
1002 {
1003 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1004 {
1005 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1006 }
1007 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1008
1009 // Change collision info from a static object to a ghosty collision object
1010 PhysBody.collisionType = CollisionType.VolumeDetect;
1011 }
1012 }
1013
1014 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1015 private void EnableCollisions(bool wantsCollisionEvents)
1016 {
1017 if (wantsCollisionEvents)
1018 {
1019 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1020 }
1021 else
1022 {
1023 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1024 }
1025 }
1026
1027 // Add me to the physical world.
1028 // Object MUST NOT already be in the world.
1029 // This routine exists because some assorted properties get mangled by adding to the world.
1030 internal void AddObjectToPhysicalWorld()
1031 {
1032 if (PhysBody.HasPhysicalBody)
1033 {
1034 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1035 }
1036 else
1037 {
1038 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1039 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1040 }
1041 }
1042
1043 // prims don't fly
1044 public override bool Flying {
1045 get { return _flying; }
1046 set {
1047 _flying = value;
1048 }
1049 }
1050 public override bool SetAlwaysRun {
1051 get { return _setAlwaysRun; }
1052 set { _setAlwaysRun = value; }
1053 }
1054 public override bool ThrottleUpdates {
1055 get { return _throttleUpdates; }
1056 set { _throttleUpdates = value; }
1057 }
1058 public bool IsPhantom {
1059 get {
1060 // SceneObjectPart removes phantom objects from the physics scene
1061 // so, although we could implement touching and such, we never
1062 // are invoked as a phantom object
1063 return false;
1064 }
1065 }
1066 public override bool FloatOnWater {
1067 set {
1068 _floatOnWater = value;
1069 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1070 {
1071 if (_floatOnWater)
1072 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1073 else
1074 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1075 });
1076 }
1077 }
1078 public override OMV.Vector3 RotationalVelocity {
1079 get {
1080 return _rotationalVelocity;
1081 }
1082 set {
1083 _rotationalVelocity = value;
1084 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1085 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1086 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1087 {
1088 ForceRotationalVelocity = _rotationalVelocity;
1089 });
1090 }
1091 }
1092 public override OMV.Vector3 ForceRotationalVelocity {
1093 get {
1094 return _rotationalVelocity;
1095 }
1096 set {
1097 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1098 if (PhysBody.HasPhysicalBody)
1099 {
1100 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1101 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1102 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1103 ActivateIfPhysical(false);
1104 }
1105 }
1106 }
1107 public override bool Kinematic {
1108 get { return _kinematic; }
1109 set { _kinematic = value;
1110 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1111 }
1112 }
1113 public override float Buoyancy {
1114 get { return _buoyancy; }
1115 set {
1116 _buoyancy = value;
1117 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1118 {
1119 ForceBuoyancy = _buoyancy;
1120 });
1121 }
1122 }
1123 public override float ForceBuoyancy {
1124 get { return _buoyancy; }
1125 set {
1126 _buoyancy = value;
1127 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1128 // Force the recalculation of the various inertia,etc variables in the object
1129 UpdatePhysicalMassProperties(RawMass, true);
1130 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1131 ActivateIfPhysical(false);
1132 }
1133 }
1134
1135 public override bool PIDActive
1136 {
1137 get
1138 {
1139 return MoveToTargetActive;
1140 }
1141
1142 set
1143 {
1144 MoveToTargetActive = value;
1145
1146 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1147 {
1148 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1149 });
1150
1151 // Call update so actor Refresh() is called to start things off
1152 PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1153 {
1154 UpdatePhysicalParameters();
1155 });
1156 }
1157 }
1158
1159 public override OMV.Vector3 PIDTarget
1160 {
1161 set
1162 {
1163 base.PIDTarget = value;
1164 BSActor actor;
1165 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1166 {
1167 // if the actor exists, tell it to refresh its values.
1168 actor.Refresh();
1169 }
1170
1171 }
1172 }
1173 // Used for llSetHoverHeight and maybe vehicle height
1174 // Hover Height will override MoveTo target's Z
1175 public override bool PIDHoverActive {
1176 set {
1177 base.HoverActive = value;
1178 EnableActor(HoverActive, HoverActorName, delegate()
1179 {
1180 return new BSActorHover(PhysScene, this, HoverActorName);
1181 });
1182
1183 // Call update so actor Refresh() is called to start things off
1184 PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1185 {
1186 UpdatePhysicalParameters();
1187 });
1188 }
1189 }
1190
1191 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1192 // Per documentation, max force is limited.
1193 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1194
1195 // Since this force is being applied in only one step, make this a force per second.
1196 addForce /= PhysScene.LastTimeStep;
1197 AddForce(addForce, pushforce, false /* inTaintTime */);
1198 }
1199
1200 // Applying a force just adds this to the total force on the object.
1201 // This added force will only last the next simulation tick.
1202 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1203 // for an object, doesn't matter if force is a pushforce or not
1204 if (IsPhysicallyActive)
1205 {
1206 if (force.IsFinite())
1207 {
1208 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1209
1210 OMV.Vector3 addForce = force;
1211 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1212 {
1213 // Bullet adds this central force to the total force for this tick.
1214 // Deep down in Bullet:
1215 // linearVelocity += totalForce / mass * timeStep;
1216 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1217 if (PhysBody.HasPhysicalBody)
1218 {
1219 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1220 ActivateIfPhysical(false);
1221 }
1222 });
1223 }
1224 else
1225 {
1226 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1227 return;
1228 }
1229 }
1230 }
1231
1232 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1233 // for an object, doesn't matter if force is a pushforce or not
1234 if (!IsPhysicallyActive)
1235 {
1236 if (impulse.IsFinite())
1237 {
1238 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1239 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1240
1241 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1242 {
1243 // Bullet adds this impulse immediately to the velocity
1244 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1245 if (PhysBody.HasPhysicalBody)
1246 {
1247 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1248 ActivateIfPhysical(false);
1249 }
1250 });
1251 }
1252 else
1253 {
1254 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1255 return;
1256 }
1257 }
1258 }
1259
1260 // BSPhysObject.AddAngularForce()
1261 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1262 {
1263 if (force.IsFinite())
1264 {
1265 OMV.Vector3 angForce = force;
1266 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1267 {
1268 if (PhysBody.HasPhysicalBody)
1269 {
1270 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1271 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1272 ActivateIfPhysical(false);
1273 }
1274 });
1275 }
1276 else
1277 {
1278 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1279 return;
1280 }
1281 }
1282
1283 // A torque impulse.
1284 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1285 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1286 // Computed as: angularVelocity += impulse * inertia;
1287 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1288 {
1289 OMV.Vector3 applyImpulse = impulse;
1290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1291 {
1292 if (PhysBody.HasPhysicalBody)
1293 {
1294 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1295 ActivateIfPhysical(false);
1296 }
1297 });
1298 }
1299
1300 public override void SetMomentum(OMV.Vector3 momentum) {
1301 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1302 }
1303 #region Mass Calculation
1304
1305 private float CalculateMass()
1306 {
1307 float volume = _size.X * _size.Y * _size.Z; // default
1308 float tmp;
1309
1310 float returnMass = 0;
1311 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1312 float hollowVolume = hollowAmount * hollowAmount;
1313
1314 switch (BaseShape.ProfileShape)
1315 {
1316 case ProfileShape.Square:
1317 // default box
1318
1319 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1320 {
1321 if (hollowAmount > 0.0)
1322 {
1323 switch (BaseShape.HollowShape)
1324 {
1325 case HollowShape.Square:
1326 case HollowShape.Same:
1327 break;
1328
1329 case HollowShape.Circle:
1330
1331 hollowVolume *= 0.78539816339f;
1332 break;
1333
1334 case HollowShape.Triangle:
1335
1336 hollowVolume *= (0.5f * .5f);
1337 break;
1338
1339 default:
1340 hollowVolume = 0;
1341 break;
1342 }
1343 volume *= (1.0f - hollowVolume);
1344 }
1345 }
1346
1347 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1348 {
1349 //a tube
1350
1351 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1352 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1353 volume -= volume*tmp*tmp;
1354
1355 if (hollowAmount > 0.0)
1356 {
1357 hollowVolume *= hollowAmount;
1358
1359 switch (BaseShape.HollowShape)
1360 {
1361 case HollowShape.Square:
1362 case HollowShape.Same:
1363 break;
1364
1365 case HollowShape.Circle:
1366 hollowVolume *= 0.78539816339f;;
1367 break;
1368
1369 case HollowShape.Triangle:
1370 hollowVolume *= 0.5f * 0.5f;
1371 break;
1372 default:
1373 hollowVolume = 0;
1374 break;
1375 }
1376 volume *= (1.0f - hollowVolume);
1377 }
1378 }
1379
1380 break;
1381
1382 case ProfileShape.Circle:
1383
1384 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1385 {
1386 volume *= 0.78539816339f; // elipse base
1387
1388 if (hollowAmount > 0.0)
1389 {
1390 switch (BaseShape.HollowShape)
1391 {
1392 case HollowShape.Same:
1393 case HollowShape.Circle:
1394 break;
1395
1396 case HollowShape.Square:
1397 hollowVolume *= 0.5f * 2.5984480504799f;
1398 break;
1399
1400 case HollowShape.Triangle:
1401 hollowVolume *= .5f * 1.27323954473516f;
1402 break;
1403
1404 default:
1405 hollowVolume = 0;
1406 break;
1407 }
1408 volume *= (1.0f - hollowVolume);
1409 }
1410 }
1411
1412 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1413 {
1414 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1415 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1416 volume *= (1.0f - tmp * tmp);
1417
1418 if (hollowAmount > 0.0)
1419 {
1420
1421 // calculate the hollow volume by it's shape compared to the prim shape
1422 hollowVolume *= hollowAmount;
1423
1424 switch (BaseShape.HollowShape)
1425 {
1426 case HollowShape.Same:
1427 case HollowShape.Circle:
1428 break;
1429
1430 case HollowShape.Square:
1431 hollowVolume *= 0.5f * 2.5984480504799f;
1432 break;
1433
1434 case HollowShape.Triangle:
1435 hollowVolume *= .5f * 1.27323954473516f;
1436 break;
1437
1438 default:
1439 hollowVolume = 0;
1440 break;
1441 }
1442 volume *= (1.0f - hollowVolume);
1443 }
1444 }
1445 break;
1446
1447 case ProfileShape.HalfCircle:
1448 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1449 {
1450 volume *= 0.52359877559829887307710723054658f;
1451 }
1452 break;
1453
1454 case ProfileShape.EquilateralTriangle:
1455
1456 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1457 {
1458 volume *= 0.32475953f;
1459
1460 if (hollowAmount > 0.0)
1461 {
1462
1463 // calculate the hollow volume by it's shape compared to the prim shape
1464 switch (BaseShape.HollowShape)
1465 {
1466 case HollowShape.Same:
1467 case HollowShape.Triangle:
1468 hollowVolume *= .25f;
1469 break;
1470
1471 case HollowShape.Square:
1472 hollowVolume *= 0.499849f * 3.07920140172638f;
1473 break;
1474
1475 case HollowShape.Circle:
1476 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1477 // Cyllinder hollow volume calculation
1478
1479 hollowVolume *= 0.1963495f * 3.07920140172638f;
1480 break;
1481
1482 default:
1483 hollowVolume = 0;
1484 break;
1485 }
1486 volume *= (1.0f - hollowVolume);
1487 }
1488 }
1489 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1490 {
1491 volume *= 0.32475953f;
1492 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1493 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1494 volume *= (1.0f - tmp * tmp);
1495
1496 if (hollowAmount > 0.0)
1497 {
1498
1499 hollowVolume *= hollowAmount;
1500
1501 switch (BaseShape.HollowShape)
1502 {
1503 case HollowShape.Same:
1504 case HollowShape.Triangle:
1505 hollowVolume *= .25f;
1506 break;
1507
1508 case HollowShape.Square:
1509 hollowVolume *= 0.499849f * 3.07920140172638f;
1510 break;
1511
1512 case HollowShape.Circle:
1513
1514 hollowVolume *= 0.1963495f * 3.07920140172638f;
1515 break;
1516
1517 default:
1518 hollowVolume = 0;
1519 break;
1520 }
1521 volume *= (1.0f - hollowVolume);
1522 }
1523 }
1524 break;
1525
1526 default:
1527 break;
1528 }
1529
1530
1531
1532 float taperX1;
1533 float taperY1;
1534 float taperX;
1535 float taperY;
1536 float pathBegin;
1537 float pathEnd;
1538 float profileBegin;
1539 float profileEnd;
1540
1541 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1542 {
1543 taperX1 = BaseShape.PathScaleX * 0.01f;
1544 if (taperX1 > 1.0f)
1545 taperX1 = 2.0f - taperX1;
1546 taperX = 1.0f - taperX1;
1547
1548 taperY1 = BaseShape.PathScaleY * 0.01f;
1549 if (taperY1 > 1.0f)
1550 taperY1 = 2.0f - taperY1;
1551 taperY = 1.0f - taperY1;
1552 }
1553 else
1554 {
1555 taperX = BaseShape.PathTaperX * 0.01f;
1556 if (taperX < 0.0f)
1557 taperX = -taperX;
1558 taperX1 = 1.0f - taperX;
1559
1560 taperY = BaseShape.PathTaperY * 0.01f;
1561 if (taperY < 0.0f)
1562 taperY = -taperY;
1563 taperY1 = 1.0f - taperY;
1564
1565 }
1566
1567
1568 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1569
1570 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1571 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1572 volume *= (pathEnd - pathBegin);
1573
1574 // this is crude aproximation
1575 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1576 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1577 volume *= (profileEnd - profileBegin);
1578
1579 returnMass = Density * BSParam.DensityScaleFactor * volume;
1580
1581 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1582 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1583 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1584 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1585
1586 return returnMass;
1587 }// end CalculateMass
1588 #endregion Mass Calculation
1589
1590 // Rebuild the geometry and object.
1591 // This is called when the shape changes so we need to recreate the mesh/hull.
1592 // Called at taint-time!!!
1593 public void CreateGeomAndObject(bool forceRebuild)
1594 {
1595 // Create the correct physical representation for this type of object.
1596 // Updates base.PhysBody and base.PhysShape with the new information.
1597 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1598 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1599 {
1600 // Called if the current prim body is about to be destroyed.
1601 // Remove all the physical dependencies on the old body.
1602 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1603 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1604 RemoveDependencies();
1605 });
1606
1607 // Make sure the properties are set on the new object
1608 UpdatePhysicalParameters();
1609 return;
1610 }
1611
1612 // Called at taint-time
1613 protected virtual void RemoveDependencies()
1614 {
1615 PhysicalActors.RemoveDependencies();
1616 }
1617
1618 #region Extension
1619 public override object Extension(string pFunct, params object[] pParams)
1620 {
1621 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1622 object ret = null;
1623 switch (pFunct)
1624 {
1625 case ExtendedPhysics.PhysFunctAxisLockLimits:
1626 ret = SetAxisLockLimitsExtension(pParams);
1627 break;
1628 default:
1629 ret = base.Extension(pFunct, pParams);
1630 break;
1631 }
1632 return ret;
1633 }
1634
1635 private void InitializeAxisActor()
1636 {
1637 EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1638 LockedAxisActorName, delegate()
1639 {
1640 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1641 });
1642
1643 // Update parameters so the new actor's Refresh() action is called at the right time.
1644 PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1645 {
1646 UpdatePhysicalParameters();
1647 });
1648 }
1649
1650 // Passed an array of an array of parameters, set the axis locking.
1651 // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1652 // followed by another int and floats, etc.
1653 private object SetAxisLockLimitsExtension(object[] pParams)
1654 {
1655 DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1656 object ret = null;
1657 try
1658 {
1659 if (pParams.GetLength(0) > 1)
1660 {
1661 int index = 2;
1662 while (index < pParams.GetLength(0))
1663 {
1664 var funct = pParams[index];
1665 DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1666 if (funct is Int32 || funct is Int64)
1667 {
1668 switch ((int)funct)
1669 {
1670 // Those that take no parameters
1671 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1672 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1673 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1674 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1675 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1676 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1677 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1678 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1679 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1680 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1681 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1682 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1683 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1684 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1685 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1686 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1687 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1688 ApplyAxisLimits((int)funct, 0f, 0f);
1689 index += 1;
1690 break;
1691 // Those that take two parameters (the limits)
1692 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1693 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1694 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1695 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1696 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1697 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1698 ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1699 index += 3;
1700 break;
1701 default:
1702 m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1703 index += 1;
1704 break;
1705 }
1706 }
1707 }
1708 InitializeAxisActor();
1709 ret = (object)index;
1710 }
1711 }
1712 catch (Exception e)
1713 {
1714 m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1715 ret = null;
1716 }
1717 return ret; // not implemented yet
1718 }
1719
1720 // Set the locking parameters.
1721 // If an axis is locked, the limits for the axis are set to zero,
1722 // If the axis is being constrained, the high and low value are passed and set.
1723 // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1724 protected void ApplyAxisLimits(int funct, float low, float high)
1725 {
1726 DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1727 float linearMax = 23000f;
1728 float angularMax = (float)Math.PI;
1729
1730 switch (funct)
1731 {
1732 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1733 this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1734 this.LockedLinearAxisLow = OMV.Vector3.Zero;
1735 this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1736 break;
1737 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1738 this.LockedLinearAxis.X = LockedAxis;
1739 this.LockedLinearAxisLow.X = 0f;
1740 this.LockedLinearAxisHigh.X = 0f;
1741 break;
1742 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1743 this.LockedLinearAxis.X = LockedAxis;
1744 this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1745 this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1746 break;
1747 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1748 this.LockedLinearAxis.Y = LockedAxis;
1749 this.LockedLinearAxisLow.Y = 0f;
1750 this.LockedLinearAxisHigh.Y = 0f;
1751 break;
1752 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1753 this.LockedLinearAxis.Y = LockedAxis;
1754 this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1755 this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1756 break;
1757 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1758 this.LockedLinearAxis.Z = LockedAxis;
1759 this.LockedLinearAxisLow.Z = 0f;
1760 this.LockedLinearAxisHigh.Z = 0f;
1761 break;
1762 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1763 this.LockedLinearAxis.Z = LockedAxis;
1764 this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1765 this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1766 break;
1767 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1768 this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1769 this.LockedAngularAxisLow = OMV.Vector3.Zero;
1770 this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1771 break;
1772 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1773 this.LockedAngularAxis.X = LockedAxis;
1774 this.LockedAngularAxisLow.X = 0;
1775 this.LockedAngularAxisHigh.X = 0;
1776 break;
1777 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1778 this.LockedAngularAxis.X = LockedAxis;
1779 this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1780 this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1781 break;
1782 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1783 this.LockedAngularAxis.Y = LockedAxis;
1784 this.LockedAngularAxisLow.Y = 0;
1785 this.LockedAngularAxisHigh.Y = 0;
1786 break;
1787 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1788 this.LockedAngularAxis.Y = LockedAxis;
1789 this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1790 this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1791 break;
1792 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1793 this.LockedAngularAxis.Z = LockedAxis;
1794 this.LockedAngularAxisLow.Z = 0;
1795 this.LockedAngularAxisHigh.Z = 0;
1796 break;
1797 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1798 this.LockedAngularAxis.Z = LockedAxis;
1799 this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1800 this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1801 break;
1802 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1803 this.LockedLinearAxis = LockedAxisFree;
1804 this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1805 this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1806 break;
1807 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1808 this.LockedLinearAxis.X = FreeAxis;
1809 this.LockedLinearAxisLow.X = -linearMax;
1810 this.LockedLinearAxisHigh.X = linearMax;
1811 break;
1812 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1813 this.LockedLinearAxis.Y = FreeAxis;
1814 this.LockedLinearAxisLow.Y = -linearMax;
1815 this.LockedLinearAxisHigh.Y = linearMax;
1816 break;
1817 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1818 this.LockedLinearAxis.Z = FreeAxis;
1819 this.LockedLinearAxisLow.Z = -linearMax;
1820 this.LockedLinearAxisHigh.Z = linearMax;
1821 break;
1822 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1823 this.LockedAngularAxis = LockedAxisFree;
1824 this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1825 this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1826 break;
1827 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1828 this.LockedAngularAxis.X = FreeAxis;
1829 this.LockedAngularAxisLow.X = -angularMax;
1830 this.LockedAngularAxisHigh.X = angularMax;
1831 break;
1832 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1833 this.LockedAngularAxis.Y = FreeAxis;
1834 this.LockedAngularAxisLow.Y = -angularMax;
1835 this.LockedAngularAxisHigh.Y = angularMax;
1836 break;
1837 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1838 this.LockedAngularAxis.Z = FreeAxis;
1839 this.LockedAngularAxisLow.Z = -angularMax;
1840 this.LockedAngularAxisHigh.Z = angularMax;
1841 break;
1842 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1843 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1844 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1845 break;
1846 default:
1847 break;
1848 }
1849 return;
1850 }
1851 #endregion // Extension
1852
1853 // The physics engine says that properties have updated. Update same and inform
1854 // the world that things have changed.
1855 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1856 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1857 public override void UpdateProperties(EntityProperties entprop)
1858 {
1859 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1860 TriggerPreUpdatePropertyAction(ref entprop);
1861
1862 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1863
1864 // Assign directly to the local variables so the normal set actions do not happen
1865 RawPosition = entprop.Position;
1866 RawOrientation = entprop.Rotation;
1867 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1868 // very sensitive to velocity changes.
1869 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1870 RawVelocity = entprop.Velocity;
1871 _acceleration = entprop.Acceleration;
1872 _rotationalVelocity = entprop.RotationalVelocity;
1873
1874 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1875
1876 // The sanity check can change the velocity and/or position.
1877 if (PositionSanityCheck(true /* inTaintTime */ ))
1878 {
1879 entprop.Position = RawPosition;
1880 entprop.Velocity = RawVelocity;
1881 entprop.RotationalVelocity = _rotationalVelocity;
1882 entprop.Acceleration = _acceleration;
1883 }
1884
1885 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1886 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1887
1888 // remember the current and last set values
1889 LastEntityProperties = CurrentEntityProperties;
1890 CurrentEntityProperties = entprop;
1891
1892 PhysScene.PostUpdate(this);
1893 }
1894}
1895}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
new file mode 100755
index 0000000..d8ed56b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
@@ -0,0 +1,182 @@
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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Runtime.InteropServices;
32using OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.PhysicsModules.SharedBase;
35
36using OMV = OpenMetaverse;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40public class BSPrimDisplaced : BSPrim
41{
42 // The purpose of this subclass is to do any mapping between what the simulator thinks
43 // the prim position and orientation is and what the physical position/orientation.
44 // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
45 // of the prim/linkset. The simulator, on the other hand, tracks the location of
46 // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere
47 // but the origin of the root prim, the physical origin is displaced from the simulator origin.
48 //
49 // This routine works by capturing ForcePosition and
50 // adjusting the simulator values (being set) into the physical values.
51 // The conversion is also done in the opposite direction (physical origin -> simulator origin).
52 //
53 // The updateParameter call is also captured and the values from the physics engine
54 // are converted into simulator origin values before being passed to the base
55 // class.
56
57 // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass.
58 public virtual OMV.Vector3 PositionDisplacement { get; set; }
59
60 public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
61 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
62 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
63 {
64 ClearDisplacement();
65 }
66
67 // Clears any center-of-mass displacement introduced by linksets, etc.
68 // Does not clear the displacement set by the user.
69 public void ClearDisplacement()
70 {
71 if (UserSetCenterOfMassDisplacement.HasValue)
72 PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement;
73 else
74 PositionDisplacement = OMV.Vector3.Zero;
75 }
76
77 // Set this sets and computes the displacement from the passed prim to the center-of-mass.
78 // A user set value for center-of-mass overrides whatever might be passed in here.
79 // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
80 // Returns the relative offset from the root position to the center-of-mass.
81 // Called at taint time.
82 public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
83 {
84 PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
85 Vector3 comDisp;
86 if (UserSetCenterOfMassDisplacement.HasValue)
87 comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
88 else
89 comDisp = centerOfMassDisplacement;
90
91 // Eliminate any jitter caused be very slight differences in masses and positions
92 if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) )
93 comDisp = Vector3.Zero;
94
95 DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
96 LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
97 if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) )
98 {
99 // Displacement setting is changing.
100 // The relationship between the physical object and simulated object must be aligned.
101 PositionDisplacement = comDisp;
102 this.ForcePosition = RawPosition;
103 }
104
105 return PositionDisplacement;
106 }
107
108 // 'ForcePosition' is the one way to set the physical position of the body in the physics engine.
109 // Displace the simulator idea of position (center of root prim) to the physical position.
110 public override Vector3 ForcePosition
111 {
112 get {
113 OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody);
114 if (PositionDisplacement != OMV.Vector3.Zero)
115 {
116 // If there is some displacement, return the physical position (center-of-mass)
117 // location minus the displacement to give the center of the root prim.
118 OMV.Vector3 displacement = PositionDisplacement * ForceOrientation;
119 DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}",
120 LocalID, physPosition, displacement, physPosition - displacement);
121 physPosition -= displacement;
122 }
123 RawPosition = physPosition;
124 return physPosition;
125 }
126 set
127 {
128 if (PositionDisplacement != OMV.Vector3.Zero)
129 {
130 // This value is the simulator's idea of where the prim is: the center of the root prim
131 RawPosition = value;
132
133 // Move the passed root prim postion to the center-of-mass position and set in the physics engine.
134 OMV.Vector3 displacement = PositionDisplacement * RawOrientation;
135 OMV.Vector3 displacedPos = RawPosition + displacement;
136 DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}",
137 LocalID, RawPosition, displacement, displacedPos);
138 if (PhysBody.HasPhysicalBody)
139 {
140 PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation);
141 ActivateIfPhysical(false);
142 }
143 }
144 else
145 {
146 base.ForcePosition = value;
147 }
148 }
149 }
150
151 // These are also overridden by BSPrimLinkable if the prim can be part of a linkset
152 public override OMV.Vector3 CenterOfMass
153 {
154 get { return RawPosition; }
155 }
156
157 public override OMV.Vector3 GeometricCenter
158 {
159 get { return RawPosition; }
160 }
161
162 public override void UpdateProperties(EntityProperties entprop)
163 {
164 // Undo any center-of-mass displacement that might have been done.
165 if (PositionDisplacement != OMV.Vector3.Zero)
166 {
167 // The origional shape was offset from 'zero' by PositionDisplacement.
168 // These physical location must be back converted to be centered around the displaced
169 // root shape.
170
171 // Move the returned center-of-mass location to the root prim location.
172 OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation;
173 OMV.Vector3 displacedPos = entprop.Position - displacement;
174 DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}",
175 LocalID, entprop.Position, displacement, displacedPos);
176 entprop.Position = displacedPos;
177 }
178
179 base.UpdateProperties(entprop);
180 }
181}
182}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
new file mode 100755
index 0000000..55b5da0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
@@ -0,0 +1,349 @@
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.PhysicsModule.BulletS
37{
38public class BSPrimLinkable : BSPrimDisplaced
39{
40 // The purpose of this subclass is to add linkset functionality to the prim. This overrides
41 // operations necessary for keeping the linkset created and, additionally, this
42 // calls the linkset implementation for its creation and management.
43
44#pragma warning disable 414
45 private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
46#pragma warning restore 414
47
48 // This adds the overrides for link() and delink() so the prim is linkable.
49
50 public BSLinkset Linkset { get; set; }
51 // The index of this child prim.
52 public int LinksetChildIndex { get; set; }
53
54 public BSLinkset.LinksetImplementation LinksetType { get; set; }
55
56 public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
57 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
58 : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
59 {
60 // Default linkset implementation for this prim
61 LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
62
63 Linkset = BSLinkset.Factory(PhysScene, this);
64
65 Linkset.Refresh(this);
66 }
67
68 public override void Destroy()
69 {
70 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
71 base.Destroy();
72 }
73
74 public override void link(OpenSim.Region.PhysicsModules.SharedBase.PhysicsActor obj)
75 {
76 BSPrimLinkable parent = obj as BSPrimLinkable;
77 if (parent != null)
78 {
79 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
80 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
81
82 Linkset = parent.Linkset.AddMeToLinkset(this);
83
84 DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
85 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
86 }
87 return;
88 }
89
90 public override void delink()
91 {
92 // TODO: decide if this parent checking needs to happen at taint time
93 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
94
95 BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
96 int childrenBefore = Linkset.NumberOfChildren; // DEBUG
97
98 Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
99
100 DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
101 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
102 return;
103 }
104
105 // When simulator changes position, this might be moving a child of the linkset.
106 public override OMV.Vector3 Position
107 {
108 get { return base.Position; }
109 set
110 {
111 base.Position = value;
112 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
113 {
114 Linkset.UpdateProperties(UpdatedProperties.Position, this);
115 });
116 }
117 }
118
119 // When simulator changes orientation, this might be moving a child of the linkset.
120 public override OMV.Quaternion Orientation
121 {
122 get { return base.Orientation; }
123 set
124 {
125 base.Orientation = value;
126 PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
127 {
128 Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
129 });
130 }
131 }
132
133 public override float TotalMass
134 {
135 get { return Linkset.LinksetMass; }
136 }
137
138 public override OMV.Vector3 CenterOfMass
139 {
140 get { return Linkset.CenterOfMass; }
141 }
142
143 public override OMV.Vector3 GeometricCenter
144 {
145 get { return Linkset.GeometricCenter; }
146 }
147
148 // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
149 public override void UpdatePhysicalParameters()
150 {
151 base.UpdatePhysicalParameters();
152 // Recompute any linkset parameters.
153 // When going from non-physical to physical, this re-enables the constraints that
154 // had been automatically disabled when the mass was set to zero.
155 // For compound based linksets, this enables and disables interactions of the children.
156 if (Linkset != null) // null can happen during initialization
157 Linkset.Refresh(this);
158 }
159
160 // When the prim is made dynamic or static, the linkset needs to change.
161 protected override void MakeDynamic(bool makeStatic)
162 {
163 base.MakeDynamic(makeStatic);
164 if (Linkset != null) // null can happen during initialization
165 {
166 if (makeStatic)
167 Linkset.MakeStatic(this);
168 else
169 Linkset.MakeDynamic(this);
170 }
171 }
172
173 // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
174 protected override void RemoveDependencies()
175 {
176 Linkset.RemoveDependencies(this);
177 base.RemoveDependencies();
178 }
179
180 // Called after a simulation step for the changes in physical object properties.
181 // Do any filtering/modification needed for linksets.
182 public override void UpdateProperties(EntityProperties entprop)
183 {
184 if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
185 {
186 // Properties are only updated for the roots of a linkset.
187 // TODO: this will have to change when linksets are articulated.
188 base.UpdateProperties(entprop);
189 }
190 /*
191 else
192 {
193 // For debugging, report the movement of children
194 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
195 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
196 entprop.Acceleration, entprop.RotationalVelocity);
197 }
198 */
199 // The linkset might like to know about changing locations
200 Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
201 }
202
203 // Called after a simulation step to post a collision with this object.
204 // This returns 'true' if the collision has been queued and the SendCollisions call must
205 // be made at the end of the simulation step.
206 public override bool Collide(uint collidingWith, BSPhysObject collidee,
207 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
208 {
209 bool ret = false;
210 // Ask the linkset if it wants to handle the collision
211 if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
212 {
213 // The linkset didn't handle it so pass the collision through normal processing
214 ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
215 }
216 return ret;
217 }
218
219 // A linkset reports any collision on any part of the linkset.
220 public long SomeCollisionSimulationStep = 0;
221 public override bool HasSomeCollision
222 {
223 get
224 {
225 return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
226 }
227 set
228 {
229 if (value)
230 SomeCollisionSimulationStep = PhysScene.SimulationStep;
231 else
232 SomeCollisionSimulationStep = 0;
233
234 base.HasSomeCollision = value;
235 }
236 }
237
238 // Convert the existing linkset of this prim into a new type.
239 public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
240 {
241 bool ret = false;
242 if (LinksetType != newType)
243 {
244 DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
245
246 // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
247 this.LinksetType = newType;
248
249 BSLinkset oldLinkset = this.Linkset;
250 BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
251
252 this.Linkset = newLinkset;
253
254 // Pick up any physical dependencies this linkset might have in the physics engine.
255 oldLinkset.RemoveDependencies(this);
256
257 // Create a list of the children (mainly because can't interate through a list that's changing)
258 List<BSPrimLinkable> children = new List<BSPrimLinkable>();
259 oldLinkset.ForEachMember((child) =>
260 {
261 if (!oldLinkset.IsRoot(child))
262 children.Add(child);
263 return false; // 'false' says to continue to next member
264 });
265
266 // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
267 foreach (BSPrimLinkable child in children)
268 {
269 oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
270 }
271 foreach (BSPrimLinkable child in children)
272 {
273 newLinkset.AddMeToLinkset(child);
274 child.Linkset = newLinkset;
275 }
276
277 // Force the shape and linkset to get reconstructed
278 newLinkset.Refresh(this);
279 this.ForceBodyShapeRebuild(true /* inTaintTime */);
280 }
281 return ret;
282 }
283
284 #region Extension
285 public override object Extension(string pFunct, params object[] pParams)
286 {
287 DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
288 object ret = null;
289 switch (pFunct)
290 {
291 // physGetLinksetType();
292 // pParams = [ BSPhysObject root, null ]
293 case ExtendedPhysics.PhysFunctGetLinksetType:
294 {
295 ret = (object)LinksetType;
296 DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
297 break;
298 }
299 // physSetLinksetType(type);
300 // pParams = [ BSPhysObject root, null, integer type ]
301 case ExtendedPhysics.PhysFunctSetLinksetType:
302 {
303 if (pParams.Length > 2)
304 {
305 BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
306 if (Linkset.IsRoot(this))
307 {
308 PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
309 {
310 // Cause the linkset type to change
311 DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
312 LocalID, Linkset.LinksetImpl, linksetType);
313 ConvertLinkset(linksetType);
314 });
315 }
316 ret = (object)(int)linksetType;
317 }
318 break;
319 }
320 // physChangeLinkType(linknum, typeCode);
321 // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
322 case ExtendedPhysics.PhysFunctChangeLinkType:
323 {
324 ret = Linkset.Extension(pFunct, pParams);
325 break;
326 }
327 // physGetLinkType(linknum);
328 // pParams = [ BSPhysObject root, BSPhysObject child ]
329 case ExtendedPhysics.PhysFunctGetLinkType:
330 {
331 ret = Linkset.Extension(pFunct, pParams);
332 break;
333 }
334 // physChangeLinkParams(linknum, [code, value, code, value, ...]);
335 // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
336 case ExtendedPhysics.PhysFunctChangeLinkParams:
337 {
338 ret = Linkset.Extension(pFunct, pParams);
339 break;
340 }
341 default:
342 ret = base.Extension(pFunct, pParams);
343 break;
344 }
345 return ret;
346 }
347 #endregion // Extension
348}
349}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
new file mode 100644
index 0000000..452ce55
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -0,0 +1,1333 @@
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.Reflection;
31using System.Runtime.InteropServices;
32using System.Text;
33using System.Threading;
34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using Nini.Config;
40using log4net;
41using OpenMetaverse;
42using Mono.Addins;
43
44namespace OpenSim.Region.PhysicsModule.BulletS
45{
46 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "BulletSPhysicsScene")]
47 public sealed class BSScene : PhysicsScene, IPhysicsParameters, INonSharedRegionModule
48 {
49 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50 internal static readonly string LogHeader = "[BULLETS SCENE]";
51
52 private bool m_Enabled = false;
53 private IConfigSource m_Config;
54
55 // The name of the region we're working for.
56 public string RegionName { get; private set; }
57
58 public string BulletSimVersion = "?";
59
60 // The handle to the underlying managed or unmanaged version of Bullet being used.
61 public string BulletEngineName { get; private set; }
62 public BSAPITemplate PE;
63
64 // If the physics engine is running on a separate thread
65 public Thread m_physicsThread;
66
67 public Dictionary<uint, BSPhysObject> PhysObjects;
68 public BSShapeCollection Shapes;
69
70 // Keeping track of the objects with collisions so we can report begin and end of a collision
71 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
72 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
73
74 // All the collision processing is protected with this lock object
75 public Object CollisionLock = new Object();
76
77 // Properties are updated here
78 public Object UpdateLock = new Object();
79 public HashSet<BSPhysObject> ObjectsWithUpdates = new HashSet<BSPhysObject>();
80
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> AvatarsInScene = new HashSet<BSPhysObject>();
84 private Object AvatarsInSceneLock = new Object();
85
86 // let my minuions use my logger
87 public ILog Logger { get { return m_log; } }
88
89 public IMesher mesher;
90 public uint WorldID { get; private set; }
91 public BulletWorld World { get; private set; }
92
93 // All the constraints that have been allocated in this instance.
94 public BSConstraintCollection Constraints { get; private set; }
95
96 // Simulation parameters
97 //internal float m_physicsStepTime; // if running independently, the interval simulated by default
98
99 internal int m_maxSubSteps;
100 internal float m_fixedTimeStep;
101
102 internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
103
104 internal long m_simulationStep = 0; // The current simulation step.
105 public long SimulationStep { get { return m_simulationStep; } }
106 // A number to use for SimulationStep that is probably not any step value
107 // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
108 public static long NotASimulationStep = -1234;
109
110 internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
111
112 internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
113
114 // Physical objects can register for prestep or poststep events
115 public delegate void PreStepAction(float timeStep);
116 public delegate void PostStepAction(float timeStep);
117 public event PreStepAction BeforeStep;
118 public event PostStepAction AfterStep;
119
120 // A value of the time 'now' so all the collision and update routines do not have to get their own
121 // Set to 'now' just before all the prims and actors are called for collisions and updates
122 public int SimulationNowTime { get; private set; }
123
124 // True if initialized and ready to do simulation steps
125 private bool m_initialized = false;
126
127 // Flag which is true when processing taints.
128 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
129 public bool InTaintTime { get; private set; }
130
131 // Pinned memory used to pass step information between managed and unmanaged
132 internal int m_maxCollisionsPerFrame;
133 internal CollisionDesc[] m_collisionArray;
134
135 internal int m_maxUpdatesPerFrame;
136 internal EntityProperties[] m_updateArray;
137
138 /// <summary>
139 /// Used to control physics simulation timing if Bullet is running on its own thread.
140 /// </summary>
141 private ManualResetEvent m_updateWaitEvent;
142
143 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
144 public const uint GROUNDPLANE_ID = 1;
145 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
146
147 public float SimpleWaterLevel { get; set; }
148 public BSTerrainManager TerrainManager { get; private set; }
149
150 public ConfigurationParameters Params
151 {
152 get { return UnmanagedParams[0]; }
153 }
154 public Vector3 DefaultGravity
155 {
156 get { return new Vector3(0f, 0f, Params.gravity); }
157 }
158 // Just the Z value of the gravity
159 public float DefaultGravityZ
160 {
161 get { return Params.gravity; }
162 }
163
164 // When functions in the unmanaged code must be called, it is only
165 // done at a known time just before the simulation step. The taint
166 // system saves all these function calls and executes them in
167 // order before the simulation.
168 public delegate void TaintCallback();
169 private struct TaintCallbackEntry
170 {
171 public String originator;
172 public String ident;
173 public TaintCallback callback;
174 public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
175 {
176 originator = BSScene.DetailLogZero;
177 ident = pIdent;
178 callback = pCallBack;
179 }
180 public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
181 {
182 originator = pOrigin;
183 ident = pIdent;
184 callback = pCallBack;
185 }
186 }
187 private Object _taintLock = new Object(); // lock for using the next object
188 private List<TaintCallbackEntry> _taintOperations;
189 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
190 private List<TaintCallbackEntry> _postStepOperations;
191
192 // A pointer to an instance if this structure is passed to the C++ code
193 // Used to pass basic configuration values to the unmanaged code.
194 internal ConfigurationParameters[] UnmanagedParams;
195
196 // Sometimes you just have to log everything.
197 public LogWriter PhysicsLogging;
198 private bool m_physicsLoggingEnabled;
199 private string m_physicsLoggingDir;
200 private string m_physicsLoggingPrefix;
201 private int m_physicsLoggingFileMinutes;
202 private bool m_physicsLoggingDoFlush;
203 private bool m_physicsPhysicalDumpEnabled;
204 public int PhysicsMetricDumpFrames { get; set; }
205 // 'true' of the vehicle code is to log lots of details
206 public bool VehicleLoggingEnabled { get; private set; }
207 public bool VehiclePhysicalLoggingEnabled { get; private set; }
208
209 #region INonSharedRegionModule
210 public string Name
211 {
212 get { return "BulletSim"; }
213 }
214
215 public Type ReplaceableInterface
216 {
217 get { return null; }
218 }
219
220 public void Initialise(IConfigSource source)
221 {
222 // TODO: Move this out of Startup
223 IConfig config = source.Configs["Startup"];
224 if (config != null)
225 {
226 string physics = config.GetString("physics", string.Empty);
227 if (physics == Name)
228 {
229 m_Enabled = true;
230 m_Config = source;
231 }
232 }
233
234 }
235
236 public void Close()
237 {
238 }
239
240 public void AddRegion(Scene scene)
241 {
242 if (!m_Enabled)
243 return;
244
245 EngineType = Name;
246 RegionName = scene.RegionInfo.RegionName;
247 PhysicsSceneName = EngineType + "/" + RegionName;
248
249 scene.RegisterModuleInterface<PhysicsScene>(this);
250 Vector3 extent = new Vector3(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, scene.RegionInfo.RegionSizeZ);
251 Initialise(m_Config, extent);
252
253 base.Initialise(scene.PhysicsRequestAsset,
254 (scene.Heightmap != null ? scene.Heightmap.GetFloatsSerialised() : new float[scene.RegionInfo.RegionSizeX * scene.RegionInfo.RegionSizeY]),
255 (float)scene.RegionInfo.RegionSettings.WaterHeight);
256
257 }
258
259 public void RemoveRegion(Scene scene)
260 {
261 if (!m_Enabled)
262 return;
263 }
264
265 public void RegionLoaded(Scene scene)
266 {
267 if (!m_Enabled)
268 return;
269
270 mesher = scene.RequestModuleInterface<IMesher>();
271 if (mesher == null)
272 m_log.WarnFormat("{0} No mesher. Things will not work well.", LogHeader);
273
274 scene.PhysicsEnabled = true;
275 }
276 #endregion
277
278 #region Initialization
279
280 private void Initialise(IConfigSource config, Vector3 regionExtent)
281 {
282 _taintOperations = new List<TaintCallbackEntry>();
283 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
284 _postStepOperations = new List<TaintCallbackEntry>();
285 PhysObjects = new Dictionary<uint, BSPhysObject>();
286 Shapes = new BSShapeCollection(this);
287
288 m_simulatedTime = 0f;
289 LastTimeStep = 0.1f;
290
291 // Allocate pinned memory to pass parameters.
292 UnmanagedParams = new ConfigurationParameters[1];
293
294 // Set default values for physics parameters plus any overrides from the ini file
295 GetInitialParameterValues(config);
296
297 // Force some parameters to values depending on other configurations
298 // Only use heightmap terrain implementation if terrain larger than legacy size
299 if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
300 {
301 m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
302 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
303 }
304
305 // Get the connection to the physics engine (could be native or one of many DLLs)
306 PE = SelectUnderlyingBulletEngine(BulletEngineName);
307
308 // Enable very detailed logging.
309 // By creating an empty logger when not logging, the log message invocation code
310 // can be left in and every call doesn't have to check for null.
311 if (m_physicsLoggingEnabled)
312 {
313 PhysicsLogging = new LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
314 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
315 }
316 else
317 {
318 PhysicsLogging = new LogWriter();
319 }
320
321 // Allocate memory for returning of the updates and collisions from the physics engine
322 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
323 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
324
325 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
326 // a child in a mega-region.
327 // Bullet actually doesn't care about the extents of the simulated
328 // area. It tracks active objects no matter where they are.
329 Vector3 worldExtent = regionExtent;
330
331 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
332
333 Constraints = new BSConstraintCollection(World);
334
335 TerrainManager = new BSTerrainManager(this, worldExtent);
336 TerrainManager.CreateInitialGroundPlaneAndTerrain();
337
338 // Put some informational messages into the log file.
339 m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
340
341 InTaintTime = false;
342 m_initialized = true;
343
344 // If the physics engine runs on its own thread, start same.
345 if (BSParam.UseSeparatePhysicsThread)
346 {
347 // The physics simulation should happen independently of the heartbeat loop
348 m_physicsThread
349 = WorkManager.StartThread(
350 BulletSPluginPhysicsThread,
351 string.Format("{0} ({1})", BulletEngineName, RegionName),
352 ThreadPriority.Normal,
353 true,
354 true);
355 }
356 }
357
358 // All default parameter values are set here. There should be no values set in the
359 // variable definitions.
360 private void GetInitialParameterValues(IConfigSource config)
361 {
362 ConfigurationParameters parms = new ConfigurationParameters();
363 UnmanagedParams[0] = parms;
364
365 BSParam.SetParameterDefaultValues(this);
366
367 if (config != null)
368 {
369 // If there are specifications in the ini file, use those values
370 IConfig pConfig = config.Configs["BulletSim"];
371 if (pConfig != null)
372 {
373 BSParam.SetParameterConfigurationValues(this, pConfig);
374
375 // There are two Bullet implementations to choose from
376 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
377
378 // Very detailed logging for physics debugging
379 // TODO: the boolean values can be moved to the normal parameter processing.
380 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
381 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
382 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
383 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
384 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
385 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
386 // Very detailed logging for vehicle debugging
387 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
388 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
389
390 // Do any replacements in the parameters
391 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
392 }
393 else
394 {
395 // Nothing in the configuration INI file so assume unmanaged and other defaults.
396 BulletEngineName = "BulletUnmanaged";
397 m_physicsLoggingEnabled = false;
398 VehicleLoggingEnabled = false;
399 }
400
401 // The material characteristics.
402 BSMaterials.InitializeFromDefaults(Params);
403 if (pConfig != null)
404 {
405 // Let the user add new and interesting material property values.
406 BSMaterials.InitializefromParameters(pConfig);
407 }
408 }
409 }
410
411 // A helper function that handles a true/false parameter and returns the proper float number encoding
412 float ParamBoolean(IConfig config, string parmName, float deflt)
413 {
414 float ret = deflt;
415 if (config.Contains(parmName))
416 {
417 ret = ConfigurationParameters.numericFalse;
418 if (config.GetBoolean(parmName, false))
419 {
420 ret = ConfigurationParameters.numericTrue;
421 }
422 }
423 return ret;
424 }
425
426 // Select the connection to the actual Bullet implementation.
427 // The main engine selection is the engineName up to the first hypen.
428 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
429 // is passed to the engine to do its special selection, etc.
430 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
431 {
432 // For the moment, do a simple switch statement.
433 // Someday do fancyness with looking up the interfaces in the assembly.
434 BSAPITemplate ret = null;
435
436 string selectionName = engineName.ToLower();
437 int hyphenIndex = engineName.IndexOf("-");
438 if (hyphenIndex > 0)
439 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
440
441 switch (selectionName)
442 {
443 case "bullet":
444 case "bulletunmanaged":
445 ret = new BSAPIUnman(engineName, this);
446 break;
447 case "bulletxna":
448 ret = new BSAPIXNA(engineName, this);
449 // Disable some features that are not implemented in BulletXNA
450 m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
451 m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
452 BSParam.ShouldUseBulletHACD = false;
453 m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
454 BSParam.ShouldUseSingleConvexHullForPrims = false;
455 m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
456 BSParam.ShouldUseGImpactShapeForPrims = false;
457 m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
458 BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
459 break;
460 }
461
462 if (ret == null)
463 {
464 m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
465 }
466 else
467 {
468 m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
469 }
470
471 return ret;
472 }
473
474 public override void Dispose()
475 {
476 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
477
478 // make sure no stepping happens while we're deleting stuff
479 m_initialized = false;
480
481 lock (PhysObjects)
482 {
483 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
484 {
485 kvp.Value.Destroy();
486 }
487 PhysObjects.Clear();
488 }
489
490 // Now that the prims are all cleaned up, there should be no constraints left
491 if (Constraints != null)
492 {
493 Constraints.Dispose();
494 Constraints = null;
495 }
496
497 if (Shapes != null)
498 {
499 Shapes.Dispose();
500 Shapes = null;
501 }
502
503 if (TerrainManager != null)
504 {
505 TerrainManager.ReleaseGroundPlaneAndTerrain();
506 TerrainManager.Dispose();
507 TerrainManager = null;
508 }
509
510 // Anything left in the unmanaged code should be cleaned out
511 PE.Shutdown(World);
512
513 // Not logging any more
514 PhysicsLogging.Close();
515 }
516 #endregion // Construction and Initialization
517
518 #region Prim and Avatar addition and removal
519
520 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
521 {
522 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
523 return null;
524 }
525
526 public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
527 {
528 // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
529
530 if (!m_initialized) return null;
531
532 BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying);
533 lock (PhysObjects)
534 PhysObjects.Add(localID, actor);
535
536 // TODO: Remove kludge someday.
537 // We must generate a collision for avatars whether they collide or not.
538 // This is required by OpenSim to update avatar animations, etc.
539 lock (AvatarsInSceneLock)
540 AvatarsInScene.Add(actor);
541
542 return actor;
543 }
544
545 public override void RemoveAvatar(PhysicsActor actor)
546 {
547 // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
548
549 if (!m_initialized) return;
550
551 BSCharacter bsactor = actor as BSCharacter;
552 if (bsactor != null)
553 {
554 try
555 {
556 lock (PhysObjects)
557 PhysObjects.Remove(bsactor.LocalID);
558 // Remove kludge someday
559 lock (AvatarsInSceneLock)
560 AvatarsInScene.Remove(bsactor);
561 }
562 catch (Exception e)
563 {
564 m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
565 }
566 bsactor.Destroy();
567 // bsactor.dispose();
568 }
569 else
570 {
571 m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
572 LogHeader, actor.LocalID, actor.GetType().Name);
573 }
574 }
575
576 public override void RemovePrim(PhysicsActor prim)
577 {
578 if (!m_initialized) return;
579
580 BSPhysObject bsprim = prim as BSPhysObject;
581 if (bsprim != null)
582 {
583 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
584 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
585 try
586 {
587 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
588 }
589 catch (Exception e)
590 {
591 m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
592 }
593 bsprim.Destroy();
594 // bsprim.dispose();
595 }
596 else
597 {
598 m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
599 }
600 }
601
602 public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
603 Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
604 {
605 // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
606
607 if (!m_initialized) return null;
608
609 // DetailLog("{0},BSScene.AddPrimShape,call", localID);
610
611 BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
612 lock (PhysObjects) PhysObjects.Add(localID, prim);
613 return prim;
614 }
615
616 // This is a call from the simulator saying that some physical property has been updated.
617 // The BulletSim driver senses the changing of relevant properties so this taint
618 // information call is not needed.
619 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
620
621 #endregion // Prim and Avatar addition and removal
622
623 #region Simulation
624
625 // Call from the simulator to send physics information to the simulator objects.
626 // This pushes all the collision and property update events into the objects in
627 // the simulator and, since it is on the heartbeat thread, there is an implicit
628 // locking of those data structures from other heartbeat events.
629 // If the physics engine is running on a separate thread, the update information
630 // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
631 public override float Simulate(float timeStep)
632 {
633 if (!BSParam.UseSeparatePhysicsThread)
634 {
635 DoPhysicsStep(timeStep);
636 }
637 return SendUpdatesToSimulator(timeStep);
638 }
639
640 // Call the physics engine to do one 'timeStep' and collect collisions and updates
641 // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
642 private void DoPhysicsStep(float timeStep)
643 {
644 // prevent simulation until we've been initialized
645 if (!m_initialized) return;
646
647 LastTimeStep = timeStep;
648
649 int updatedEntityCount = 0;
650 int collidersCount = 0;
651
652 int beforeTime = Util.EnvironmentTickCount();
653 int simTime = 0;
654
655 int numTaints = _taintOperations.Count;
656 InTaintTime = true; // Only used for debugging so locking is not necessary.
657
658 // update the prim states while we know the physics engine is not busy
659 ProcessTaints();
660
661 // Some of the physical objects requre individual, pre-step calls
662 // (vehicles and avatar movement, in particular)
663 TriggerPreStepEvent(timeStep);
664
665 // the prestep actions might have added taints
666 numTaints += _taintOperations.Count;
667 ProcessTaints();
668
669 InTaintTime = false; // Only used for debugging so locking is not necessary.
670
671 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
672 // Only enable this in a limited test world with few objects.
673 if (m_physicsPhysicalDumpEnabled)
674 PE.DumpAllInfo(World);
675
676 // step the physical world one interval
677 m_simulationStep++;
678 int numSubSteps = 0;
679 try
680 {
681 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
682
683 }
684 catch (Exception e)
685 {
686 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
687 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
688 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
689 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
690 updatedEntityCount = 0;
691 collidersCount = 0;
692 }
693
694 // Make the physics engine dump useful statistics periodically
695 if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
696 PE.DumpPhysicsStatistics(World);
697
698 // Get a value for 'now' so all the collision and update routines don't have to get their own.
699 SimulationNowTime = Util.EnvironmentTickCount();
700
701 // Send collision information to the colliding objects. The objects decide if the collision
702 // is 'real' (like linksets don't collide with themselves) and the individual objects
703 // know if the simulator has subscribed to collisions.
704 lock (CollisionLock)
705 {
706 if (collidersCount > 0)
707 {
708 lock (PhysObjects)
709 {
710 for (int ii = 0; ii < collidersCount; ii++)
711 {
712 uint cA = m_collisionArray[ii].aID;
713 uint cB = m_collisionArray[ii].bID;
714 Vector3 point = m_collisionArray[ii].point;
715 Vector3 normal = m_collisionArray[ii].normal;
716 float penetration = m_collisionArray[ii].penetration;
717 SendCollision(cA, cB, point, normal, penetration);
718 SendCollision(cB, cA, point, -normal, penetration);
719 }
720 }
721 }
722 }
723
724 // If any of the objects had updated properties, tell the managed objects about the update
725 // and remember that there was a change so it will be passed to the simulator.
726 lock (UpdateLock)
727 {
728 if (updatedEntityCount > 0)
729 {
730 lock (PhysObjects)
731 {
732 for (int ii = 0; ii < updatedEntityCount; ii++)
733 {
734 EntityProperties entprop = m_updateArray[ii];
735 BSPhysObject pobj;
736 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
737 {
738 if (pobj.IsInitialized)
739 pobj.UpdateProperties(entprop);
740 }
741 }
742 }
743 }
744 }
745
746 // Some actors want to know when the simulation step is complete.
747 TriggerPostStepEvent(timeStep);
748
749 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
750 if (PhysicsLogging.Enabled)
751 {
752 DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
753 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
754 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
755 }
756
757 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
758 // Only enable this in a limited test world with few objects.
759 if (m_physicsPhysicalDumpEnabled)
760 PE.DumpAllInfo(World);
761
762 // The physics engine returns the number of milliseconds it simulated this call.
763 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
764 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
765 m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
766 }
767
768 // Called by a BSPhysObject to note that it has changed properties and this information
769 // should be passed up to the simulator at the proper time.
770 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
771 // this is is under UpdateLock.
772 public void PostUpdate(BSPhysObject updatee)
773 {
774 lock (UpdateLock)
775 {
776 ObjectsWithUpdates.Add(updatee);
777 }
778 }
779
780 // The simulator thinks it is physics time so return all the collisions and position
781 // updates that were collected in actual physics simulation.
782 private float SendUpdatesToSimulator(float timeStep)
783 {
784 if (!m_initialized) return 5.0f;
785
786 DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
787 BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
788 // Push the collisions into the simulator.
789 lock (CollisionLock)
790 {
791 if (ObjectsWithCollisions.Count > 0)
792 {
793 foreach (BSPhysObject bsp in ObjectsWithCollisions)
794 if (!bsp.SendCollisions())
795 {
796 // If the object is done colliding, see that it's removed from the colliding list
797 ObjectsWithNoMoreCollisions.Add(bsp);
798 }
799 }
800
801 // This is a kludge to get avatar movement updates.
802 // The simulator expects collisions for avatars even if there are have been no collisions.
803 // The event updates avatar animations and stuff.
804 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
805 // Note that we get a copy of the list to search because SendCollision() can take a while.
806 HashSet<BSPhysObject> tempAvatarsInScene;
807 lock (AvatarsInSceneLock)
808 {
809 tempAvatarsInScene = new HashSet<BSPhysObject>(AvatarsInScene);
810 }
811 foreach (BSPhysObject actor in tempAvatarsInScene)
812 {
813 if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
814 actor.SendCollisions();
815 }
816 tempAvatarsInScene = null;
817
818 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
819 // Not done above because it is inside an iteration of ObjectWithCollisions.
820 // This complex collision processing is required to create an empty collision
821 // event call after all real collisions have happened on an object. This allows
822 // the simulator to generate the 'collision end' event.
823 if (ObjectsWithNoMoreCollisions.Count > 0)
824 {
825 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
826 ObjectsWithCollisions.Remove(po);
827 ObjectsWithNoMoreCollisions.Clear();
828 }
829 }
830
831 // Call the simulator for each object that has physics property updates.
832 HashSet<BSPhysObject> updatedObjects = null;
833 lock (UpdateLock)
834 {
835 if (ObjectsWithUpdates.Count > 0)
836 {
837 updatedObjects = ObjectsWithUpdates;
838 ObjectsWithUpdates = new HashSet<BSPhysObject>();
839 }
840 }
841 if (updatedObjects != null)
842 {
843 foreach (BSPhysObject obj in updatedObjects)
844 {
845 obj.RequestPhysicsterseUpdate();
846 }
847 updatedObjects.Clear();
848 }
849
850 // Return the framerate simulated to give the above returned results.
851 // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
852 float simTime = m_simulatedTime;
853 m_simulatedTime = 0f;
854 return simTime;
855 }
856
857 // Something has collided
858 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
859 {
860 if (localID <= TerrainManager.HighestTerrainID)
861 {
862 return; // don't send collisions to the terrain
863 }
864
865 BSPhysObject collider;
866 // NOTE that PhysObjects was locked before the call to SendCollision().
867 if (!PhysObjects.TryGetValue(localID, out collider))
868 {
869 // If the object that is colliding cannot be found, just ignore the collision.
870 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
871 return;
872 }
873
874 // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
875 BSPhysObject collidee = null;
876 PhysObjects.TryGetValue(collidingWith, out collidee);
877
878 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
879
880 if (collider.IsInitialized)
881 {
882 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
883 {
884 // If a collision was 'good', remember to send it to the simulator
885 lock (CollisionLock)
886 {
887 ObjectsWithCollisions.Add(collider);
888 }
889 }
890 }
891
892 return;
893 }
894
895 public void BulletSPluginPhysicsThread()
896 {
897 Thread.CurrentThread.Priority = ThreadPriority.Highest;
898 m_updateWaitEvent = new ManualResetEvent(false);
899
900 while (m_initialized)
901 {
902 int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
903
904 if (BSParam.Active)
905 DoPhysicsStep(BSParam.PhysicsTimeStep);
906
907 int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
908 int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
909
910 if (simulationTimeVsRealtimeDifferenceMS > 0)
911 {
912 // The simulation of the time interval took less than realtime.
913 // Do a wait for the rest of realtime.
914 m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
915 //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
916 }
917 else
918 {
919 // The simulation took longer than realtime.
920 // Do some scaling of simulation time.
921 // TODO.
922 DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
923 }
924
925 Watchdog.UpdateThread();
926 }
927
928 Watchdog.RemoveThread();
929 }
930
931 #endregion // Simulation
932
933 public override void GetResults() { }
934
935 #region Terrain
936
937 public override void SetTerrain(float[] heightMap) {
938 TerrainManager.SetTerrain(heightMap);
939 }
940
941 public override void SetWaterLevel(float baseheight)
942 {
943 SimpleWaterLevel = baseheight;
944 }
945
946 public override void DeleteTerrain()
947 {
948 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
949 }
950
951 // Although no one seems to check this, I do support combining.
952 public override bool SupportsCombining()
953 {
954 return TerrainManager.SupportsCombining();
955 }
956 // This call says I am a child to region zero in a mega-region. 'pScene' is that
957 // of region zero, 'offset' is my offset from regions zero's origin, and
958 // 'extents' is the largest XY that is handled in my region.
959 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
960 {
961 TerrainManager.Combine(pScene, offset, extents);
962 }
963
964 // Unhook all the combining that I know about.
965 public override void UnCombine(PhysicsScene pScene)
966 {
967 TerrainManager.UnCombine(pScene);
968 }
969
970 #endregion // Terrain
971
972 public override Dictionary<uint, float> GetTopColliders()
973 {
974 Dictionary<uint, float> topColliders;
975
976 lock (PhysObjects)
977 {
978 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
979 {
980 kvp.Value.ComputeCollisionScore();
981 }
982
983 List<BSPhysObject> orderedPrims = new List<BSPhysObject>(PhysObjects.Values);
984 orderedPrims.OrderByDescending(p => p.CollisionScore);
985 topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
986 }
987
988 return topColliders;
989 }
990
991 public override bool IsThreaded { get { return false; } }
992
993 #region Extensions
994 public override object Extension(string pFunct, params object[] pParams)
995 {
996 DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
997 return base.Extension(pFunct, pParams);
998 }
999 #endregion // Extensions
1000
1001 public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
1002 {
1003 float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f;
1004 float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f;
1005 float pathBegin = (float)pbs.PathBegin * 2.0e-5f;
1006 float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f;
1007 float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f;
1008 float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f;
1009 float pathTaperX = pbs.PathTaperX * 0.01f;
1010 float pathTaperY = pbs.PathTaperY * 0.01f;
1011
1012 float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f;
1013 float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f;
1014 float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f;
1015 if (profileHollow > 0.95f)
1016 profileHollow = 0.95f;
1017
1018 StringBuilder buff = new StringBuilder();
1019 buff.Append("shape=");
1020 buff.Append(((ProfileShape)pbs.ProfileShape).ToString());
1021 buff.Append(",");
1022 buff.Append("hollow=");
1023 buff.Append(((HollowShape)pbs.HollowShape).ToString());
1024 buff.Append(",");
1025 buff.Append("pathCurve=");
1026 buff.Append(((Extrusion)pbs.PathCurve).ToString());
1027 buff.Append(",");
1028 buff.Append("profCurve=");
1029 buff.Append(((Extrusion)pbs.ProfileCurve).ToString());
1030 buff.Append(",");
1031 buff.Append("profHollow=");
1032 buff.Append(profileHollow.ToString());
1033 buff.Append(",");
1034 buff.Append("pathBegEnd=");
1035 buff.Append(pathBegin.ToString());
1036 buff.Append("/");
1037 buff.Append(pathEnd.ToString());
1038 buff.Append(",");
1039 buff.Append("profileBegEnd=");
1040 buff.Append(profileBegin.ToString());
1041 buff.Append("/");
1042 buff.Append(profileEnd.ToString());
1043 buff.Append(",");
1044 buff.Append("scaleXY=");
1045 buff.Append(pathScaleX.ToString());
1046 buff.Append("/");
1047 buff.Append(pathScaleY.ToString());
1048 buff.Append(",");
1049 buff.Append("shearXY=");
1050 buff.Append(pathShearX.ToString());
1051 buff.Append("/");
1052 buff.Append(pathShearY.ToString());
1053 buff.Append(",");
1054 buff.Append("taperXY=");
1055 buff.Append(pbs.PathTaperX.ToString());
1056 buff.Append("/");
1057 buff.Append(pbs.PathTaperY.ToString());
1058 buff.Append(",");
1059 buff.Append("skew=");
1060 buff.Append(pbs.PathSkew.ToString());
1061 buff.Append(",");
1062 buff.Append("twist/Beg=");
1063 buff.Append(pbs.PathTwist.ToString());
1064 buff.Append("/");
1065 buff.Append(pbs.PathTwistBegin.ToString());
1066
1067 return buff.ToString();
1068 }
1069
1070 #region Taints
1071 // The simulation execution order is:
1072 // Simulate()
1073 // DoOneTimeTaints
1074 // TriggerPreStepEvent
1075 // DoOneTimeTaints
1076 // Step()
1077 // ProcessAndSendToSimulatorCollisions
1078 // ProcessAndSendToSimulatorPropertyUpdates
1079 // TriggerPostStepEvent
1080
1081 // Calls to the PhysicsActors can't directly call into the physics engine
1082 // because it might be busy. We delay changes to a known time.
1083 // We rely on C#'s closure to save and restore the context for the delegate.
1084 public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
1085 {
1086 TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
1087 }
1088 public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
1089 {
1090 TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1091 }
1092 public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
1093 {
1094 TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
1095 }
1096 public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
1097 {
1098 TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
1099 }
1100 // Sometimes a potentially tainted operation can be used in and out of taint time.
1101 // This routine executes the command immediately if in taint-time otherwise it is queued.
1102 public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
1103 {
1104 if (!m_initialized) return;
1105
1106 if (inTaintTime)
1107 pCallback();
1108 else
1109 {
1110 lock (_taintLock)
1111 {
1112 _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
1113 }
1114 }
1115 }
1116
1117 private void TriggerPreStepEvent(float timeStep)
1118 {
1119 PreStepAction actions = BeforeStep;
1120 if (actions != null)
1121 actions(timeStep);
1122
1123 }
1124
1125 private void TriggerPostStepEvent(float timeStep)
1126 {
1127 PostStepAction actions = AfterStep;
1128 if (actions != null)
1129 actions(timeStep);
1130
1131 }
1132
1133 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
1134 // a callback into itself to do the actual property change. That callback is called
1135 // here just before the physics engine is called to step the simulation.
1136 public void ProcessTaints()
1137 {
1138 ProcessRegularTaints();
1139 ProcessPostTaintTaints();
1140 }
1141
1142 private void ProcessRegularTaints()
1143 {
1144 if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
1145 {
1146 // swizzle a new list into the list location so we can process what's there
1147 List<TaintCallbackEntry> oldList;
1148 lock (_taintLock)
1149 {
1150 oldList = _taintOperations;
1151 _taintOperations = new List<TaintCallbackEntry>();
1152 }
1153
1154 foreach (TaintCallbackEntry tcbe in oldList)
1155 {
1156 try
1157 {
1158 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
1159 tcbe.callback();
1160 }
1161 catch (Exception e)
1162 {
1163 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
1164 }
1165 }
1166 oldList.Clear();
1167 }
1168 }
1169
1170 // Schedule an update to happen after all the regular taints are processed.
1171 // Note that new requests for the same operation ("ident") for the same object ("ID")
1172 // will replace any previous operation by the same object.
1173 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
1174 {
1175 string IDAsString = ID.ToString();
1176 string uniqueIdent = ident + "-" + IDAsString;
1177 lock (_taintLock)
1178 {
1179 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
1180 }
1181
1182 return;
1183 }
1184
1185 // Taints that happen after the normal taint processing but before the simulation step.
1186 private void ProcessPostTaintTaints()
1187 {
1188 if (m_initialized && _postTaintOperations.Count > 0)
1189 {
1190 Dictionary<string, TaintCallbackEntry> oldList;
1191 lock (_taintLock)
1192 {
1193 oldList = _postTaintOperations;
1194 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
1195 }
1196
1197 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
1198 {
1199 try
1200 {
1201 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
1202 kvp.Value.callback();
1203 }
1204 catch (Exception e)
1205 {
1206 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
1207 }
1208 }
1209 oldList.Clear();
1210 }
1211 }
1212
1213 // Only used for debugging. Does not change state of anything so locking is not necessary.
1214 public bool AssertInTaintTime(string whereFrom)
1215 {
1216 if (!InTaintTime)
1217 {
1218 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
1219 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
1220 // Util.PrintCallStack(DetailLog);
1221 }
1222 return InTaintTime;
1223 }
1224
1225 #endregion // Taints
1226
1227 #region IPhysicsParameters
1228 // Get the list of parameters this physics engine supports
1229 public PhysParameterEntry[] GetParameterList()
1230 {
1231 BSParam.BuildParameterTable();
1232 return BSParam.SettableParameters;
1233 }
1234
1235 // Set parameter on a specific or all instances.
1236 // Return 'false' if not able to set the parameter.
1237 // Setting the value in the m_params block will change the value the physics engine
1238 // will use the next time since it's pinned and shared memory.
1239 // Some of the values require calling into the physics engine to get the new
1240 // value activated ('terrainFriction' for instance).
1241 public bool SetPhysicsParameter(string parm, string val, uint localID)
1242 {
1243 bool ret = false;
1244
1245 BSParam.ParameterDefnBase theParam;
1246 if (BSParam.TryGetParameter(parm, out theParam))
1247 {
1248 // Set the value in the C# code
1249 theParam.SetValue(this, val);
1250
1251 // Optionally set the parameter in the unmanaged code
1252 if (theParam.HasSetOnObject)
1253 {
1254 // update all the localIDs specified
1255 // If the local ID is APPLY_TO_NONE, just change the default value
1256 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1257 // If the localID is a specific object, apply the parameter change to only that object
1258 List<uint> objectIDs = new List<uint>();
1259 switch (localID)
1260 {
1261 case PhysParameterEntry.APPLY_TO_NONE:
1262 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1263 objectIDs.Add(TERRAIN_ID);
1264 TaintedUpdateParameter(parm, objectIDs, val);
1265 break;
1266 case PhysParameterEntry.APPLY_TO_ALL:
1267 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1268 TaintedUpdateParameter(parm, objectIDs, val);
1269 break;
1270 default:
1271 // setting only one localID
1272 objectIDs.Add(localID);
1273 TaintedUpdateParameter(parm, objectIDs, val);
1274 break;
1275 }
1276 }
1277
1278 ret = true;
1279 }
1280 return ret;
1281 }
1282
1283 // schedule the actual updating of the paramter to when the phys engine is not busy
1284 private void TaintedUpdateParameter(string parm, List<uint> lIDs, string val)
1285 {
1286 string xval = val;
1287 List<uint> xlIDs = lIDs;
1288 string xparm = parm;
1289 TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
1290 BSParam.ParameterDefnBase thisParam;
1291 if (BSParam.TryGetParameter(xparm, out thisParam))
1292 {
1293 if (thisParam.HasSetOnObject)
1294 {
1295 foreach (uint lID in xlIDs)
1296 {
1297 BSPhysObject theObject = null;
1298 if (PhysObjects.TryGetValue(lID, out theObject))
1299 thisParam.SetOnObject(this, theObject);
1300 }
1301 }
1302 }
1303 });
1304 }
1305
1306 // Get parameter.
1307 // Return 'false' if not able to get the parameter.
1308 public bool GetPhysicsParameter(string parm, out string value)
1309 {
1310 string val = String.Empty;
1311 bool ret = false;
1312 BSParam.ParameterDefnBase theParam;
1313 if (BSParam.TryGetParameter(parm, out theParam))
1314 {
1315 val = theParam.GetValue(this);
1316 ret = true;
1317 }
1318 value = val;
1319 return ret;
1320 }
1321
1322 #endregion IPhysicsParameters
1323
1324 // Invoke the detailed logger and output something if it's enabled.
1325 public void DetailLog(string msg, params Object[] args)
1326 {
1327 PhysicsLogging.Write(msg, args);
1328 }
1329 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1330 public const string DetailLogZero = "0000000000";
1331
1332 }
1333}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
new file mode 100755
index 0000000..b100273
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
@@ -0,0 +1,425 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.PhysicsModules.SharedBase;
33using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37public sealed class BSShapeCollection : IDisposable
38{
39#pragma warning disable 414
40 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
41#pragma warning restore 414
42
43 private BSScene m_physicsScene { get; set; }
44
45 private Object m_collectionActivityLock = new Object();
46
47 private bool DDetail = false;
48
49 public BSShapeCollection(BSScene physScene)
50 {
51 m_physicsScene = physScene;
52 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
53 // While detailed debugging is still active, this is better than commenting out all the
54 // DetailLog statements. When debugging slows down, this and the protected logging
55 // statements can be commented/removed.
56 DDetail = true;
57 }
58
59 public void Dispose()
60 {
61 // TODO!!!!!!!!!
62 }
63
64 // Callbacks called just before either the body or shape is destroyed.
65 // Mostly used for changing bodies out from under Linksets.
66 // Useful for other cases where parameters need saving.
67 // Passing 'null' says no callback.
68 public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
69
70 // Called to update/change the body and shape for an object.
71 // The object has some shape and body on it. Here we decide if that is the correct shape
72 // for the current state of the object (static/dynamic/...).
73 // If bodyCallback is not null, it is called if either the body or the shape are changed
74 // so dependencies (like constraints) can be removed before the physical object is dereferenced.
75 // Return 'true' if either the body or the shape changed.
76 // Called at taint-time.
77 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
78 {
79 m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
80
81 bool ret = false;
82
83 // This lock could probably be pushed down lower but building shouldn't take long
84 lock (m_collectionActivityLock)
85 {
86 // Do we have the correct geometry for this type of object?
87 // Updates prim.BSShape with information/pointers to shape.
88 // Returns 'true' of BSShape is changed to a new shape.
89 bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
90 // If we had to select a new shape geometry for the object,
91 // rebuild the body around it.
92 // Updates prim.BSBody with information/pointers to requested body
93 // Returns 'true' if BSBody was changed.
94 bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
95 ret = newGeom || newBody;
96 }
97 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
98 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
99
100 return ret;
101 }
102
103 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
104 {
105 return GetBodyAndShape(forceRebuild, sim, prim, null);
106 }
107
108 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
109 // before replacing it.
110 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
111 {
112 if (prim.PhysShape.HasPhysicalShape)
113 {
114 if (shapeCallback != null)
115 shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
116 prim.PhysShape.Dereference(m_physicsScene);
117 }
118 prim.PhysShape = new BSShapeNull();
119 }
120
121 // Create the geometry information in Bullet for later use.
122 // The objects needs a hull if it's physical otherwise a mesh is enough.
123 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
124 // shared geometries will be used. If the parameters of the existing shape are the same
125 // as this request, the shape is not rebuilt.
126 // Info in prim.BSShape is updated to the new shape.
127 // Returns 'true' if the geometry was rebuilt.
128 // Called at taint-time!
129 public const int AvatarShapeCapsule = 0;
130 public const int AvatarShapeCube = 1;
131 public const int AvatarShapeOvoid = 2;
132 public const int AvatarShapeMesh = 3;
133 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
134 {
135 bool ret = false;
136 bool haveShape = false;
137 bool nativeShapePossible = true;
138 PrimitiveBaseShape pbs = prim.BaseShape;
139
140 // Kludge to create the capsule for the avatar.
141 // TDOD: Remove/redo this when BSShapeAvatar is working!!
142 BSCharacter theChar = prim as BSCharacter;
143 if (theChar != null)
144 {
145 DereferenceExistingShape(prim, shapeCallback);
146 switch (BSParam.AvatarShape)
147 {
148 case AvatarShapeCapsule:
149 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
150 BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
151 ret = true;
152 haveShape = true;
153 break;
154 case AvatarShapeCube:
155 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
156 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE);
157 ret = true;
158 haveShape = true;
159 break;
160 case AvatarShapeOvoid:
161 // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape
162 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
163 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE);
164 ret = true;
165 haveShape = true;
166 break;
167 case AvatarShapeMesh:
168 break;
169 default:
170 break;
171 }
172 }
173
174 // If the prim attributes are simple, this could be a simple Bullet native shape
175 // Native shapes work whether to object is static or physical.
176 if (!haveShape
177 && nativeShapePossible
178 && pbs != null
179 && PrimHasNoCuts(pbs)
180 && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
181 )
182 {
183 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
184 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
185 if (prim.PhysShape.HasPhysicalShape)
186 scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
187
188 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
189 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
190
191 // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
192 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
193 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
194 {
195 haveShape = true;
196 if (forceRebuild
197 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
198 )
199 {
200 DereferenceExistingShape(prim, shapeCallback);
201 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
202 BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
203 ret = true;
204 }
205 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
206 prim.LocalID, forceRebuild, ret, prim.PhysShape);
207 }
208 // If we didn't make a sphere, maybe a box will work.
209 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
210 {
211 haveShape = true;
212 if (forceRebuild
213 || prim.Scale != scaleOfExistingShape
214 || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
215 )
216 {
217 DereferenceExistingShape(prim, shapeCallback);
218 prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
219 BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
220 ret = true;
221 }
222 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
223 prim.LocalID, forceRebuild, ret, prim.PhysShape);
224 }
225 }
226
227 // If a simple shape is not happening, create a mesh and possibly a hull.
228 if (!haveShape && pbs != null)
229 {
230 ret = CreateGeomMeshOrHull(prim, shapeCallback);
231 }
232
233 return ret;
234 }
235
236 // return 'true' if this shape description does not include any cutting or twisting.
237 public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
238 {
239 return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
240 && pbs.ProfileHollow == 0
241 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
242 && pbs.PathBegin == 0 && pbs.PathEnd == 0
243 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
244 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
245 && pbs.PathShearX == 0 && pbs.PathShearY == 0;
246 }
247
248 // return 'true' if the prim's shape was changed.
249 private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
250 {
251
252 bool ret = false;
253 // Note that if it's a native shape, the check for physical/non-physical is not
254 // made. Native shapes work in either case.
255 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
256 {
257 // Use a simple, single mesh convex hull shape if the object is simple enough
258 BSShape potentialHull = null;
259
260 PrimitiveBaseShape pbs = prim.BaseShape;
261 // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
262 if (BSParam.ShouldUseSingleConvexHullForPrims
263 && pbs != null
264 && !pbs.SculptEntry
265 && PrimHasNoCuts(pbs)
266 )
267 {
268 potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
269 }
270 // Use the GImpact shape if it is a prim that has some concaveness
271 if (potentialHull == null
272 && BSParam.ShouldUseGImpactShapeForPrims
273 && pbs != null
274 && !pbs.SculptEntry
275 )
276 {
277 potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
278 }
279 // If not any of the simple cases, just make a hull
280 if (potentialHull == null)
281 {
282 potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
283 }
284
285 // If the current shape is not what is on the prim at the moment, time to change.
286 if (!prim.PhysShape.HasPhysicalShape
287 || potentialHull.ShapeType != prim.PhysShape.ShapeType
288 || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
289 {
290 DereferenceExistingShape(prim, shapeCallback);
291 prim.PhysShape = potentialHull;
292 ret = true;
293 }
294 else
295 {
296 // The current shape on the prim is the correct one. We don't need the potential reference.
297 potentialHull.Dereference(m_physicsScene);
298 }
299 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
300 }
301 else
302 {
303 // Non-physical objects should be just meshes.
304 BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
305 // If the current shape is not what is on the prim at the moment, time to change.
306 if (!prim.PhysShape.HasPhysicalShape
307 || potentialMesh.ShapeType != prim.PhysShape.ShapeType
308 || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
309 {
310 DereferenceExistingShape(prim, shapeCallback);
311 prim.PhysShape = potentialMesh;
312 ret = true;
313 }
314 else
315 {
316 // We don't need this reference to the mesh that is already being using.
317 potentialMesh.Dereference(m_physicsScene);
318 }
319 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
320 }
321 return ret;
322 }
323
324 // Track another user of a body.
325 // We presume the caller has allocated the body.
326 // Bodies only have one user so the body is just put into the world if not already there.
327 private void ReferenceBody(BulletBody body)
328 {
329 lock (m_collectionActivityLock)
330 {
331 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
332 if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
333 {
334 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
335 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
336 }
337 }
338 }
339
340 // Release the usage of a body.
341 // Called when releasing use of a BSBody. BSShape is handled separately.
342 // Called in taint time.
343 public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
344 {
345 if (!body.HasPhysicalBody)
346 return;
347
348 m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
349
350 lock (m_collectionActivityLock)
351 {
352 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
353 // If the caller needs to know the old body is going away, pass the event up.
354 if (bodyCallback != null)
355 bodyCallback(body, null);
356
357 // Removing an object not in the world is a NOOP
358 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
359
360 // Zero any reference to the shape so it is not freed when the body is deleted.
361 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
362
363 m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
364 }
365 }
366
367 // Create a body object in Bullet.
368 // Updates prim.BSBody with the information about the new body if one is created.
369 // Returns 'true' if an object was actually created.
370 // Called at taint-time.
371 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
372 {
373 bool ret = false;
374
375 // the mesh, hull or native shape must have already been created in Bullet
376 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
377
378 // If there is an existing body, verify it's of an acceptable type.
379 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
380 if (!mustRebuild)
381 {
382 CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
383 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
384 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
385 {
386 // If the collisionObject is not the correct type for solidness, rebuild what's there
387 mustRebuild = true;
388 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
389 }
390 }
391
392 if (mustRebuild || forceRebuild)
393 {
394 // Free any old body
395 DereferenceBody(prim.PhysBody, bodyCallback);
396
397 BulletBody aBody;
398 if (prim.IsSolid)
399 {
400 aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
401 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
402 }
403 else
404 {
405 aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
406 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
407 }
408
409 ReferenceBody(aBody);
410
411 prim.PhysBody = aBody;
412
413 ret = true;
414 }
415
416 return ret;
417 }
418
419 private void DetailLog(string msg, params Object[] args)
420 {
421 if (m_physicsScene.PhysicsLogging.Enabled)
422 m_physicsScene.DetailLog(msg, args);
423 }
424}
425}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
new file mode 100755
index 0000000..086a412
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
@@ -0,0 +1,1463 @@
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.Text;
31
32using OpenSim.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.PhysicsModules.Meshing;
35using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
36
37using OMV = OpenMetaverse;
38
39namespace OpenSim.Region.PhysicsModule.BulletS
40{
41// Information class that holds stats for the shape. Which values mean
42// something depends on the type of shape.
43// This information is used for debugging and stats and is not used
44// for operational things.
45public class ShapeInfoInfo
46{
47 public int Vertices { get; set; }
48 private int m_hullCount;
49 private int[] m_verticesPerHull;
50 public ShapeInfoInfo()
51 {
52 Vertices = 0;
53 m_hullCount = 0;
54 m_verticesPerHull = null;
55 }
56 public int HullCount
57 {
58 set
59 {
60 m_hullCount = value;
61 m_verticesPerHull = new int[m_hullCount];
62 Array.Clear(m_verticesPerHull, 0, m_hullCount);
63 }
64 get { return m_hullCount; }
65 }
66 public void SetVerticesPerHull(int hullNum, int vertices)
67 {
68 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
69 {
70 m_verticesPerHull[hullNum] = vertices;
71 }
72 }
73 public int GetVerticesPerHull(int hullNum)
74 {
75 if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
76 {
77 return m_verticesPerHull[hullNum];
78 }
79 return 0;
80 }
81 public override string ToString()
82 {
83 StringBuilder buff = new StringBuilder();
84 // buff.Append("ShapeInfo=<");
85 buff.Append("<");
86 if (Vertices > 0)
87 {
88 buff.Append("verts=");
89 buff.Append(Vertices.ToString());
90 }
91
92 if (Vertices > 0 && HullCount > 0) buff.Append(",");
93
94 if (HullCount > 0)
95 {
96 buff.Append("nHulls=");
97 buff.Append(HullCount.ToString());
98 buff.Append(",");
99 buff.Append("hullVerts=");
100 for (int ii = 0; ii < HullCount; ii++)
101 {
102 if (ii != 0) buff.Append(",");
103 buff.Append(GetVerticesPerHull(ii).ToString());
104 }
105 }
106 buff.Append(">");
107 return buff.ToString();
108 }
109}
110
111public abstract class BSShape
112{
113 private static string LogHeader = "[BULLETSIM SHAPE]";
114
115 public int referenceCount { get; set; }
116 public DateTime lastReferenced { get; set; }
117 public BulletShape physShapeInfo { get; set; }
118 public ShapeInfoInfo shapeInfo { get; private set; }
119
120 public BSShape()
121 {
122 referenceCount = 1;
123 lastReferenced = DateTime.Now;
124 physShapeInfo = new BulletShape();
125 shapeInfo = new ShapeInfoInfo();
126 }
127 public BSShape(BulletShape pShape)
128 {
129 referenceCount = 1;
130 lastReferenced = DateTime.Now;
131 physShapeInfo = pShape;
132 shapeInfo = new ShapeInfoInfo();
133 }
134
135 // Get another reference to this shape.
136 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
137
138 // Called when this shape is being used again.
139 // Used internally. External callers should call instance.GetReference() to properly copy/reference
140 // the shape.
141 protected virtual void IncrementReference()
142 {
143 referenceCount++;
144 lastReferenced = DateTime.Now;
145 }
146
147 // Called when this shape is done being used.
148 protected virtual void DecrementReference()
149 {
150 referenceCount--;
151 lastReferenced = DateTime.Now;
152 }
153
154 // Release the use of a physical shape.
155 public abstract void Dereference(BSScene physicsScene);
156
157 // Return 'true' if there is an allocated physics physical shape under this class instance.
158 public virtual bool HasPhysicalShape
159 {
160 get
161 {
162 if (physShapeInfo != null)
163 return physShapeInfo.HasPhysicalShape;
164 return false;
165 }
166 }
167 public virtual BSPhysicsShapeType ShapeType
168 {
169 get
170 {
171 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
172 if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
173 ret = physShapeInfo.shapeType;
174 return ret;
175 }
176 }
177
178 // Returns a string for debugging that uniquily identifies the memory used by this instance
179 public virtual string AddrString
180 {
181 get
182 {
183 if (physShapeInfo != null)
184 return physShapeInfo.AddrString;
185 return "unknown";
186 }
187 }
188
189 public override string ToString()
190 {
191 StringBuilder buff = new StringBuilder();
192 if (physShapeInfo == null)
193 {
194 buff.Append("<noPhys");
195 }
196 else
197 {
198 buff.Append("<phy=");
199 buff.Append(physShapeInfo.ToString());
200 }
201 buff.Append(",c=");
202 buff.Append(referenceCount.ToString());
203 buff.Append(">");
204 return buff.ToString();
205 }
206
207 #region Common shape routines
208 // Create a hash of all the shape parameters to be used as a key for this particular shape.
209 public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
210 {
211 // level of detail based on size and type of the object
212 float lod = BSParam.MeshLOD;
213 if (pbs.SculptEntry)
214 lod = BSParam.SculptLOD;
215
216 // Mega prims usually get more detail because one can interact with shape approximations at this size.
217 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
218 if (maxAxis > BSParam.MeshMegaPrimThreshold)
219 lod = BSParam.MeshMegaPrimLOD;
220
221 retLod = lod;
222 return pbs.GetMeshKey(size, lod);
223 }
224
225 // The creation of a mesh or hull can fail if an underlying asset is not available.
226 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
227 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
228 // The first case causes the asset to be fetched. The second case requires
229 // us to not loop forever.
230 // Called after creating a physical mesh or hull. If the physical shape was created,
231 // just return.
232 public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
233 {
234 // If the shape was successfully created, nothing more to do
235 if (newShape.HasPhysicalShape)
236 return newShape;
237
238 // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
239 // fetched but we end up here again, the meshing of the asset must have failed.
240 // Prevent trying to keep fetching the mesh by declaring failure.
241 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
242 {
243 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
244 physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
245 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
246 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
247 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
248 }
249 else
250 {
251 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
252 if (prim.BaseShape.SculptEntry
253 && !prim.AssetFailed()
254 && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
255 && prim.BaseShape.SculptTexture != OMV.UUID.Zero
256 )
257 {
258 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
259 prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
260 // Multiple requestors will know we're waiting for this asset
261 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
262
263 BSPhysObject xprim = prim;
264 RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
265 if (assetProvider != null)
266 {
267 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
268 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
269 {
270 // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
271 bool assetFound = false;
272 string mismatchIDs = String.Empty; // DEBUG DEBUG
273 if (asset != null && yprim.BaseShape.SculptEntry)
274 {
275 if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
276 {
277 yprim.BaseShape.SculptData = asset.Data;
278 // This will cause the prim to see that the filler shape is not the right
279 // one and try again to build the object.
280 // No race condition with the normal shape setting since the rebuild is at taint time.
281 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
282 yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
283 assetFound = true;
284 }
285 else
286 {
287 mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
288 }
289 }
290 if (!assetFound)
291 {
292 yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
293 }
294 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
295 yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
296 });
297 }
298 else
299 {
300 xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
301 physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
302 LogHeader, physicsScene.PhysicsSceneName);
303 }
304 }
305 else
306 {
307 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
308 {
309 physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
310 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
311 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
312 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
313 }
314 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
315 {
316 physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
317 LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
318 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
319 prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
320 }
321 }
322 }
323
324 // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
325 BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
326 physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
327
328 return fillShape.physShapeInfo;
329 }
330
331 public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
332 {
333 StringBuilder buff = new StringBuilder(prim.PhysObjectName);
334 buff.Append("/pos=");
335 buff.Append(prim.RawPosition.ToString());
336 if (pScene != null)
337 {
338 buff.Append("/rgn=");
339 buff.Append(pScene.PhysicsSceneName);
340 }
341 return buff.ToString();
342 }
343
344 #endregion // Common shape routines
345}
346
347// ============================================================================================================
348public class BSShapeNull : BSShape
349{
350 public BSShapeNull() : base()
351 {
352 }
353 public static BSShape GetReference() { return new BSShapeNull(); }
354 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
355 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
356}
357
358// ============================================================================================================
359// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere.
360// They are odd in that they don't allocate meshes but are computated/procedural.
361// This means allocation and freeing is different than meshes.
362public class BSShapeNative : BSShape
363{
364 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
365 public BSShapeNative(BulletShape pShape) : base(pShape)
366 {
367 }
368
369 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
370 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
371 {
372 // Native shapes are not shared and are always built anew.
373 return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
374 }
375
376 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
377 {
378 // Native shapes are not shared so we return a new shape.
379 BSShape ret = null;
380 lock (physShapeInfo)
381 {
382 ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
383 physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
384 }
385 return ret;
386 }
387
388 // Make this reference to the physical shape go away since native shapes are not shared.
389 public override void Dereference(BSScene physicsScene)
390 {
391 // Native shapes are not tracked and are released immediately
392 lock (physShapeInfo)
393 {
394 if (physShapeInfo.HasPhysicalShape)
395 {
396 physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
397 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
398 }
399 physShapeInfo.Clear();
400 // Garbage collection will free up this instance.
401 }
402 }
403
404 private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
405 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
406 {
407 BulletShape newShape;
408
409 ShapeData nativeShapeData = new ShapeData();
410 nativeShapeData.Type = shapeType;
411 nativeShapeData.ID = prim.LocalID;
412 nativeShapeData.Scale = prim.Scale;
413 nativeShapeData.Size = prim.Scale;
414 nativeShapeData.MeshKey = (ulong)shapeKey;
415 nativeShapeData.HullKey = (ulong)shapeKey;
416
417 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
418 {
419 newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
420 physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
421 }
422 else
423 {
424 newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
425 }
426 if (!newShape.HasPhysicalShape)
427 {
428 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
429 LogHeader, prim.LocalID, shapeType);
430 }
431 newShape.shapeType = shapeType;
432 newShape.isNativeShape = true;
433 newShape.shapeKey = (UInt64)shapeKey;
434 return newShape;
435 }
436
437}
438
439// ============================================================================================================
440// BSShapeMesh is a simple mesh.
441public class BSShapeMesh : BSShape
442{
443 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
444 public static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
445
446 public BSShapeMesh(BulletShape pShape) : base(pShape)
447 {
448 }
449 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
450 {
451 float lod;
452 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
453
454 BSShapeMesh retMesh = null;
455 lock (Meshes)
456 {
457 if (Meshes.TryGetValue(newMeshKey, out retMesh))
458 {
459 // The mesh has already been created. Return a new reference to same.
460 retMesh.IncrementReference();
461 }
462 else
463 {
464 retMesh = new BSShapeMesh(new BulletShape());
465 // An instance of this mesh has not been created. Build and remember same.
466 BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
467
468 // Check to see if mesh was created (might require an asset).
469 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
470 if (!newShape.isNativeShape || prim.AssetFailed() )
471 {
472 // If a mesh was what was created, remember the built shape for later sharing.
473 // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
474 Meshes.Add(newMeshKey, retMesh);
475 }
476
477 retMesh.physShapeInfo = newShape;
478 }
479 }
480 physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
481 return retMesh;
482 }
483 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
484 {
485 BSShape ret = null;
486 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
487 // and we must create a copy of the native shape since they are never shared.
488 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
489 {
490 // TODO: decide when the native shapes should be freed. Check in Dereference?
491 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
492 }
493 else
494 {
495 // Another reference to this shape is just counted.
496 IncrementReference();
497 ret = this;
498 }
499 return ret;
500 }
501 public override void Dereference(BSScene physicsScene)
502 {
503 lock (Meshes)
504 {
505 this.DecrementReference();
506 physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
507 // TODO: schedule aging and destruction of unused meshes.
508 }
509 }
510 // Loop through all the known meshes and return the description based on the physical address.
511 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
512 {
513 bool ret = false;
514 BSShapeMesh foundDesc = null;
515 lock (Meshes)
516 {
517 foreach (BSShapeMesh sm in Meshes.Values)
518 {
519 if (sm.physShapeInfo.ReferenceSame(pShape))
520 {
521 foundDesc = sm;
522 ret = true;
523 break;
524 }
525
526 }
527 }
528 outMesh = foundDesc;
529 return ret;
530 }
531
532 public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
533 private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
534 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
535 {
536 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
537 (w, iC, i, vC, v) =>
538 {
539 shapeInfo.Vertices = vC;
540 return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v);
541 });
542 }
543
544 // Code that uses the mesher to create the index/vertices info for a trimesh shape.
545 // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
546 // The actual build call is passed so this logic can be used by several of the shapes that use a
547 // simple mesh as their base shape.
548 public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
549 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
550 {
551 BulletShape newShape = new BulletShape();
552
553 IMesh meshData = null;
554 lock (physicsScene.mesher)
555 {
556 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
557 false, // say it is not physical so a bounding box is not built
558 false // do not cache the mesh and do not use previously built versions
559 );
560 }
561
562 if (meshData != null)
563 {
564 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
565 {
566 // Release the fetched asset data once it has been used.
567 pbs.SculptData = new byte[0];
568 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
569 }
570
571 int[] indices = meshData.getIndexListAsInt();
572 int realIndicesIndex = indices.Length;
573 float[] verticesAsFloats = meshData.getVertexListAsFloat();
574
575 if (BSParam.ShouldRemoveZeroWidthTriangles)
576 {
577 // Remove degenerate triangles. These are triangles with two of the vertices
578 // are the same. This is complicated by the problem that vertices are not
579 // made unique in sculpties so we have to compare the values in the vertex.
580 realIndicesIndex = 0;
581 for (int tri = 0; tri < indices.Length; tri += 3)
582 {
583 // Compute displacements into vertex array for each vertex of the triangle
584 int v1 = indices[tri + 0] * 3;
585 int v2 = indices[tri + 1] * 3;
586 int v3 = indices[tri + 2] * 3;
587 // Check to see if any two of the vertices are the same
588 if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
589 && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
590 && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
591 || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
592 && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
593 && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
594 || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
595 && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
596 && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
597 )
598 {
599 // None of the vertices of the triangles are the same. This is a good triangle;
600 indices[realIndicesIndex + 0] = indices[tri + 0];
601 indices[realIndicesIndex + 1] = indices[tri + 1];
602 indices[realIndicesIndex + 2] = indices[tri + 2];
603 realIndicesIndex += 3;
604 }
605 }
606 }
607 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
608 BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
609
610 if (realIndicesIndex != 0)
611 {
612 newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
613 }
614 else
615 {
616 // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
617 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
618 physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
619 physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
620 }
621 }
622 newShape.shapeKey = newMeshKey;
623
624 return newShape;
625 }
626}
627
628// ============================================================================================================
629// BSShapeHull is a physical shape representation htat is made up of many convex hulls.
630// The convex hulls are either supplied with the asset or are approximated by one of the
631// convex hull creation routines (in OpenSim or in Bullet).
632public class BSShapeHull : BSShape
633{
634#pragma warning disable 414
635 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
636#pragma warning restore 414
637
638 public static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
639
640
641 public BSShapeHull(BulletShape pShape) : base(pShape)
642 {
643 }
644 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
645 {
646 float lod;
647 System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
648
649 BSShapeHull retHull = null;
650 lock (Hulls)
651 {
652 if (Hulls.TryGetValue(newHullKey, out retHull))
653 {
654 // The mesh has already been created. Return a new reference to same.
655 retHull.IncrementReference();
656 }
657 else
658 {
659 retHull = new BSShapeHull(new BulletShape());
660 // An instance of this mesh has not been created. Build and remember same.
661 BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
662
663 // Check to see if hull was created (might require an asset).
664 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
665 if (!newShape.isNativeShape || prim.AssetFailed())
666 {
667 // If a mesh was what was created, remember the built shape for later sharing.
668 Hulls.Add(newHullKey, retHull);
669 }
670 retHull.physShapeInfo = newShape;
671 }
672 }
673 physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
674 return retHull;
675 }
676 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
677 {
678 BSShape ret = null;
679 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
680 // and we must create a copy of the native shape since they are never shared.
681 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
682 {
683 // TODO: decide when the native shapes should be freed. Check in Dereference?
684 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
685 }
686 else
687 {
688 // Another reference to this shape is just counted.
689 IncrementReference();
690 ret = this;
691 }
692 return ret;
693 }
694 public override void Dereference(BSScene physicsScene)
695 {
696 lock (Hulls)
697 {
698 this.DecrementReference();
699 physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
700 // TODO: schedule aging and destruction of unused meshes.
701 }
702 }
703
704 List<ConvexResult> m_hulls;
705 private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
706 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
707 {
708 BulletShape newShape = new BulletShape();
709
710 IMesh meshData = null;
711 List<List<OMV.Vector3>> allHulls = null;
712 lock (physicsScene.mesher)
713 {
714 // Pass true for physicalness as this prevents the creation of bounding box which is not needed
715 meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
716
717 // If we should use the asset's hull info, fetch it out of the locked mesher
718 if (meshData != null && BSParam.ShouldUseAssetHulls)
719 {
720 Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
721 if (realMesher != null)
722 {
723 allHulls = realMesher.GetConvexHulls(size);
724 }
725 if (allHulls == null)
726 {
727 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
728 }
729 }
730 }
731
732 // If there is hull data in the mesh asset, build the hull from that
733 if (allHulls != null && BSParam.ShouldUseAssetHulls)
734 {
735 int hullCount = allHulls.Count;
736 shapeInfo.HullCount = hullCount;
737 int totalVertices = 1; // include one for the count of the hulls
738 // Using the structure described for HACD hulls, create the memory sturcture
739 // to pass the hull data to the creater.
740 foreach (List<OMV.Vector3> hullVerts in allHulls)
741 {
742 totalVertices += 4; // add four for the vertex count and centroid
743 totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
744 }
745 float[] convHulls = new float[totalVertices];
746
747 convHulls[0] = (float)hullCount;
748 int jj = 1;
749 int hullIndex = 0;
750 foreach (List<OMV.Vector3> hullVerts in allHulls)
751 {
752 convHulls[jj + 0] = hullVerts.Count;
753 convHulls[jj + 1] = 0f; // centroid x,y,z
754 convHulls[jj + 2] = 0f;
755 convHulls[jj + 3] = 0f;
756 jj += 4;
757 foreach (OMV.Vector3 oneVert in hullVerts)
758 {
759 convHulls[jj + 0] = oneVert.X;
760 convHulls[jj + 1] = oneVert.Y;
761 convHulls[jj + 2] = oneVert.Z;
762 jj += 3;
763 }
764 shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
765 hullIndex++;
766 }
767
768 // create the hull data structure in Bullet
769 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
770
771 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
772 prim.LocalID, hullCount, totalVertices, newShape);
773 }
774
775 // If no hull specified in the asset and we should use Bullet's HACD approximation...
776 if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
777 {
778 // Build the hull shape from an existing mesh shape.
779 // The mesh should have already been created in Bullet.
780 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
781 BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
782
783 if (meshShape.physShapeInfo.HasPhysicalShape)
784 {
785 HACDParams parms = new HACDParams();
786 parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
787 parms.minClusters = BSParam.BHullMinClusters;
788 parms.compacityWeight = BSParam.BHullCompacityWeight;
789 parms.volumeWeight = BSParam.BHullVolumeWeight;
790 parms.concavity = BSParam.BHullConcavity;
791 parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
792 parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
793 parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
794 parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
795 parms.whichHACD = 0; // Use the HACD routine that comes with Bullet
796
797 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
798 newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
799 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
800
801 // Now done with the mesh shape.
802 shapeInfo.HullCount = 1;
803 BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
804 if (maybeMesh != null)
805 shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
806 meshShape.Dereference(physicsScene);
807 }
808 physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
809 }
810
811 // If no other hull specifications, use our HACD hull approximation.
812 if (!newShape.HasPhysicalShape && meshData != null)
813 {
814 if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
815 {
816 // Release the fetched asset data once it has been used.
817 pbs.SculptData = new byte[0];
818 prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
819 }
820
821 int[] indices = meshData.getIndexListAsInt();
822 List<OMV.Vector3> vertices = meshData.getVertexList();
823
824 //format conversion from IMesh format to DecompDesc format
825 List<int> convIndices = new List<int>();
826 List<float3> convVertices = new List<float3>();
827 for (int ii = 0; ii < indices.GetLength(0); ii++)
828 {
829 convIndices.Add(indices[ii]);
830 }
831 foreach (OMV.Vector3 vv in vertices)
832 {
833 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
834 }
835
836 uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
837 if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
838 {
839 // Simple primitive shapes we know are convex so they are better implemented with
840 // fewer hulls.
841 // Check for simple shape (prim without cuts) and reduce split parameter if so.
842 if (BSShapeCollection.PrimHasNoCuts(pbs))
843 {
844 maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
845 }
846 }
847
848 // setup and do convex hull conversion
849 m_hulls = new List<ConvexResult>();
850 DecompDesc dcomp = new DecompDesc();
851 dcomp.mIndices = convIndices;
852 dcomp.mVertices = convVertices;
853 dcomp.mDepth = maxDepthSplit;
854 dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
855 dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
856 dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
857 dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
858 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
859 // create the hull into the _hulls variable
860 convexBuilder.process(dcomp);
861
862 physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
863 BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
864
865 // Convert the vertices and indices for passing to unmanaged.
866 // The hull information is passed as a large floating point array.
867 // The format is:
868 // convHulls[0] = number of hulls
869 // convHulls[1] = number of vertices in first hull
870 // convHulls[2] = hull centroid X coordinate
871 // convHulls[3] = hull centroid Y coordinate
872 // convHulls[4] = hull centroid Z coordinate
873 // convHulls[5] = first hull vertex X
874 // convHulls[6] = first hull vertex Y
875 // convHulls[7] = first hull vertex Z
876 // convHulls[8] = second hull vertex X
877 // ...
878 // convHulls[n] = number of vertices in second hull
879 // convHulls[n+1] = second hull centroid X coordinate
880 // ...
881 //
882 // TODO: is is very inefficient. Someday change the convex hull generator to return
883 // data structures that do not need to be converted in order to pass to Bullet.
884 // And maybe put the values directly into pinned memory rather than marshaling.
885 int hullCount = m_hulls.Count;
886 int totalVertices = 1; // include one for the count of the hulls
887 foreach (ConvexResult cr in m_hulls)
888 {
889 totalVertices += 4; // add four for the vertex count and centroid
890 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
891 }
892 float[] convHulls = new float[totalVertices];
893
894 convHulls[0] = (float)hullCount;
895 int jj = 1;
896 foreach (ConvexResult cr in m_hulls)
897 {
898 // copy vertices for index access
899 float3[] verts = new float3[cr.HullVertices.Count];
900 int kk = 0;
901 foreach (float3 ff in cr.HullVertices)
902 {
903 verts[kk++] = ff;
904 }
905
906 // add to the array one hull's worth of data
907 convHulls[jj++] = cr.HullIndices.Count;
908 convHulls[jj++] = 0f; // centroid x,y,z
909 convHulls[jj++] = 0f;
910 convHulls[jj++] = 0f;
911 foreach (int ind in cr.HullIndices)
912 {
913 convHulls[jj++] = verts[ind].x;
914 convHulls[jj++] = verts[ind].y;
915 convHulls[jj++] = verts[ind].z;
916 }
917 }
918 // create the hull data structure in Bullet
919 newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
920 }
921 newShape.shapeKey = newHullKey;
922 return newShape;
923 }
924 // Callback from convex hull creater with a newly created hull.
925 // Just add it to our collection of hulls for this shape.
926 private void HullReturn(ConvexResult result)
927 {
928 m_hulls.Add(result);
929 return;
930 }
931 // Loop through all the known hulls and return the description based on the physical address.
932 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
933 {
934 bool ret = false;
935 BSShapeHull foundDesc = null;
936 lock (Hulls)
937 {
938 foreach (BSShapeHull sh in Hulls.Values)
939 {
940 if (sh.physShapeInfo.ReferenceSame(pShape))
941 {
942 foundDesc = sh;
943 ret = true;
944 break;
945 }
946
947 }
948 }
949 outHull = foundDesc;
950 return ret;
951 }
952}
953
954// ============================================================================================================
955// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate
956// meshes. Used by BulletSim for complex shapes like linksets.
957public class BSShapeCompound : BSShape
958{
959 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
960 public static Dictionary<string, BSShapeCompound> CompoundShapes = new Dictionary<string, BSShapeCompound>();
961
962 public BSShapeCompound(BulletShape pShape) : base(pShape)
963 {
964 }
965 public static BSShape GetReference(BSScene physicsScene)
966 {
967 // Base compound shapes are not shared so this returns a raw shape.
968 // A built compound shape can be reused in linksets.
969 BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene));
970 CompoundShapes.Add(ret.AddrString, ret);
971 return ret;
972 }
973 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
974 {
975 // Calling this reference means we want another handle to an existing compound shape
976 // (usually linksets) so return this copy.
977 IncrementReference();
978 return this;
979 }
980 // Dereferencing a compound shape releases the hold on all the child shapes.
981 public override void Dereference(BSScene physicsScene)
982 {
983 lock (physShapeInfo)
984 {
985 this.DecrementReference();
986 physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this);
987 if (referenceCount <= 0)
988 {
989 if (!physicsScene.PE.IsCompound(physShapeInfo))
990 {
991 // Failed the sanity check!!
992 physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
993 LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString);
994 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
995 BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString);
996 return;
997 }
998
999 int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo);
1000 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}",
1001 BSScene.DetailLogZero, physShapeInfo, numChildren);
1002
1003 // Loop through all the children dereferencing each.
1004 for (int ii = numChildren - 1; ii >= 0; ii--)
1005 {
1006 BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii);
1007 DereferenceAnonCollisionShape(physicsScene, childShape);
1008 }
1009
1010 lock (CompoundShapes)
1011 CompoundShapes.Remove(physShapeInfo.AddrString);
1012 physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
1013 }
1014 }
1015 }
1016 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
1017 {
1018 lock (CompoundShapes)
1019 {
1020 string addr = pShape.AddrString;
1021 return CompoundShapes.TryGetValue(addr, out outCompound);
1022 }
1023 }
1024 private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene)
1025 {
1026 BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false);
1027 return cShape;
1028 }
1029 // Sometimes we have a pointer to a collision shape but don't know what type it is.
1030 // Figure out type and call the correct dereference routine.
1031 // Called at taint-time.
1032 private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
1033 {
1034 // TODO: figure a better way to go through all the shape types and find a possible instance.
1035 physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
1036 BSScene.DetailLogZero, pShape);
1037 BSShapeMesh meshDesc;
1038 if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
1039 {
1040 meshDesc.Dereference(physicsScene);
1041 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
1042 }
1043 else
1044 {
1045 BSShapeHull hullDesc;
1046 if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
1047 {
1048 hullDesc.Dereference(physicsScene);
1049 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
1050 }
1051 else
1052 {
1053 BSShapeConvexHull chullDesc;
1054 if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
1055 {
1056 chullDesc.Dereference(physicsScene);
1057 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
1058 }
1059 else
1060 {
1061 BSShapeGImpact gImpactDesc;
1062 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
1063 {
1064 gImpactDesc.Dereference(physicsScene);
1065 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
1066 }
1067 else
1068 {
1069 // Didn't find it in the lists of specific types. It could be compound.
1070 BSShapeCompound compoundDesc;
1071 if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc))
1072 {
1073 compoundDesc.Dereference(physicsScene);
1074 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
1075 }
1076 else
1077 {
1078 // If none of the above, maybe it is a simple native shape.
1079 if (physicsScene.PE.IsNativeShape(pShape))
1080 {
1081 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
1082 BSShapeNative nativeShape = new BSShapeNative(pShape);
1083 nativeShape.Dereference(physicsScene);
1084 }
1085 else
1086 {
1087 physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
1088 LogHeader, pShape);
1089 }
1090 }
1091 }
1092 }
1093 }
1094 }
1095 }
1096}
1097
1098// ============================================================================================================
1099// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex
1100// hull shapes. This is used for simple prims that are convex and thus can be made into a simple
1101// collision shape (a single hull). More complex physical shapes will be BSShapeHull's.
1102public class BSShapeConvexHull : BSShape
1103{
1104#pragma warning disable 414
1105 private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]";
1106#pragma warning restore 414
1107
1108 public static Dictionary<System.UInt64, BSShapeConvexHull> ConvexHulls = new Dictionary<System.UInt64, BSShapeConvexHull>();
1109
1110 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
1111 {
1112 }
1113 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1114 {
1115 float lod;
1116 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1117
1118 physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}",
1119 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1120
1121 BSShapeConvexHull retConvexHull = null;
1122 lock (ConvexHulls)
1123 {
1124 if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull))
1125 {
1126 // The mesh has already been created. Return a new reference to same.
1127 retConvexHull.IncrementReference();
1128 }
1129 else
1130 {
1131 retConvexHull = new BSShapeConvexHull(new BulletShape());
1132 BulletShape convexShape = null;
1133
1134 // Get a handle to a mesh to build the hull from
1135 BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim);
1136 if (baseMesh.physShapeInfo.isNativeShape)
1137 {
1138 // We get here if the mesh was not creatable. Could be waiting for an asset from the disk.
1139 // In the short term, we return the native shape and a later ForceBodyShapeRebuild should
1140 // get back to this code with a buildable mesh.
1141 // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed?
1142 convexShape = baseMesh.physShapeInfo;
1143 }
1144 else
1145 {
1146 convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo);
1147 convexShape.shapeKey = newMeshKey;
1148 ConvexHulls.Add(convexShape.shapeKey, retConvexHull);
1149 physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}",
1150 BSScene.DetailLogZero, convexShape);
1151 }
1152
1153 // Done with the base mesh
1154 baseMesh.Dereference(physicsScene);
1155
1156 retConvexHull.physShapeInfo = convexShape;
1157 }
1158 }
1159 return retConvexHull;
1160 }
1161 public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim)
1162 {
1163 // Calling this reference means we want another handle to an existing shape
1164 // (usually linksets) so return this copy.
1165 IncrementReference();
1166 return this;
1167 }
1168 // Dereferencing a compound shape releases the hold on all the child shapes.
1169 public override void Dereference(BSScene physicsScene)
1170 {
1171 lock (ConvexHulls)
1172 {
1173 this.DecrementReference();
1174 physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
1175 // TODO: schedule aging and destruction of unused meshes.
1176 }
1177 }
1178 // Loop through all the known hulls and return the description based on the physical address.
1179 public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull)
1180 {
1181 bool ret = false;
1182 BSShapeConvexHull foundDesc = null;
1183 lock (ConvexHulls)
1184 {
1185 foreach (BSShapeConvexHull sh in ConvexHulls.Values)
1186 {
1187 if (sh.physShapeInfo.ReferenceSame(pShape))
1188 {
1189 foundDesc = sh;
1190 ret = true;
1191 break;
1192 }
1193
1194 }
1195 }
1196 outHull = foundDesc;
1197 return ret;
1198 }
1199}
1200// ============================================================================================================
1201// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that
1202// can handle concave as well as convex shapes. Much slower computationally but creates smoother
1203// shapes than multiple convex hull approximations.
1204public class BSShapeGImpact : BSShape
1205{
1206#pragma warning disable 414
1207 private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]";
1208#pragma warning restore 414
1209
1210 public static Dictionary<System.UInt64, BSShapeGImpact> GImpacts = new Dictionary<System.UInt64, BSShapeGImpact>();
1211
1212 public BSShapeGImpact(BulletShape pShape) : base(pShape)
1213 {
1214 }
1215 public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
1216 {
1217 float lod;
1218 System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
1219
1220 physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}",
1221 prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod);
1222
1223 BSShapeGImpact retGImpact = null;
1224 lock (GImpacts)
1225 {
1226 if (GImpacts.TryGetValue(newMeshKey, out retGImpact))
1227 {
1228 // The mesh has already been created. Return a new reference to same.
1229 retGImpact.IncrementReference();
1230 }
1231 else
1232 {
1233 retGImpact = new BSShapeGImpact(new BulletShape());
1234 BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
1235
1236 // Check to see if mesh was created (might require an asset).
1237 newShape = VerifyMeshCreated(physicsScene, newShape, prim);
1238 newShape.shapeKey = newMeshKey;
1239 if (!newShape.isNativeShape || prim.AssetFailed())
1240 {
1241 // If a mesh was what was created, remember the built shape for later sharing.
1242 // Also note that if meshing failed we put it in the mesh list as there is nothing
1243 // else to do about the mesh.
1244 GImpacts.Add(newMeshKey, retGImpact);
1245 }
1246
1247 retGImpact.physShapeInfo = newShape;
1248 }
1249 }
1250 return retGImpact;
1251 }
1252
1253 private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
1254 PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
1255 {
1256 return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
1257 (w, iC, i, vC, v) =>
1258 {
1259 shapeInfo.Vertices = vC;
1260 return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v);
1261 });
1262 }
1263
1264 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1265 {
1266 BSShape ret = null;
1267 // If the underlying shape is native, the actual shape has not been build (waiting for asset)
1268 // and we must create a copy of the native shape since they are never shared.
1269 if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
1270 {
1271 // TODO: decide when the native shapes should be freed. Check in Dereference?
1272 ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
1273 }
1274 else
1275 {
1276 // Another reference to this shape is just counted.
1277 IncrementReference();
1278 ret = this;
1279 }
1280 return ret;
1281 }
1282 // Dereferencing a compound shape releases the hold on all the child shapes.
1283 public override void Dereference(BSScene physicsScene)
1284 {
1285 lock (GImpacts)
1286 {
1287 this.DecrementReference();
1288 physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this);
1289 // TODO: schedule aging and destruction of unused meshes.
1290 }
1291 }
1292 // Loop through all the known hulls and return the description based on the physical address.
1293 public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull)
1294 {
1295 bool ret = false;
1296 BSShapeGImpact foundDesc = null;
1297 lock (GImpacts)
1298 {
1299 foreach (BSShapeGImpact sh in GImpacts.Values)
1300 {
1301 if (sh.physShapeInfo.ReferenceSame(pShape))
1302 {
1303 foundDesc = sh;
1304 ret = true;
1305 break;
1306 }
1307
1308 }
1309 }
1310 outHull = foundDesc;
1311 return ret;
1312 }
1313}
1314
1315// ============================================================================================================
1316// BSShapeAvatar is a specialized mesh shape for avatars.
1317public class BSShapeAvatar : BSShape
1318{
1319#pragma warning disable 414
1320 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
1321#pragma warning restore 414
1322
1323 public BSShapeAvatar()
1324 : base()
1325 {
1326 }
1327 public static BSShape GetReference(BSPhysObject prim)
1328 {
1329 return new BSShapeNull();
1330 }
1331 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
1332 {
1333 return new BSShapeNull();
1334 }
1335 public override void Dereference(BSScene physicsScene) { }
1336
1337 // From the front:
1338 // A---A
1339 // / \
1340 // B-------B
1341 // / \ +Z
1342 // C-----------C |
1343 // \ / -Y --+-- +Y
1344 // \ / |
1345 // \ / -Z
1346 // D-----D
1347 // \ /
1348 // E-E
1349
1350 // From the top A and E are just lines.
1351 // B, C and D are hexagons:
1352 //
1353 // C1--C2 +X
1354 // / \ |
1355 // C0 C3 -Y --+-- +Y
1356 // \ / |
1357 // C5--C4 -X
1358
1359 // Zero goes directly through the middle so the offsets are from that middle axis
1360 // and up and down from a middle horizon (A and E are the same distance from the zero).
1361 // The height, width and depth is one. All scaling is done by the simulator.
1362
1363 // Z component -- how far the level is from the middle zero
1364 private const float Aup = 0.5f;
1365 private const float Bup = 0.4f;
1366 private const float Cup = 0.3f;
1367 private const float Dup = -0.4f;
1368 private const float Eup = -0.5f;
1369
1370 // Y component -- distance from center to x0 and x3
1371 private const float Awid = 0.25f;
1372 private const float Bwid = 0.3f;
1373 private const float Cwid = 0.5f;
1374 private const float Dwid = 0.3f;
1375 private const float Ewid = 0.2f;
1376
1377 // Y component -- distance from center to x1, x2, x4 and x5
1378 private const float Afwid = 0.0f;
1379 private const float Bfwid = 0.2f;
1380 private const float Cfwid = 0.4f;
1381 private const float Dfwid = 0.2f;
1382 private const float Efwid = 0.0f;
1383
1384 // X component -- distance from zero to the front or back of a level
1385 private const float Adep = 0f;
1386 private const float Bdep = 0.3f;
1387 private const float Cdep = 0.5f;
1388 private const float Ddep = 0.2f;
1389 private const float Edep = 0f;
1390
1391 private OMV.Vector3[] avatarVertices = {
1392 new OMV.Vector3( 0.0f, -Awid, Aup), // A0
1393 new OMV.Vector3( 0.0f, +Awid, Aup), // A3
1394
1395 new OMV.Vector3( 0.0f, -Bwid, Bup), // B0
1396 new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1
1397 new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2
1398 new OMV.Vector3( 0.0f, +Bwid, Bup), // B3
1399 new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4
1400 new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5
1401
1402 new OMV.Vector3( 0.0f, -Cwid, Cup), // C0
1403 new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1
1404 new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2
1405 new OMV.Vector3( 0.0f, +Cwid, Cup), // C3
1406 new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4
1407 new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5
1408
1409 new OMV.Vector3( 0.0f, -Dwid, Dup), // D0
1410 new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1
1411 new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2
1412 new OMV.Vector3( 0.0f, +Dwid, Dup), // D3
1413 new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4
1414 new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5
1415
1416 new OMV.Vector3( 0.0f, -Ewid, Eup), // E0
1417 new OMV.Vector3( 0.0f, +Ewid, Eup), // E3
1418 };
1419
1420 // Offsets of the vertices in the vertices array
1421 private enum Ind : int
1422 {
1423 A0, A3,
1424 B0, B1, B2, B3, B4, B5,
1425 C0, C1, C2, C3, C4, C5,
1426 D0, D1, D2, D3, D4, D5,
1427 E0, E3
1428 }
1429
1430 // Comments specify trianges and quads in clockwise direction
1431 private Ind[] avatarIndices = {
1432 Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1
1433 Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3
1434 Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3
1435 Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4
1436 Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0
1437 Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0
1438
1439 Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1
1440 Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2
1441 Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3
1442 Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4
1443 Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5
1444 Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0
1445
1446 Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1
1447 Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2
1448 Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3
1449 Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4
1450 Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5
1451 Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0
1452
1453 Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1
1454 Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3
1455 Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3
1456 Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4
1457 Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0
1458 Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0
1459
1460 };
1461
1462}
1463}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
index e4fecc3..42fc11b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
@@ -30,15 +30,14 @@ using System.Text;
30 30
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework; 32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules; 33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.Physics.Manager;
35 34
36using Nini.Config; 35using Nini.Config;
37using log4net; 36using log4net;
38 37
39using OpenMetaverse; 38using OpenMetaverse;
40 39
41namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.PhysicsModule.BulletS
42{ 41{
43public sealed class BSTerrainHeightmap : BSTerrainPhys 42public sealed class BSTerrainHeightmap : BSTerrainPhys
44{ 43{
@@ -58,7 +57,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
58 { 57 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; 58 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 } 59 }
61 m_mapInfo = new BulletHMapInfo(id, initialMap); 60 m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
62 m_mapInfo.minCoords = minTerrainCoords; 61 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords; 62 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase; 63 m_mapInfo.terrainRegionBase = TerrainBase;
@@ -68,11 +67,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
68 67
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z 68 // 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). 69 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, 70 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords) 71 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 72 : base(physicsScene, regionBase, id)
74 { 73 {
75 m_mapInfo = new BulletHMapInfo(id, initialMap); 74 m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
76 m_mapInfo.minCoords = minCoords; 75 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords; 76 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z; 77 m_mapInfo.minZ = minCoords.Z;
@@ -92,7 +91,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
92 private void BuildHeightmapTerrain() 91 private void BuildHeightmapTerrain()
93 { 92 {
94 // Create the terrain shape from the mapInfo 93 // Create the terrain shape from the mapInfo
95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID, 94 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, 95 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); 96 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98 97
@@ -103,26 +102,25 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 102 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 103 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
105 104
106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, 105 m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
107 m_mapInfo.ID, centerPos, Quaternion.Identity); 106 m_mapInfo.ID, centerPos, Quaternion.Identity);
108 107
109 // Set current terrain attributes 108 // Set current terrain attributes
110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); 109 m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); 110 m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); 111 m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); 112 m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
113
114 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
114 115
115 // Return the new terrain to the world of physical objects 116 // Return the new terrain to the world of physical objects
116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody); 117 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody);
117 118
118 // redo its bounding box now that it is in the world 119 // redo its bounding box now that it is in the world
119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody); 120 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody);
120
121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
123 121
124 // Make it so the terrain will not move or be considered for movement. 122 // Make it so the terrain will not move or be considered for movement.
125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); 123 m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
126 124
127 return; 125 return;
128 } 126 }
@@ -134,9 +132,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
134 { 132 {
135 if (m_mapInfo.terrainBody.HasPhysicalBody) 133 if (m_mapInfo.terrainBody.HasPhysicalBody)
136 { 134 {
137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody); 135 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody);
138 // Frees both the body and the shape. 136 // Frees both the body and the shape.
139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody); 137 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody);
140 } 138 }
141 } 139 }
142 m_mapInfo = null; 140 m_mapInfo = null;
@@ -155,7 +153,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
155 catch 153 catch
156 { 154 {
157 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 155 // 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}", 156 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
159 LogHeader, m_mapInfo.terrainRegionBase, pos); 157 LogHeader, m_mapInfo.terrainRegionBase, pos);
160 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 158 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
161 } 159 }
@@ -165,7 +163,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
165 // The passed position is relative to the base of the region. 163 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos) 164 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 { 165 {
168 return PhysicsScene.SimpleWaterLevel; 166 return m_physicsScene.SimpleWaterLevel;
169 } 167 }
170} 168}
171} 169}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
index 2e9db39..d11baa6 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -30,15 +30,14 @@ using System.Text;
30 30
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Region.Framework; 32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules; 33using OpenSim.Region.PhysicsModules.SharedBase;
34using OpenSim.Region.Physics.Manager;
35 34
36using Nini.Config; 35using Nini.Config;
37using log4net; 36using log4net;
38 37
39using OpenMetaverse; 38using OpenMetaverse;
40 39
41namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.PhysicsModule.BulletS
42{ 41{
43 42
44// The physical implementation of the terrain is wrapped in this class. 43// The physical implementation of the terrain is wrapped in this class.
@@ -50,14 +49,14 @@ public abstract class BSTerrainPhys : IDisposable
50 Mesh = 1 49 Mesh = 1
51 } 50 }
52 51
53 public BSScene PhysicsScene { get; private set; } 52 protected BSScene m_physicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this. 53 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; } 54 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; } 55 public uint ID { get; private set; }
57 56
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) 57 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 { 58 {
60 PhysicsScene = physicsScene; 59 m_physicsScene = physicsScene;
61 TerrainBase = regionBase; 60 TerrainBase = regionBase;
62 ID = id; 61 ID = id;
63 } 62 }
@@ -86,7 +85,7 @@ public sealed class BSTerrainManager : IDisposable
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 85 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 86
88 // The scene that I am part of 87 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; } 88 private BSScene m_physicsScene { get; set; }
90 89
91 // The ground plane created to keep thing from falling to infinity. 90 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane; 91 private BulletBody m_groundPlane;
@@ -111,9 +110,11 @@ public sealed class BSTerrainManager : IDisposable
111 private Vector3 m_worldMax; 110 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; } 111 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113 112
114 public BSTerrainManager(BSScene physicsScene) 113 public BSTerrainManager(BSScene physicsScene, Vector3 regionSize)
115 { 114 {
116 PhysicsScene = physicsScene; 115 m_physicsScene = physicsScene;
116 DefaultRegionSize = regionSize;
117
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>(); 118 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118 119
119 // Assume one region of default size 120 // Assume one region of default size
@@ -132,32 +133,39 @@ public sealed class BSTerrainManager : IDisposable
132 // safe to call Bullet in real time. We hope no one is moving prims around yet. 133 // safe to call Bullet in real time. We hope no one is moving prims around yet.
133 public void CreateInitialGroundPlaneAndTerrain() 134 public void CreateInitialGroundPlaneAndTerrain()
134 { 135 {
136 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 137 // 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); 138 BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, 139 Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane);
138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity); 140 m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
141 BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity);
139 142
140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
142 // Ground plane does not move
143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
144 // Everything collides with the ground plane. 143 // Everything collides with the ground plane.
145 m_groundPlane.collisionType = CollisionType.Groundplane; 144 m_groundPlane.collisionType = CollisionType.Groundplane;
146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
147 145
148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 146 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane);
149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 147 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane);
150 m_terrains.Add(Vector3.Zero, initialTerrain); 148
149 // Ground plane does not move
150 m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
151
152 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
153 lock (m_terrains)
154 {
155 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
156 m_terrains.Add(Vector3.Zero, initialTerrain);
157 }
151 } 158 }
152 159
153 // Release all the terrain structures we might have allocated 160 // Release all the terrain structures we might have allocated
154 public void ReleaseGroundPlaneAndTerrain() 161 public void ReleaseGroundPlaneAndTerrain()
155 { 162 {
163 DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName);
156 if (m_groundPlane.HasPhysicalBody) 164 if (m_groundPlane.HasPhysicalBody)
157 { 165 {
158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane)) 166 if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane))
159 { 167 {
160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane); 168 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane);
161 } 169 }
162 m_groundPlane.Clear(); 170 m_groundPlane.Clear();
163 } 171 }
@@ -183,7 +191,7 @@ public sealed class BSTerrainManager : IDisposable
183 float[] localHeightMap = heightMap; 191 float[] localHeightMap = heightMap;
184 // If there are multiple requests for changes to the same terrain between ticks, 192 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one. 193 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() 194 m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
187 { 195 {
188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 196 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
189 { 197 {
@@ -193,11 +201,9 @@ public sealed class BSTerrainManager : IDisposable
193 // the terrain is added to our parent 201 // the terrain is added to our parent
194 if (MegaRegionParentPhysicsScene is BSScene) 202 if (MegaRegionParentPhysicsScene is BSScene)
195 { 203 {
196 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 204 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax);
197 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 205 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain(
198 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain( 206 BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
199 BSScene.CHILDTERRAIN_ID, localHeightMap,
200 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
201 } 207 }
202 } 208 }
203 else 209 else
@@ -205,27 +211,34 @@ public sealed class BSTerrainManager : IDisposable
205 // If not doing the mega-prim thing, just change the terrain 211 // If not doing the mega-prim thing, just change the terrain
206 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 212 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
207 213
208 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, 214 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize);
209 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
210 } 215 }
211 }); 216 });
212 } 217 }
213 218
214 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain 219 // Another region is calling this region and passing a terrain.
220 // A region that is not the mega-region root will pass its terrain to the root region so the root region
221 // physics engine will have all the terrains.
222 private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
223 {
224 // Since we are called by another region's thread, the action must be rescheduled onto our processing thread.
225 m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate()
226 {
227 UpdateTerrain(id, heightMap, minCoords, maxCoords);
228 });
229 }
230
231 // 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 232 // 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. 233 // 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. 234 // 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 235 // If there is an existing terrain body, a new
219 // terrain shape is created and added to the body. 236 // 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. 237 // 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.) 238 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time. 239 // Called during taint-time.
223 private void UpdateTerrain(uint id, float[] heightMap, 240 private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
225 { 241 {
226 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
227 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
228
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
231 // object height, for instance). The terrain wants the bounding box for the 244 // object height, for instance). The terrain wants the bounding box for the
@@ -245,6 +258,9 @@ public sealed class BSTerrainManager : IDisposable
245 minCoords.Z = minZ; 258 minCoords.Z = minZ;
246 maxCoords.Z = maxZ; 259 maxCoords.Z = maxZ;
247 260
261 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}",
262 BSScene.DetailLogZero, id, minCoords, maxCoords);
263
248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 264 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
249 265
250 lock (m_terrains) 266 lock (m_terrains)
@@ -253,8 +269,8 @@ public sealed class BSTerrainManager : IDisposable
253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) 269 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
254 { 270 {
255 // There is already a terrain in this spot. Free the old and build the new. 271 // 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}", 272 DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); 273 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords);
258 274
259 // Remove old terrain from the collection 275 // Remove old terrain from the collection
260 m_terrains.Remove(terrainRegionBase); 276 m_terrains.Remove(terrainRegionBase);
@@ -263,6 +279,7 @@ public sealed class BSTerrainManager : IDisposable
263 279
264 if (MegaRegionParentPhysicsScene == null) 280 if (MegaRegionParentPhysicsScene == null)
265 { 281 {
282 // This terrain is not part of the mega-region scheme. Create vanilla terrain.
266 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 283 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
267 m_terrains.Add(terrainRegionBase, newTerrainPhys); 284 m_terrains.Add(terrainRegionBase, newTerrainPhys);
268 285
@@ -291,8 +308,8 @@ public sealed class BSTerrainManager : IDisposable
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID) 308 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount; 309 newTerrainID = ++m_terrainCount;
293 310
294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", 311 DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 312 BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords);
296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 313 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
297 m_terrains.Add(terrainRegionBase, newTerrainPhys); 314 m_terrains.Add(terrainRegionBase, newTerrainPhys);
298 315
@@ -304,26 +321,26 @@ public sealed class BSTerrainManager : IDisposable
304 // TODO: redo terrain implementation selection to allow other base types than heightMap. 321 // 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) 322 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
306 { 323 {
307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 324 m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
308 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 325 LogHeader, m_physicsScene.RegionName, terrainRegionBase,
309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); 326 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
310 BSTerrainPhys newTerrainPhys = null; 327 BSTerrainPhys newTerrainPhys = null;
311 switch ((int)BSParam.TerrainImplementation) 328 switch ((int)BSParam.TerrainImplementation)
312 { 329 {
313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 330 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 331 newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id,
315 heightMap, minCoords, maxCoords); 332 heightMap, minCoords, maxCoords);
316 break; 333 break;
317 case (int)BSTerrainPhys.TerrainImplementation.Mesh: 334 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
318 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id, 335 newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id,
319 heightMap, minCoords, maxCoords); 336 heightMap, minCoords, maxCoords);
320 break; 337 break;
321 default: 338 default:
322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 339 m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
323 LogHeader, 340 LogHeader,
324 (int)BSParam.TerrainImplementation, 341 (int)BSParam.TerrainImplementation,
325 BSParam.TerrainImplementation, 342 BSParam.TerrainImplementation,
326 PhysicsScene.RegionName, terrainRegionBase); 343 m_physicsScene.RegionName, terrainRegionBase);
327 break; 344 break;
328 } 345 }
329 return newTerrainPhys; 346 return newTerrainPhys;
@@ -337,6 +354,64 @@ public sealed class BSTerrainManager : IDisposable
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); 354 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 } 355 }
339 356
357 // Return a new position that is over known terrain if the position is outside our terrain.
358 public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
359 {
360 float edgeEpsilon = 0.1f;
361
362 Vector3 ret = pPos;
363
364 // First, base addresses are never negative so correct for that possible problem.
365 if (ret.X < 0f || ret.Y < 0f)
366 {
367 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
368 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
369 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
370 BSScene.DetailLogZero, pPos, ret);
371 }
372
373 // Can't do this function if we don't know about any terrain.
374 if (m_terrains.Count == 0)
375 return ret;
376
377 int loopPrevention = 10;
378 Vector3 terrainBaseXYZ;
379 BSTerrainPhys physTerrain;
380 while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
381 {
382 // The passed position is not within a known terrain area.
383 // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region.
384
385 // Must be off the top of a region. Find an adjacent region to move into.
386 // The returned terrain is always 'lower'. That is, closer to <0,0>.
387 Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
388
389 if (adjacentTerrainBase.X < terrainBaseXYZ.X)
390 {
391 // moving down into a new region in the X dimension. New position will be the max in the new base.
392 ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon;
393 }
394 if (adjacentTerrainBase.Y < terrainBaseXYZ.Y)
395 {
396 // moving down into a new region in the X dimension. New position will be the max in the new base.
397 ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon;
398 }
399 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
400 BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
401
402 if (loopPrevention-- < 0f)
403 {
404 // The 'while' is a little dangerous so this prevents looping forever if the
405 // mapping of the terrains ever gets messed up (like nothing at <0,0>) or
406 // the list of terrains is in transition.
407 DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
408 break;
409 }
410 }
411
412 return ret;
413 }
414
340 // Given an X and Y, find the height of the terrain. 415 // Given an X and Y, find the height of the terrain.
341 // Since we could be handling multiple terrains for a mega-region, 416 // Since we could be handling multiple terrains for a mega-region,
342 // the base of the region is calcuated assuming all regions are 417 // the base of the region is calcuated assuming all regions are
@@ -368,8 +443,8 @@ public sealed class BSTerrainManager : IDisposable
368 } 443 }
369 else 444 else
370 { 445 {
371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 446 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
372 LogHeader, PhysicsScene.RegionName, tX, tY); 447 LogHeader, m_physicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", 448 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ); 449 BSScene.DetailLogZero, pos, terrainBaseXYZ);
375 } 450 }
@@ -390,8 +465,8 @@ public sealed class BSTerrainManager : IDisposable
390 } 465 }
391 else 466 else
392 { 467 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", 468 m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); 469 LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 } 470 }
396 return ret; 471 return ret;
397 } 472 }
@@ -400,18 +475,69 @@ public sealed class BSTerrainManager : IDisposable
400 // the descriptor class and the 'base' fo the addresses therein. 475 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) 476 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 { 477 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 478 bool ret = false;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 479
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); 480 Vector3 terrainBaseXYZ = Vector3.Zero;
481 if (pos.X < 0f || pos.Y < 0f)
482 {
483 // We don't handle negative addresses so just make up a base that will not be found.
484 terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
485 }
486 else
487 {
488 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
489 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
490 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
491 }
406 492
407 BSTerrainPhys physTerrain = null; 493 BSTerrainPhys physTerrain = null;
408 lock (m_terrains) 494 lock (m_terrains)
409 { 495 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); 496 ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 } 497 }
412 outTerrainBase = terrainBaseXYZ; 498 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain; 499 outPhysTerrain = physTerrain;
414 return (physTerrain != null); 500 return ret;
501 }
502
503 // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
504 // this one. Usually used to return an out of bounds object to a known place.
505 private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
506 {
507 Vector3 ret = pTerrainBase;
508
509 // Can't do this function if we don't know about any terrain.
510 if (m_terrains.Count == 0)
511 return ret;
512
513 // Just some sanity
514 ret.X = Util.Clamp<float>(ret.X, 0f, 1000000f);
515 ret.Y = Util.Clamp<float>(ret.Y, 0f, 1000000f);
516 ret.Z = 0f;
517
518 lock (m_terrains)
519 {
520 // Once down to the <0,0> region, we have to be done.
521 while (ret.X > 0f || ret.Y > 0f)
522 {
523 if (ret.X > 0f)
524 {
525 ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
526 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
527 if (m_terrains.ContainsKey(ret))
528 break;
529 }
530 if (ret.Y > 0f)
531 {
532 ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
533 DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
534 if (m_terrains.ContainsKey(ret))
535 break;
536 }
537 }
538 }
539
540 return ret;
415 } 541 }
416 542
417 // Although no one seems to check this, I do support combining. 543 // Although no one seems to check this, I do support combining.
@@ -452,7 +578,7 @@ public sealed class BSTerrainManager : IDisposable
452 578
453 private void DetailLog(string msg, params Object[] args) 579 private void DetailLog(string msg, params Object[] args)
454 { 580 {
455 PhysicsScene.PhysicsLogging.Write(msg, args); 581 m_physicsScene.PhysicsLogging.Write(msg, args);
456 } 582 }
457} 583}
458} 584}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
new file mode 100755
index 0000000..cd59b65
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
@@ -0,0 +1,440 @@
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
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35using Nini.Config;
36using log4net;
37
38using OpenMetaverse;
39
40namespace OpenSim.Region.PhysicsModule.BulletS
41{
42public sealed class BSTerrainMesh : BSTerrainPhys
43{
44 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
45
46 private float[] m_savedHeightMap;
47 int m_sizeX;
48 int m_sizeY;
49
50 BulletShape m_terrainShape;
51 BulletBody m_terrainBody;
52
53 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
54 : base(physicsScene, regionBase, id)
55 {
56 }
57
58 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
59 : base(physicsScene, regionBase, id)
60 {
61 }
62
63 // Create terrain mesh from a heightmap.
64 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
65 Vector3 minCoords, Vector3 maxCoords)
66 : base(physicsScene, regionBase, id)
67 {
68 int indicesCount;
69 int[] indices;
70 int verticesCount;
71 float[] vertices;
72
73 m_savedHeightMap = initialMap;
74
75 m_sizeX = (int)(maxCoords.X - minCoords.X);
76 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
77
78 bool meshCreationSuccess = false;
79 if (BSParam.TerrainMeshMagnification == 1)
80 {
81 // If a magnification of one, use the old routine that is tried and true.
82 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene,
83 initialMap, m_sizeX, m_sizeY, // input size
84 Vector3.Zero, // base for mesh
85 out indicesCount, out indices, out verticesCount, out vertices);
86 }
87 else
88 {
89 // Other magnifications use the newer routine
90 meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene,
91 initialMap, m_sizeX, m_sizeY, // input size
92 BSParam.TerrainMeshMagnification,
93 physicsScene.TerrainManager.DefaultRegionSize,
94 Vector3.Zero, // base for mesh
95 out indicesCount, out indices, out verticesCount, out vertices);
96 }
97 if (!meshCreationSuccess)
98 {
99 // DISASTER!!
100 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID);
101 m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
102 // Something is very messed up and a crash is in our future.
103 return;
104 }
105
106 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
107 BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);
108
109 m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices);
110 if (!m_terrainShape.HasPhysicalShape)
111 {
112 // DISASTER!!
113 m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID);
114 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
115 // Something is very messed up and a crash is in our future.
116 return;
117 }
118
119 Vector3 pos = regionBase;
120 Quaternion rot = Quaternion.Identity;
121
122 m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
123 if (!m_terrainBody.HasPhysicalBody)
124 {
125 // DISASTER!!
126 m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
127 // Something is very messed up and a crash is in our future.
128 return;
129 }
130 physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);
131
132 // Set current terrain attributes
133 m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
134 m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
135 m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
136 m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
137 m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
138
139 // Static objects are not very massive.
140 m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
141
142 // Put the new terrain to the world of physical objects
143 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody);
144
145 // Redo its bounding box now that it is in the world
146 m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody);
147
148 m_terrainBody.collisionType = CollisionType.Terrain;
149 m_terrainBody.ApplyCollisionMask(m_physicsScene);
150
151 if (BSParam.UseSingleSidedMeshes)
152 {
153 m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
154 m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
155 }
156
157 // Make it so the terrain will not move or be considered for movement.
158 m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
159 }
160
161 public override void Dispose()
162 {
163 if (m_terrainBody.HasPhysicalBody)
164 {
165 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody);
166 // Frees both the body and the shape.
167 m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody);
168 m_terrainBody.Clear();
169 m_terrainShape.Clear();
170 }
171 }
172
173 public override float GetTerrainHeightAtXYZ(Vector3 pos)
174 {
175 // For the moment use the saved heightmap to get the terrain height.
176 // TODO: raycast downward to find the true terrain below the position.
177 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
178
179 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
180 try
181 {
182 ret = m_savedHeightMap[mapIndex];
183 }
184 catch
185 {
186 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
187 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
188 LogHeader, TerrainBase, pos);
189 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
190 }
191 return ret;
192 }
193
194 // The passed position is relative to the base of the region.
195 public override float GetWaterLevelAtXYZ(Vector3 pos)
196 {
197 return m_physicsScene.SimpleWaterLevel;
198 }
199
200 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
201 // Return 'true' if successfully created.
202 public static bool ConvertHeightmapToMesh( BSScene physicsScene,
203 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
204 Vector3 extentBase, // base to be added to all vertices
205 out int indicesCountO, out int[] indicesO,
206 out int verticesCountO, out float[] verticesO)
207 {
208 bool ret = false;
209
210 int indicesCount = 0;
211 int verticesCount = 0;
212 int[] indices = new int[0];
213 float[] vertices = new float[0];
214
215 // Simple mesh creation which assumes magnification == 1.
216 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
217
218 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
219 // from zero to <= sizeX). The triangle indices are then generated as two triangles
220 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
221 // column of vertices are used to complete the triangles of the last row and column
222 // of the heightmap.
223 try
224 {
225 // One vertice per heightmap value plus the vertices off the side and bottom edge.
226 int totalVertices = (sizeX + 1) * (sizeY + 1);
227 vertices = new float[totalVertices * 3];
228 int totalIndices = sizeX * sizeY * 6;
229 indices = new int[totalIndices];
230
231 if (physicsScene != null)
232 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}",
233 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase);
234 float minHeight = float.MaxValue;
235 // Note that sizeX+1 vertices are created since there is land between this and the next region.
236 for (int yy = 0; yy <= sizeY; yy++)
237 {
238 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
239 {
240 int offset = yy * sizeX + xx;
241 // Extend the height with the height from the last row or column
242 if (yy == sizeY) offset -= sizeX;
243 if (xx == sizeX) offset -= 1;
244 float height = heightMap[offset];
245 minHeight = Math.Min(minHeight, height);
246 vertices[verticesCount + 0] = (float)xx + extentBase.X;
247 vertices[verticesCount + 1] = (float)yy + extentBase.Y;
248 vertices[verticesCount + 2] = height + extentBase.Z;
249 verticesCount += 3;
250 }
251 }
252 verticesCount = verticesCount / 3;
253
254 for (int yy = 0; yy < sizeY; yy++)
255 {
256 for (int xx = 0; xx < sizeX; xx++)
257 {
258 int offset = yy * (sizeX + 1) + xx;
259 // Each vertices is presumed to be the upper left corner of a box of two triangles
260 indices[indicesCount + 0] = offset;
261 indices[indicesCount + 1] = offset + 1;
262 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
263 indices[indicesCount + 3] = offset + 1;
264 indices[indicesCount + 4] = offset + sizeX + 2;
265 indices[indicesCount + 5] = offset + sizeX + 1;
266 indicesCount += 6;
267 }
268 }
269
270 ret = true;
271 }
272 catch (Exception e)
273 {
274 if (physicsScene != null)
275 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
276 LogHeader, physicsScene.RegionName, extentBase, e);
277 }
278
279 indicesCountO = indicesCount;
280 indicesO = indices;
281 verticesCountO = verticesCount;
282 verticesO = vertices;
283
284 return ret;
285 }
286
287 private class HeightMapGetter
288 {
289 private float[] m_heightMap;
290 private int m_sizeX;
291 private int m_sizeY;
292 public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY)
293 {
294 m_heightMap = pHeightMap;
295 m_sizeX = pSizeX;
296 m_sizeY = pSizeY;
297 }
298 // The heightmap is extended as an infinite plane at the last height
299 public float GetHeight(int xx, int yy)
300 {
301 int offset = 0;
302 // Extend the height with the height from the last row or column
303 if (yy >= m_sizeY)
304 if (xx >= m_sizeX)
305 offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1);
306 else
307 offset = (m_sizeY - 1) * m_sizeX + xx;
308 else
309 if (xx >= m_sizeX)
310 offset = yy * m_sizeX + (m_sizeX - 1);
311 else
312 offset = yy * m_sizeX + xx;
313
314 return m_heightMap[offset];
315 }
316 }
317
318 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
319 // Version that handles magnification.
320 // Return 'true' if successfully created.
321 public static bool ConvertHeightmapToMesh2( BSScene physicsScene,
322 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
323 int magnification, // number of vertices per heighmap step
324 Vector3 extent, // dimensions of the output mesh
325 Vector3 extentBase, // base to be added to all vertices
326 out int indicesCountO, out int[] indicesO,
327 out int verticesCountO, out float[] verticesO)
328 {
329 bool ret = false;
330
331 int indicesCount = 0;
332 int verticesCount = 0;
333 int[] indices = new int[0];
334 float[] vertices = new float[0];
335
336 HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY);
337
338 // The vertices dimension of the output mesh
339 int meshX = sizeX * magnification;
340 int meshY = sizeY * magnification;
341 // The output size of one mesh step
342 float meshXStep = extent.X / meshX;
343 float meshYStep = extent.Y / meshY;
344
345 // Create an array of vertices that is meshX+1 by meshY+1 (note the loop
346 // from zero to <= meshX). The triangle indices are then generated as two triangles
347 // per heightmap point. There are meshX by meshY of these squares. The extra row and
348 // column of vertices are used to complete the triangles of the last row and column
349 // of the heightmap.
350 try
351 {
352 // Vertices for the output heightmap plus one on the side and bottom to complete triangles
353 int totalVertices = (meshX + 1) * (meshY + 1);
354 vertices = new float[totalVertices * 3];
355 int totalIndices = meshX * meshY * 6;
356 indices = new int[totalIndices];
357
358 if (physicsScene != null)
359 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}",
360 BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY),
361 totalVertices, totalIndices, extentBase);
362
363 float minHeight = float.MaxValue;
364 // Note that sizeX+1 vertices are created since there is land between this and the next region.
365 // Loop through the output vertices and compute the mediun height in between the input vertices
366 for (int yy = 0; yy <= meshY; yy++)
367 {
368 for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
369 {
370 float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point
371 int stepY = (int)offsetY;
372 float fractionalY = offsetY - (float)stepY;
373 float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point
374 int stepX = (int)offsetX;
375 float fractionalX = offsetX - (float)stepX;
376
377 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}",
378 // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY);
379
380 // get the four corners of the heightmap square the mesh point is in
381 float heightUL = hmap.GetHeight(stepX , stepY );
382 float heightUR = hmap.GetHeight(stepX + 1, stepY );
383 float heightLL = hmap.GetHeight(stepX , stepY + 1);
384 float heightLR = hmap.GetHeight(stepX + 1, stepY + 1);
385
386 // bilinear interplolation
387 float height = heightUL * (1 - fractionalX) * (1 - fractionalY)
388 + heightUR * fractionalX * (1 - fractionalY)
389 + heightLL * (1 - fractionalX) * fractionalY
390 + heightLR * fractionalX * fractionalY;
391
392 // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}",
393 // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height);
394
395 minHeight = Math.Min(minHeight, height);
396
397 vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X;
398 vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y;
399 vertices[verticesCount + 2] = height + extentBase.Z;
400 verticesCount += 3;
401 }
402 }
403 // The number of vertices generated
404 verticesCount /= 3;
405
406 // Loop through all the heightmap squares and create indices for the two triangles for that square
407 for (int yy = 0; yy < meshY; yy++)
408 {
409 for (int xx = 0; xx < meshX; xx++)
410 {
411 int offset = yy * (meshX + 1) + xx;
412 // Each vertices is presumed to be the upper left corner of a box of two triangles
413 indices[indicesCount + 0] = offset;
414 indices[indicesCount + 1] = offset + 1;
415 indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column
416 indices[indicesCount + 3] = offset + 1;
417 indices[indicesCount + 4] = offset + meshX + 2;
418 indices[indicesCount + 5] = offset + meshX + 1;
419 indicesCount += 6;
420 }
421 }
422
423 ret = true;
424 }
425 catch (Exception e)
426 {
427 if (physicsScene != null)
428 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
429 LogHeader, physicsScene.RegionName, extentBase, e);
430 }
431
432 indicesCountO = indicesCount;
433 indicesO = indices;
434 verticesCountO = verticesCount;
435 verticesO = vertices;
436
437 return ret;
438 }
439}
440}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
index 662dd68..3329395 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
@@ -29,7 +29,7 @@ using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OMV = OpenMetaverse; 30using OMV = OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.PhysicsModule.BulletS
33{ 33{
34// Classes to allow some type checking for the API 34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space. 35// These hold pointers to allocated objects in the unmanaged space.
@@ -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=");
@@ -163,14 +165,15 @@ public class BulletConstraint
163// than making copies. 165// than making copies.
164public class BulletHMapInfo 166public class BulletHMapInfo
165{ 167{
166 public BulletHMapInfo(uint id, float[] hm) { 168 public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) {
167 ID = id; 169 ID = id;
168 heightMap = hm; 170 heightMap = hm;
169 terrainRegionBase = OMV.Vector3.Zero; 171 terrainRegionBase = OMV.Vector3.Zero;
170 minCoords = new OMV.Vector3(100f, 100f, 25f); 172 minCoords = new OMV.Vector3(100f, 100f, 25f);
171 maxCoords = new OMV.Vector3(101f, 101f, 26f); 173 maxCoords = new OMV.Vector3(101f, 101f, 26f);
172 minZ = maxZ = 0f; 174 minZ = maxZ = 0f;
173 sizeX = sizeY = 256f; 175 sizeX = pSizeX;
176 sizeY = pSizeY;
174 } 177 }
175 public uint ID; 178 public uint ID;
176 public float[] heightMap; 179 public float[] heightMap;
@@ -187,6 +190,7 @@ public class BulletHMapInfo
187public enum CollisionType 190public enum CollisionType
188{ 191{
189 Avatar, 192 Avatar,
193 PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else
190 Groundplane, 194 Groundplane,
191 Terrain, 195 Terrain,
192 Static, 196 Static,
@@ -215,45 +219,55 @@ public static class BulletSimData
215{ 219{
216 220
217// Map of collisionTypes to flags for collision groups and masks. 221// Map of collisionTypes to flags for collision groups and masks.
222// An object's 'group' is the collison groups this object belongs to
223// An object's 'filter' is the groups another object has to belong to in order to collide with me
224// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0)
225//
218// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code 226// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
219// but, instead, use references to this dictionary. Finding and debugging 227// but, instead, use references to this dictionary. Finding and debugging
220// collision flag problems will be made easier. 228// collision flag problems will be made easier.
221public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks 229public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
222 = new Dictionary<CollisionType, CollisionTypeFilterGroup>() 230 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
223{ 231{
224 { CollisionType.Avatar, 232 { CollisionType.Avatar,
225 new CollisionTypeFilterGroup(CollisionType.Avatar, 233 new CollisionTypeFilterGroup(CollisionType.Avatar,
226 (uint)CollisionFilterGroups.BCharacterGroup, 234 (uint)CollisionFilterGroups.BCharacterGroup,
227 (uint)CollisionFilterGroups.BAllGroup) 235 (uint)(CollisionFilterGroups.BAllGroup))
228 }, 236 },
229 { CollisionType.Groundplane, 237 { CollisionType.PhantomToOthersAvatar,
230 new CollisionTypeFilterGroup(CollisionType.Groundplane, 238 new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar,
231 (uint)CollisionFilterGroups.BGroundPlaneGroup, 239 (uint)CollisionFilterGroups.BCharacterGroup,
232 (uint)CollisionFilterGroups.BAllGroup) 240 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup))
241 },
242 { CollisionType.Groundplane,
243 new CollisionTypeFilterGroup(CollisionType.Groundplane,
244 (uint)CollisionFilterGroups.BGroundPlaneGroup,
245 // (uint)CollisionFilterGroups.BAllGroup)
246 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
233 }, 247 },
234 { CollisionType.Terrain, 248 { CollisionType.Terrain,
235 new CollisionTypeFilterGroup(CollisionType.Terrain, 249 new CollisionTypeFilterGroup(CollisionType.Terrain,
236 (uint)CollisionFilterGroups.BTerrainGroup, 250 (uint)CollisionFilterGroups.BTerrainGroup,
237 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) 251 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
238 }, 252 },
239 { CollisionType.Static, 253 { CollisionType.Static,
240 new CollisionTypeFilterGroup(CollisionType.Static, 254 new CollisionTypeFilterGroup(CollisionType.Static,
241 (uint)CollisionFilterGroups.BStaticGroup, 255 (uint)CollisionFilterGroups.BStaticGroup,
242 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 256 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
243 }, 257 },
244 { CollisionType.Dynamic, 258 { CollisionType.Dynamic,
245 new CollisionTypeFilterGroup(CollisionType.Dynamic, 259 new CollisionTypeFilterGroup(CollisionType.Dynamic,
246 (uint)CollisionFilterGroups.BSolidGroup, 260 (uint)CollisionFilterGroups.BSolidGroup,
247 (uint)(CollisionFilterGroups.BAllGroup)) 261 (uint)(CollisionFilterGroups.BAllGroup))
248 }, 262 },
249 { CollisionType.VolumeDetect, 263 { CollisionType.VolumeDetect,
250 new CollisionTypeFilterGroup(CollisionType.VolumeDetect, 264 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
251 (uint)CollisionFilterGroups.BSensorTrigger, 265 (uint)CollisionFilterGroups.BSensorTrigger,
252 (uint)(~CollisionFilterGroups.BSensorTrigger)) 266 (uint)(~CollisionFilterGroups.BSensorTrigger))
253 }, 267 },
254 { CollisionType.LinksetChild, 268 { CollisionType.LinksetChild,
255 new CollisionTypeFilterGroup(CollisionType.LinksetChild, 269 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
256 (uint)CollisionFilterGroups.BLinksetChildGroup, 270 (uint)CollisionFilterGroups.BLinksetChildGroup,
257 (uint)(CollisionFilterGroups.BNoneGroup)) 271 (uint)(CollisionFilterGroups.BNoneGroup))
258 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) 272 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 }, 273 },
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
index a8a4ff5..0453376 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
+++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
@@ -1,93 +1,107 @@
1CURRENT PRIORITIES 1CURRENT PROBLEMS TO FIX AND/OR LOOK AT
2================================================= 2=================================================
3Redo BulletSimAPI to allow native C# implementation of Bullet option. 3Vehicle buoyancy. Computed correctly? Possibly creating very large effective mass.
4Avatar movement 4 Interaction of llSetBuoyancy and vehicle buoyancy. Should be additive?
5 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle 5 Negative buoyancy computed correctly
6 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) 6Center-of-gravity
7 avatar capsule rotation completed 7Computation of mesh mass. How done? How should it be done?
8llMoveToTarget
9Enable vehicle border crossings (at least as poorly as ODE) 8Enable vehicle border crossings (at least as poorly as ODE)
10 Terrain skirts 9 Terrain skirts
11 Avatar created in previous region and not new region when crossing border 10 Avatar created in previous region and not new region when crossing border
12 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) 11 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
13Vehicle movement on terrain smoothness 12User settable terrain mesh
13 Allow specifying as convex or concave and use different getHeight functions depending
14Boats, when turning nose down into the water
15 Acts like rotation around Z is also effecting rotation around X and Y
16Deleting a linkset while standing on the root will leave the physical shape of the root behind.
17 Not sure if it is because standing on it. Done with large prim linksets.
18Linkset child rotations.
19 Nebadon spiral tube has middle sections which are rotated wrong.
20 Select linked spiral tube. Delink and note where the middle section ends up.
21Teravus llMoveToTarget script debug
22 Mixing of hover, buoyancy/gravity, moveToTarget, into one force
23 Setting hover height to zero disables hover even if hover flags are on (from SL wiki)
24limitMotorUp calibration (more down?)
25llRotLookAt
26llLookAt
27Convert to avatar mesh capsule. Include rotation of capsule.
14Vehicle script tuning/debugging 28Vehicle script tuning/debugging
15 Avanti speed script 29 Avanti speed script
16 Weapon shooter script 30 Weapon shooter script
17limitMotorUp calibration (more down?) 31Move material definitions (friction, ...) into simulator.
18Boats float low in the water 32osGetPhysicsEngineVerion() and create a version code for the C++ DLL
19Add material densities to the material types. 33One sided meshes? Should terrain be built into a closed shape?
20 34 When meshes get partially wedged into the terrain, they cannot push themselves out.
21CRASHES 35 It is possible that Bullet processes collisions whether entering or leaving a mesh.
22================================================= 36 Ref: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4869
2320121129.1411: editting/moving phys object across region boundries causes crash 37Small physical objects do not interact correctly
24 getPos-> btRigidBody::upcast -> getBodyType -> BOOM 38 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
2520121128.1600: mesh object not rezzing (no physics mesh). 39 The chain will fall apart and pairs will dance around on ground
26 Causes many errors. Doesn't stop after first error with box shape. 40 Chains of 1x1x.2 will stay connected but will dance.
27 Eventually crashes when deleting the object. 41 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
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 42
32VEHICLES TODO LIST: 43VEHICLES TODO LIST:
33================================================= 44=================================================
34Angular motor direction is global coordinates rather than local coordinates 45LINEAR_MOTOR_DIRECTION values should be clamped to reasonable numbers.
35Border crossing with linked vehicle causes crash 46 What are the limits in SL?
36Vehicles (Move smoothly) 47 Same for other velocity settings.
37Add vehicle collisions so IsColliding is properly reported. 48UBit improvements to remove rubber-banding of avatars sitting on vehicle child prims:
38 Needed for banking, limitMotorUp, movementLimiting, ... 49 https://github.com/UbitUmarov/Ubit-opensim
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. 50Some vehicles should not be able to turn if no speed or off ground.
42Cannot edit/move a vehicle being ridden: it jumps back to the origional position. 51Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
43Neb car jiggling left and right 52Neb car jiggling left and right
44 Happens on terrain and any other mesh object. Flat cubes are much smoother. 53 Happens on terrain and any other mesh object. Flat cubes are much smoother.
45 This has been reduced but not eliminated. 54 This has been reduced but not eliminated.
46Implement referenceFrame for all the motion routines. 55Implement referenceFrame for all the motion routines.
47Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
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. 56Verify llGetVel() is returning a smooth and good value for vehicle movement.
50llGetVel() should return the root's velocity if requested in a child prim. 57llGetVel() should return the root's velocity if requested in a child prim.
51Implement function efficiency for lineaar and angular motion. 58Implement function efficiency for lineaar and angular motion.
52After 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
54Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) 59Linkset 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(). 60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
57 A kludge that isn't fixing the real problem of Bullet adding extra motion. 61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
58Incorporate inter-relationship of angular corrections. For instance, angularDeflection 62Incorporate inter-relationship of angular corrections. For instance, angularDeflection
59 and angularMotorUp will compute same X or Y correction. When added together 63 and angularMotorUp will compute same X or Y correction. When added together
60 creates over-correction and over-shoot and wabbling. 64 creates over-correction and over-shoot and wabbling.
65Vehicle attributes are not restored when a vehicle is rezzed on region creation
66 Create vehicle, setup vehicle properties, restart region, vehicle is not reinitialized.
67What to do if vehicle and prim buoyancy differ?
61 68
62BULLETSIM TODO LIST: 69GENERAL TODO LIST:
63================================================= 70=================================================
71Resitution of a prim works on another prim but not on terrain.
72 The dropped prim doesn't bounce properly on the terrain.
73Add a sanity check for PIDTarget location.
74Level-of-detail for mesh creation. Prims with circular interiors require lod of 32.
75 Is much saved with lower LODs? At the moment, all set to 32.
76Collisions are inconsistant: arrows are supposed to hit and report collision. Often don't.
77 If arrow show at prim, collision reported about 1/3 of time. If collision reported,
78 both arrow and prim report it. The arrow bounces off the prim 9 out of 10 times.
79 Shooting 5m sphere "arrows" at 60m/s.
80llMoveToTarget objects are not effected by gravity until target is removed.
81Compute CCD parameters based on body size
82Can solver iterations be changed per body/shape? Can be for constraints but what
83 about regular vehicles?
84Implement llSetPhysicalMaterial.
85 extend it with Center-of-mass, rolling friction, density
86Implement llSetForceAndTorque.
87Change BSPrim.moveToTarget to used forces rather than changing position
88 Changing position allows one to move through walls
64Implement an avatar mesh shape. The Bullet capsule is way too limited. 89Implement an avatar mesh shape. The Bullet capsule is way too limited.
65 Consider just hand creating a vertex/index array in a new BSShapeAvatar. 90 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
91Verify/fix phantom, volume-detect objects do not fall to infinity. Should stop at terrain.
66Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. 92Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
67Duplicating a physical prim causes old prim to jump away 93Duplicating 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. 94 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
69Scenes with hundred of thousands of static objects take a lot of physics CPU time. 95Scenes with hundred of thousands of static objects take a lot of physics CPU time.
70BSPrim.Force should set a continious force on the prim. The force should be
71 applied each tick. Some limits?
72Gun sending shooter flying. 96Gun sending shooter flying.
73Collision margin (gap between physical objects lying on each other) 97Collision margin (gap between physical objects lying on each other)
74Boundry checking (crashes related to crossing boundry) 98Boundry checking (crashes related to crossing boundry)
75 Add check for border edge position for avatars and objects. 99 Add check for border edge position for avatars and objects.
76 Verify the events are created for border crossings. 100 Verify the events are created for border crossings.
77Avatar rotation (check out changes to ScenePresence for physical rotation)
78Avatar running (what does phys engine need to do?)
79Small physical objects do not interact correctly
80 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
81 The chain will fall apart and pairs will dance around on ground
82 Chains of 1x1x.2 will stay connected but will dance.
83 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
84Add PID motor for avatar movement (slow to stop, ...)
85setForce should set a constant force. Different than AddImpulse.
86Implement raycast.
87Implement ShapeCollection.Dispose() 101Implement ShapeCollection.Dispose()
88Implement water as a plain so raycasting and collisions can happen with same. 102Implement water as a plain or mesh so raycasting and collisions can happen with same.
89Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE 103Add collision penetration return
90 Also osGetPhysicsEngineVerion() maybe. 104 Add field passed back by BulletSim.dll and fill with info in ManifoldConstact.GetDistance()
91Linkset.Position and Linkset.Orientation requre rewrite to properly return 105Linkset.Position and Linkset.Orientation requre rewrite to properly return
92 child position. LinksetConstraint acts like it's at taint time!! 106 child position. LinksetConstraint acts like it's at taint time!!
93Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F) 107Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
@@ -99,14 +113,17 @@ Selecting and deselecting physical objects causes CPU processing time to jump
99Re-implement buoyancy as a separate force on the object rather than diddling gravity. 113Re-implement buoyancy as a separate force on the object rather than diddling gravity.
100 Register a pre-step event to add the force. 114 Register a pre-step event to add the force.
101More efficient memory usage when passing hull information from BSPrim to BulletSim 115More efficient memory usage when passing hull information from BSPrim to BulletSim
102Avatar movement motor check for zero or small movement. Somehow suppress small movements
103 when avatar has stopped and is just standing. Simple test for near zero has
104 the problem of preventing starting up (increase from zero) especially when falling.
105Physical and phantom will drop through the terrain 116Physical and phantom will drop through the terrain
106 117
107 118
108LINKSETS 119LINKSETS
109====================================================== 120======================================================
121Child prims do not report collisions
122Allow children of a linkset to be phantom:
123 http://opensim-dev.2196679.n2.nabble.com/Setting-a-single-child-prim-to-Phantom-tp7578513.html
124 Add OS_STATUS_PHANTOM_PRIM to llSetLinkPrimitaveParamsFast.
125Editing a child of a linkset causes the child to go phantom
126 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 127Offset the center of the linkset to be the geometric center of all the prims
111 Not quite the same as the center-of-gravity 128 Not quite the same as the center-of-gravity
112Linksets should allow collisions to individual children 129Linksets should allow collisions to individual children
@@ -117,11 +134,9 @@ LinksetCompound: when one of the children changes orientation (like tires
117Verify/think through scripts in children of linksets. What do they reference 134Verify/think through scripts in children of linksets. What do they reference
118 and return when getting position, velocity, ... 135 and return when getting position, velocity, ...
119Confirm constraint linksets still work after making all the changes for compound linksets. 136Confirm constraint linksets still work after making all the changes for compound linksets.
137Use 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. 138Add '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. 139 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 140Speed up creation of large physical linksets
126 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical. 141 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). 142 REALLY bad for very large physical linksets (freezes the sim for many seconds).
@@ -131,25 +146,27 @@ Eliminate collisions between objects in a linkset. (LinksetConstraint)
131 146
132MORE 147MORE
133====================================================== 148======================================================
134Test avatar walking up stairs. How does compare with SL. 149Compute 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. 150Create tests for different interface components
151 Have test objects/scripts measure themselves and turn color if correct/bad
152 Test functions in SL and calibrate correctness there
153 Create auto rezzer and tracker to run through the tests
154Do we need to do convex hulls all the time? Can complex meshes be left meshes?
155 There is some problem with meshes and collisions
156 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. 157Debounce avatar contact so legs don't keep folding up when standing.
137Implement LSL physics controls. Like STATUS_ROTATE_X.
138Add border extensions to terrain to help region crossings and objects leaving region. 158Add border extensions to terrain to help region crossings and objects leaving region.
139Use a different capsule shape for avatar when sitting 159Use a different capsule shape for avatar when sitting
140 LL uses a pyrimidal shape scaled by the avatar's bounding box 160 LL uses a pyrimidal shape scaled by the avatar's bounding box
141 http://wiki.secondlife.com/wiki/File:Avmeshforms.png 161 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
142
143Performance test with lots of avatars. Can BulletSim support a thousand? 162Performance test with lots of avatars. Can BulletSim support a thousand?
144Optimize collisions in C++: only send up to the object subscribed to collisions. 163Optimize 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) 164 Use collision subscription and remove the collsion(A,B) and collision(B,A)
146Check whether SimMotionState needs large if statement (see TODO). 165Check whether SimMotionState needs large if statement (see TODO).
147
148Implement 'top colliders' info. 166Implement 'top colliders' info.
149Avatar jump 167Avatar jump
150Performance measurement and changes to make quicker. 168Performance measurement and changes to make quicker.
151Implement detailed physics stats (GetStats()). 169Implement detailed physics stats (GetStats()).
152
153Measure performance improvement from hulls 170Measure performance improvement from hulls
154Test not using ghost objects for volume detect implementation. 171Test not using ghost objects for volume detect implementation.
155Performance of closures and delegates for taint processing 172Performance of closures and delegates for taint processing
@@ -157,9 +174,7 @@ Performance of closures and delegates for taint processing
157 Is any slowdown introduced by the existing implementation significant? 174 Is any slowdown introduced by the existing implementation significant?
158Is there are more efficient method of implementing pre and post step actions? 175Is there are more efficient method of implementing pre and post step actions?
159 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C 176 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
160
161Physics Arena central pyramid: why is one side permiable? 177Physics Arena central pyramid: why is one side permiable?
162
163In SL, perfect spheres don't seem to have rolling friction. Add special case. 178In SL, perfect spheres don't seem to have rolling friction. Add special case.
164Enforce physical parameter min/max: 179Enforce physical parameter min/max:
165 Gravity: [-1, 28] 180 Gravity: [-1, 28]
@@ -168,6 +183,7 @@ Enforce physical parameter min/max:
168 Restitution [0, 1] 183 Restitution [0, 1]
169 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test 184 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
170Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html 185Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
186Keep avatar scaling correct. http://pennycow.blogspot.fr/2011/07/matter-of-scale.html
171 187
172INTERNAL IMPROVEMENT/CLEANUP 188INTERNAL IMPROVEMENT/CLEANUP
173================================================= 189=================================================
@@ -190,22 +206,19 @@ Generalize Dynamics and PID with standardized motors.
190Generalize Linkset and vehicles into PropertyManagers 206Generalize Linkset and vehicles into PropertyManagers
191 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies 207 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
192 Potentially add events for shape destruction, etc. 208 Potentially add events for shape destruction, etc.
193Complete implemention of preStepActions 209Better mechanism for resetting linkset set and vehicle parameters when body rebuilt.
194 Replace vehicle step call with prestep event. 210 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) 211Implement linkset by setting position of children when root updated. (LinksetManual)
197 Linkset implementation using manual prim movement. 212 Linkset implementation using manual prim movement.
198LinkablePrim class? Would that simplify/centralize the linkset logic? 213LinkablePrim class? Would that simplify/centralize the linkset logic?
199BSScene.UpdateParameterSet() is broken. How to set params on objects? 214BSScene.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 215Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
203 bob at the water level. BSPrim.PositionSanityCheck(). 216 bob at the water level. BSPrim.PositionSanityCheck()
204Should taints check for existance or activeness of target? 217Should taints check for existance or activeness of target?
205 When destroying linksets/etc, taints can be generated for objects that are 218 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 219 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. 220 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? 221 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) 222Parameters 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'? 223Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
211There are TOO MANY interfaces from BulletSim core to Bullet itself 224There are TOO MANY interfaces from BulletSim core to Bullet itself
@@ -270,3 +283,97 @@ llSetBuoyancy() (DONE)
270 (Resolution: Bullet resets object gravity when added to world. Moved set gravity) 283 (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) 284Avatar 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) 285 (Resolution: set default density to 3.5 (from 60) which is closer to SL)
286Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
287 (Resolution: added BSAPITemplate and then interfaces for C++ Bullet and C# BulletXNA
288Meshes rendering as bounding boxes (DONE)
289 (Resolution: Added test for mesh/sculpties in native shapes so it didn't think it was a box)
290llMoveToTarget (Resolution: added simple motor to update the position.)
291Angular motor direction is global coordinates rather than local coordinates (DONE)
292Add vehicle collisions so IsColliding is properly reported. (DONE)
293 Needed for banking, limitMotorUp, movementLimiting, ...
294 (Resolution: added CollisionFlags.BS_VEHICLE_COLLISION and code to use it)
295VehicleAddForce is not scaled by the simulation step but it is only
296 applied for one step. Should it be scaled? (DONE)
297 (Resolution: use force for timed things, Impulse for immediate, non-timed things)
298Complete implemention of preStepActions (DONE)
299 Replace vehicle step call with prestep event.
300 Is there a need for postStepActions? postStepTaints?
301Disable activity of passive linkset children. (DONE)
302 Since the linkset is a compound object, the old prims are left lying
303 around and need to be phantomized so they don't collide, ...
304Remove HeightmapInfo from terrain specification (DONE)
305 Since C++ code does not need terrain height, this structure et al are not needed.
306Surfboard go wonky when turning (DONE)
307 Angular motor direction is global coordinates rather than local coordinates?
308 (Resolution: made angular motor direction correct coordinate system)
309Mantis 6040 script http://opensimulator.org/mantis/view.php?id=6040 (DONE)
310 Msg Kayaker on OSGrid when working
311 (Resolution: LINEAR_DIRECTION is in vehicle coords. Test script does the
312 same in SL as in OS/BulletSim)
313Boats float low in the water (DONE)
314Boats floating at proper level (DONE)
315When is force introduced by SetForce removed? The prestep action could go forever. (DONE)
316 (Resolution: setForce registers a prestep action which keeps applying the force)
317Child movement in linkset (don't rebuild linkset) (DONE 20130122))
318Avatar standing on a moving object should start to move with the object. (DONE 20130125)
319Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
320 Verify that angular motion specified around Z moves in the vehicle coordinates.
321 DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
322Nebadon vehicles turning funny in arena (DONE)
323Lock axis (DONE 20130401)
324Terrain detail: double terrain mesh detail (DONE)
325Use the HACD convex hull routine in Bullet rather than the C# version.
326 Speed up hullifying large meshes. (DONE)
327Vehicle ride, get up, ride again. Second time vehicle does not act correctly.
328 Have to rez new vehicle and delete the old to fix situation.
329 (DONE 20130520: normalize rotations)
330Hitting RESET on Nebadon's vehicle while riding causes vehicle to get into odd
331 position state where it will not settle onto ground properly, etc
332 (DONE 20130520: normalize rotations)
333Two of Nebadon vehicles in a sim max the CPU. This is new.
334 (DONE 20130520: two problems: if asset failed to mesh, constantly refetched
335 asset; vehicle was sending too many messages to all linkset members)
336Add material densities to the material types. (WILL NOT BE DONE: not how it is done)
337Avatars walking up stairs (DONE)
338Avatar movement
339 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
340 walking up stairs is not calibrated correctly (stairs out of Kepler cabin) (DONE)
341 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
342After getting off a vehicle, the root prim is phantom (can be walked through)
343 Need to force a position update for the root prim after compound shape destruction
344 (DONE)
345Explore btGImpactMeshShape as alternative to convex hulls for simplified physical objects.
346 Regular triangle meshes don't do physical collisions.
347 (DONE: discovered GImpact is VERY CPU intensive)
348Script changing rotation of child prim while vehicle moving (eg turning wheel) causes
349 the wheel to appear to jump back. Looks like sending position from previous update.
350 (DONE: redo of compound linksets fixed problem)
351Refarb compound linkset creation to create a pseudo-root for center-of-mass
352 Let children change their shape to physical indendently and just add shapes to compound
353 (DONE: redo of compound linkset fixed problem)
354Vehicle angular vertical attraction (DONE: vegaslon code)
355vehicle angular banking (DONE: vegaslon code)
356Vehicle angular deflection (DONE: vegaslon code)
357 Preferred orientation angular correction fix
358Vehicles (Move smoothly)
359For limitMotorUp, use raycast down to find if vehicle is in the air.
360 (WILL NOT BE DONE: gravity does the job well enough)
361BSPrim.Force should set a continious force on the prim. The force should be
362 applied each tick. Some limits?
363 (DONE: added physical actors. Implemented SetForce, SetTorque, ...)
364Implement LSL physics controls. Like STATUS_ROTATE_X. (DONE)
365Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
366Avatar rotation (check out changes to ScenePresence for physical rotation) (DONE)
367Avatar running (what does phys engine need to do?) (DONE: multiplies run factor by walking force)
368setForce should set a constant force. Different than AddImpulse. (DONE)
369Add PID motor for avatar movement (slow to stop, ...) (WNBD: current works ok)
370Avatar movement motor check for zero or small movement. Somehow suppress small movements
371 when avatar has stopped and is just standing. Simple test for near zero has
372 the problem of preventing starting up (increase from zero) especially when falling.
373 (DONE: avatar movement actor knows if standing on stationary object and zeros motion)
374Can the 'inTaintTime' flag be cleaned up and used? For instance, a call to
375 BSScene.TaintedObject() could immediately execute the callback if already in taint time.
376 (DONE)
377
378
379
diff --git a/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs
new file mode 100755
index 0000000..2ba3c5a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/ExtendedPhysics.cs
@@ -0,0 +1,622 @@
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.Reflection;
31using System.Text;
32using System.Threading;
33
34using OpenSim.Framework;
35using OpenSim.Region.Framework;
36using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes;
38using OpenSim.Region.PhysicsModules.SharedBase;
39
40using Mono.Addins;
41using Nini.Config;
42using log4net;
43using OpenMetaverse;
44
45namespace OpenSim.Region.PhysicsModule.BulletS
46{
47 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
48 public class ExtendedPhysics : INonSharedRegionModule
49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private static string LogHeader = "[EXTENDED PHYSICS]";
52
53 // =============================================================
54 // Since BulletSim is a plugin, this these values aren't defined easily in one place.
55 // This table must correspond to an identical table in BSScene.
56
57 // Per scene functions. See BSScene.
58
59 // Per avatar functions. See BSCharacter.
60
61 // Per prim functions. See BSPrim.
62 public const string PhysFunctGetLinksetType = "BulletSim.GetLinksetType";
63 public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
64 public const string PhysFunctChangeLinkFixed = "BulletSim.ChangeLinkFixed";
65 public const string PhysFunctChangeLinkType = "BulletSim.ChangeLinkType";
66 public const string PhysFunctGetLinkType = "BulletSim.GetLinkType";
67 public const string PhysFunctChangeLinkParams = "BulletSim.ChangeLinkParams";
68 public const string PhysFunctAxisLockLimits = "BulletSim.AxisLockLimits";
69
70 // =============================================================
71
72 private IConfig Configuration { get; set; }
73 private bool Enabled { get; set; }
74 private Scene BaseScene { get; set; }
75 private IScriptModuleComms Comms { get; set; }
76
77 #region INonSharedRegionModule
78
79 public string Name { get { return this.GetType().Name; } }
80
81 public void Initialise(IConfigSource config)
82 {
83 BaseScene = null;
84 Enabled = false;
85 Configuration = null;
86 Comms = null;
87
88 try
89 {
90 if ((Configuration = config.Configs["ExtendedPhysics"]) != null)
91 {
92 Enabled = Configuration.GetBoolean("Enabled", Enabled);
93 }
94 }
95 catch (Exception e)
96 {
97 m_log.ErrorFormat("{0} Initialization error: {0}", LogHeader, e);
98 }
99
100 m_log.InfoFormat("{0} module {1} enabled", LogHeader, (Enabled ? "is" : "is not"));
101 }
102
103 public void Close()
104 {
105 if (BaseScene != null)
106 {
107 BaseScene.EventManager.OnObjectAddedToScene -= EventManager_OnObjectAddedToScene;
108 BaseScene.EventManager.OnSceneObjectPartUpdated -= EventManager_OnSceneObjectPartUpdated;
109 BaseScene = null;
110 }
111 }
112
113 public void AddRegion(Scene scene)
114 {
115 }
116
117 public void RemoveRegion(Scene scene)
118 {
119 if (BaseScene != null && BaseScene == scene)
120 {
121 Close();
122 }
123 }
124
125 public void RegionLoaded(Scene scene)
126 {
127 if (!Enabled) return;
128
129 BaseScene = scene;
130
131 Comms = BaseScene.RequestModuleInterface<IScriptModuleComms>();
132 if (Comms == null)
133 {
134 m_log.WarnFormat("{0} ScriptModuleComms interface not defined", LogHeader);
135 Enabled = false;
136
137 return;
138 }
139
140 // Register as LSL functions all the [ScriptInvocation] marked methods.
141 Comms.RegisterScriptInvocations(this);
142 Comms.RegisterConstants(this);
143
144 // When an object is modified, we might need to update its extended physics parameters
145 BaseScene.EventManager.OnObjectAddedToScene += EventManager_OnObjectAddedToScene;
146 BaseScene.EventManager.OnSceneObjectPartUpdated += EventManager_OnSceneObjectPartUpdated;
147
148 }
149
150 public Type ReplaceableInterface { get { return null; } }
151
152 #endregion // INonSharedRegionModule
153
154 private void EventManager_OnObjectAddedToScene(SceneObjectGroup obj)
155 {
156 }
157
158 // Event generated when some property of a prim changes.
159 private void EventManager_OnSceneObjectPartUpdated(SceneObjectPart sop, bool isFullUpdate)
160 {
161 }
162
163 [ScriptConstant]
164 public const int PHYS_CENTER_OF_MASS = 1 << 0;
165
166 [ScriptInvocation]
167 public string physGetEngineType(UUID hostID, UUID scriptID)
168 {
169 string ret = string.Empty;
170
171 if (BaseScene.PhysicsScene != null)
172 {
173 ret = BaseScene.PhysicsScene.EngineType;
174 }
175
176 return ret;
177 }
178
179 // Code for specifying params.
180 // The choice if 14700 is arbitrary and only serves to catch parameter code misuse.
181 [ScriptConstant]
182 public const int PHYS_AXIS_LOCK_LINEAR = 14700;
183 [ScriptConstant]
184 public const int PHYS_AXIS_LOCK_LINEAR_X = 14701;
185 [ScriptConstant]
186 public const int PHYS_AXIS_LIMIT_LINEAR_X = 14702;
187 [ScriptConstant]
188 public const int PHYS_AXIS_LOCK_LINEAR_Y = 14703;
189 [ScriptConstant]
190 public const int PHYS_AXIS_LIMIT_LINEAR_Y = 14704;
191 [ScriptConstant]
192 public const int PHYS_AXIS_LOCK_LINEAR_Z = 14705;
193 [ScriptConstant]
194 public const int PHYS_AXIS_LIMIT_LINEAR_Z = 14706;
195 [ScriptConstant]
196 public const int PHYS_AXIS_LOCK_ANGULAR = 14707;
197 [ScriptConstant]
198 public const int PHYS_AXIS_LOCK_ANGULAR_X = 14708;
199 [ScriptConstant]
200 public const int PHYS_AXIS_LIMIT_ANGULAR_X = 14709;
201 [ScriptConstant]
202 public const int PHYS_AXIS_LOCK_ANGULAR_Y = 14710;
203 [ScriptConstant]
204 public const int PHYS_AXIS_LIMIT_ANGULAR_Y = 14711;
205 [ScriptConstant]
206 public const int PHYS_AXIS_LOCK_ANGULAR_Z = 14712;
207 [ScriptConstant]
208 public const int PHYS_AXIS_LIMIT_ANGULAR_Z = 14713;
209 [ScriptConstant]
210 public const int PHYS_AXIS_UNLOCK_LINEAR = 14714;
211 [ScriptConstant]
212 public const int PHYS_AXIS_UNLOCK_LINEAR_X = 14715;
213 [ScriptConstant]
214 public const int PHYS_AXIS_UNLOCK_LINEAR_Y = 14716;
215 [ScriptConstant]
216 public const int PHYS_AXIS_UNLOCK_LINEAR_Z = 14717;
217 [ScriptConstant]
218 public const int PHYS_AXIS_UNLOCK_ANGULAR = 14718;
219 [ScriptConstant]
220 public const int PHYS_AXIS_UNLOCK_ANGULAR_X = 14719;
221 [ScriptConstant]
222 public const int PHYS_AXIS_UNLOCK_ANGULAR_Y = 14720;
223 [ScriptConstant]
224 public const int PHYS_AXIS_UNLOCK_ANGULAR_Z = 14721;
225 [ScriptConstant]
226 public const int PHYS_AXIS_UNLOCK = 14722;
227 // physAxisLockLimits()
228 [ScriptInvocation]
229 public int physAxisLock(UUID hostID, UUID scriptID, object[] parms)
230 {
231 int ret = -1;
232 if (!Enabled) return ret;
233
234 PhysicsActor rootPhysActor;
235 if (GetRootPhysActor(hostID, out rootPhysActor))
236 {
237 object[] parms2 = AddToBeginningOfArray(rootPhysActor, null, parms);
238 ret = MakeIntError(rootPhysActor.Extension(PhysFunctAxisLockLimits, parms2));
239 }
240
241 return ret;
242 }
243
244 [ScriptConstant]
245 public const int PHYS_LINKSET_TYPE_CONSTRAINT = 0;
246 [ScriptConstant]
247 public const int PHYS_LINKSET_TYPE_COMPOUND = 1;
248 [ScriptConstant]
249 public const int PHYS_LINKSET_TYPE_MANUAL = 2;
250
251 [ScriptInvocation]
252 public int physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
253 {
254 int ret = -1;
255 if (!Enabled) return ret;
256
257 // The part that is requesting the change.
258 SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
259
260 if (requestingPart != null)
261 {
262 // The change is always made to the root of a linkset.
263 SceneObjectGroup containingGroup = requestingPart.ParentGroup;
264 SceneObjectPart rootPart = containingGroup.RootPart;
265
266 if (rootPart != null)
267 {
268 PhysicsActor rootPhysActor = rootPart.PhysActor;
269 if (rootPhysActor != null)
270 {
271 if (rootPhysActor.IsPhysical)
272 {
273 // Change a physical linkset by making non-physical, waiting for one heartbeat so all
274 // the prim and linkset state is updated, changing the type and making the
275 // linkset physical again.
276 containingGroup.ScriptSetPhysicsStatus(false);
277 Thread.Sleep(150); // longer than one heartbeat tick
278
279 // A kludge for the moment.
280 // Since compound linksets move the children but don't generate position updates to the
281 // simulator, it is possible for compound linkset children to have out-of-sync simulator
282 // and physical positions. The following causes the simulator to push the real child positions
283 // down into the physics engine to get everything synced.
284 containingGroup.UpdateGroupPosition(containingGroup.AbsolutePosition);
285 containingGroup.UpdateGroupRotationR(containingGroup.GroupRotation);
286
287 object[] parms2 = { rootPhysActor, null, linksetType };
288 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
289 Thread.Sleep(150); // longer than one heartbeat tick
290
291 containingGroup.ScriptSetPhysicsStatus(true);
292 }
293 else
294 {
295 // Non-physical linksets don't have a physical instantiation so there is no state to
296 // worry about being updated.
297 object[] parms2 = { rootPhysActor, null, linksetType };
298 ret = MakeIntError(rootPhysActor.Extension(PhysFunctSetLinksetType, parms2));
299 }
300 }
301 else
302 {
303 m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}",
304 LogHeader, rootPart.Name, hostID);
305 }
306 }
307 else
308 {
309 m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}",
310 LogHeader, requestingPart.Name, hostID);
311 }
312 }
313 else
314 {
315 m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
316 }
317 return ret;
318 }
319
320 [ScriptInvocation]
321 public int physGetLinksetType(UUID hostID, UUID scriptID)
322 {
323 int ret = -1;
324 if (!Enabled) return ret;
325
326 PhysicsActor rootPhysActor;
327 if (GetRootPhysActor(hostID, out rootPhysActor))
328 {
329 object[] parms2 = { rootPhysActor, null };
330 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinksetType, parms2));
331 }
332 else
333 {
334 m_log.WarnFormat("{0} physGetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
335 }
336 return ret;
337 }
338
339 [ScriptConstant]
340 public const int PHYS_LINK_TYPE_FIXED = 1234;
341 [ScriptConstant]
342 public const int PHYS_LINK_TYPE_HINGE = 4;
343 [ScriptConstant]
344 public const int PHYS_LINK_TYPE_SPRING = 9;
345 [ScriptConstant]
346 public const int PHYS_LINK_TYPE_6DOF = 6;
347 [ScriptConstant]
348 public const int PHYS_LINK_TYPE_SLIDER = 7;
349
350 // physChangeLinkType(integer linkNum, integer typeCode)
351 [ScriptInvocation]
352 public int physChangeLinkType(UUID hostID, UUID scriptID, int linkNum, int typeCode)
353 {
354 int ret = -1;
355 if (!Enabled) return ret;
356
357 PhysicsActor rootPhysActor;
358 PhysicsActor childPhysActor;
359
360 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
361 {
362 object[] parms2 = { rootPhysActor, childPhysActor, typeCode };
363 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
364 }
365
366 return ret;
367 }
368
369 // physGetLinkType(integer linkNum)
370 [ScriptInvocation]
371 public int physGetLinkType(UUID hostID, UUID scriptID, int linkNum)
372 {
373 int ret = -1;
374 if (!Enabled) return ret;
375
376 PhysicsActor rootPhysActor;
377 PhysicsActor childPhysActor;
378
379 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
380 {
381 object[] parms2 = { rootPhysActor, childPhysActor };
382 ret = MakeIntError(rootPhysActor.Extension(PhysFunctGetLinkType, parms2));
383 }
384
385 return ret;
386 }
387
388 // physChangeLinkFixed(integer linkNum)
389 // Change the link between the root and the linkNum into a fixed, static physical connection.
390 [ScriptInvocation]
391 public int physChangeLinkFixed(UUID hostID, UUID scriptID, int linkNum)
392 {
393 int ret = -1;
394 if (!Enabled) return ret;
395
396 PhysicsActor rootPhysActor;
397 PhysicsActor childPhysActor;
398
399 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
400 {
401 object[] parms2 = { rootPhysActor, childPhysActor , PHYS_LINK_TYPE_FIXED };
402 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkType, parms2));
403 }
404
405 return ret;
406 }
407
408 // Code for specifying params.
409 // The choice if 14400 is arbitrary and only serves to catch parameter code misuse.
410 public const int PHYS_PARAM_MIN = 14401;
411
412 [ScriptConstant]
413 public const int PHYS_PARAM_FRAMEINA_LOC = 14401;
414 [ScriptConstant]
415 public const int PHYS_PARAM_FRAMEINA_ROT = 14402;
416 [ScriptConstant]
417 public const int PHYS_PARAM_FRAMEINB_LOC = 14403;
418 [ScriptConstant]
419 public const int PHYS_PARAM_FRAMEINB_ROT = 14404;
420 [ScriptConstant]
421 public const int PHYS_PARAM_LINEAR_LIMIT_LOW = 14405;
422 [ScriptConstant]
423 public const int PHYS_PARAM_LINEAR_LIMIT_HIGH = 14406;
424 [ScriptConstant]
425 public const int PHYS_PARAM_ANGULAR_LIMIT_LOW = 14407;
426 [ScriptConstant]
427 public const int PHYS_PARAM_ANGULAR_LIMIT_HIGH = 14408;
428 [ScriptConstant]
429 public const int PHYS_PARAM_USE_FRAME_OFFSET = 14409;
430 [ScriptConstant]
431 public const int PHYS_PARAM_ENABLE_TRANSMOTOR = 14410;
432 [ScriptConstant]
433 public const int PHYS_PARAM_TRANSMOTOR_MAXVEL = 14411;
434 [ScriptConstant]
435 public const int PHYS_PARAM_TRANSMOTOR_MAXFORCE = 14412;
436 [ScriptConstant]
437 public const int PHYS_PARAM_CFM = 14413;
438 [ScriptConstant]
439 public const int PHYS_PARAM_ERP = 14414;
440 [ScriptConstant]
441 public const int PHYS_PARAM_SOLVER_ITERATIONS = 14415;
442 [ScriptConstant]
443 public const int PHYS_PARAM_SPRING_AXIS_ENABLE = 14416;
444 [ScriptConstant]
445 public const int PHYS_PARAM_SPRING_DAMPING = 14417;
446 [ScriptConstant]
447 public const int PHYS_PARAM_SPRING_STIFFNESS = 14418;
448 [ScriptConstant]
449 public const int PHYS_PARAM_LINK_TYPE = 14419;
450 [ScriptConstant]
451 public const int PHYS_PARAM_USE_LINEAR_FRAMEA = 14420;
452 [ScriptConstant]
453 public const int PHYS_PARAM_SPRING_EQUILIBRIUM_POINT = 14421;
454
455 public const int PHYS_PARAM_MAX = 14421;
456
457 // Used when specifying a parameter that has settings for the three linear and three angular axis
458 [ScriptConstant]
459 public const int PHYS_AXIS_ALL = -1;
460 [ScriptConstant]
461 public const int PHYS_AXIS_LINEAR_ALL = -2;
462 [ScriptConstant]
463 public const int PHYS_AXIS_ANGULAR_ALL = -3;
464 [ScriptConstant]
465 public const int PHYS_AXIS_LINEAR_X = 0;
466 [ScriptConstant]
467 public const int PHYS_AXIS_LINEAR_Y = 1;
468 [ScriptConstant]
469 public const int PHYS_AXIS_LINEAR_Z = 2;
470 [ScriptConstant]
471 public const int PHYS_AXIS_ANGULAR_X = 3;
472 [ScriptConstant]
473 public const int PHYS_AXIS_ANGULAR_Y = 4;
474 [ScriptConstant]
475 public const int PHYS_AXIS_ANGULAR_Z = 5;
476
477 // physChangeLinkParams(integer linkNum, [ PHYS_PARAM_*, value, PHYS_PARAM_*, value, ...])
478 [ScriptInvocation]
479 public int physChangeLinkParams(UUID hostID, UUID scriptID, int linkNum, object[] parms)
480 {
481 int ret = -1;
482 if (!Enabled) return ret;
483
484 PhysicsActor rootPhysActor;
485 PhysicsActor childPhysActor;
486
487 if (GetRootAndChildPhysActors(hostID, linkNum, out rootPhysActor, out childPhysActor))
488 {
489 object[] parms2 = AddToBeginningOfArray(rootPhysActor, childPhysActor, parms);
490 ret = MakeIntError(rootPhysActor.Extension(PhysFunctChangeLinkParams, parms2));
491 }
492
493 return ret;
494 }
495
496 private bool GetRootPhysActor(UUID hostID, out PhysicsActor rootPhysActor)
497 {
498 SceneObjectGroup containingGroup;
499 SceneObjectPart rootPart;
500 return GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor);
501 }
502
503 private bool GetRootPhysActor(UUID hostID, out SceneObjectGroup containingGroup, out SceneObjectPart rootPart, out PhysicsActor rootPhysActor)
504 {
505 bool ret = false;
506 rootPhysActor = null;
507 containingGroup = null;
508 rootPart = null;
509
510 SceneObjectPart requestingPart;
511
512 requestingPart = BaseScene.GetSceneObjectPart(hostID);
513 if (requestingPart != null)
514 {
515 // The type is is always on the root of a linkset.
516 containingGroup = requestingPart.ParentGroup;
517 if (containingGroup != null && !containingGroup.IsDeleted)
518 {
519 rootPart = containingGroup.RootPart;
520 if (rootPart != null)
521 {
522 rootPhysActor = rootPart.PhysActor;
523 if (rootPhysActor != null)
524 {
525 ret = true;
526 }
527 else
528 {
529 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
530 LogHeader, rootPart.Name, hostID);
531 }
532 }
533 else
534 {
535 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not exist. RequestingPartName={1}, hostID={2}",
536 LogHeader, requestingPart.Name, hostID);
537 }
538 }
539 else
540 {
541 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Containing group missing or deleted. hostID={1}", LogHeader, hostID);
542 }
543 }
544 else
545 {
546 m_log.WarnFormat("{0} GetRootAndChildPhysActors: cannot find script object in scene. hostID={1}", LogHeader, hostID);
547 }
548
549 return ret;
550 }
551
552 // Find the root and child PhysActors based on the linkNum.
553 // Return 'true' if both are found and returned.
554 private bool GetRootAndChildPhysActors(UUID hostID, int linkNum, out PhysicsActor rootPhysActor, out PhysicsActor childPhysActor)
555 {
556 bool ret = false;
557 rootPhysActor = null;
558 childPhysActor = null;
559
560 SceneObjectGroup containingGroup;
561 SceneObjectPart rootPart;
562
563 if (GetRootPhysActor(hostID, out containingGroup, out rootPart, out rootPhysActor))
564 {
565 SceneObjectPart linkPart = containingGroup.GetLinkNumPart(linkNum);
566 if (linkPart != null)
567 {
568 childPhysActor = linkPart.PhysActor;
569 if (childPhysActor != null)
570 {
571 ret = true;
572 }
573 else
574 {
575 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Link part has no physical actor. rootName={1}, hostID={2}, linknum={3}",
576 LogHeader, rootPart.Name, hostID, linkNum);
577 }
578 }
579 else
580 {
581 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Could not find linknum part. rootName={1}, hostID={2}, linknum={3}",
582 LogHeader, rootPart.Name, hostID, linkNum);
583 }
584 }
585 else
586 {
587 m_log.WarnFormat("{0} GetRootAndChildPhysActors: Root part does not have a physics actor. rootName={1}, hostID={2}",
588 LogHeader, rootPart.Name, hostID);
589 }
590
591 return ret;
592 }
593
594 // Return an array of objects with the passed object as the first object of a new array
595 private object[] AddToBeginningOfArray(object firstOne, object secondOne, object[] prevArray)
596 {
597 object[] newArray = new object[2 + prevArray.Length];
598 newArray[0] = firstOne;
599 newArray[1] = secondOne;
600 prevArray.CopyTo(newArray, 2);
601 return newArray;
602 }
603
604 // Extension() returns an object. Convert that object into the integer error we expect to return.
605 private int MakeIntError(object extensionRet)
606 {
607 int ret = -1;
608 if (extensionRet != null)
609 {
610 try
611 {
612 ret = (int)extensionRet;
613 }
614 catch
615 {
616 ret = -1;
617 }
618 }
619 return ret;
620 }
621 }
622}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
index 0d1db3b..698be39 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
@@ -1,6 +1,7 @@
1using System.Reflection; 1using System.Reflection;
2using System.Runtime.CompilerServices; 2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices; 3using System.Runtime.InteropServices;
4using Mono.Addins;
4 5
5// General Information about an assembly is controlled through the following 6// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information 7// set of attributes. Change these attribute values to modify the information
@@ -29,5 +30,7 @@ using System.Runtime.InteropServices;
29// Build Number 30// Build Number
30// Revision 31// Revision
31// 32//
32[assembly: AssemblyVersion("0.7.5.*")] 33[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 34
35[assembly: Addin("OpenSim.Region.PhysicsModule.BulletS", OpenSim.VersionInfo.VersionNumber)]
36[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
new file mode 100755
index 0000000..35eba29
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
@@ -0,0 +1,156 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.PhysicsModule.BulletS;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.PhysicsModule.BulletS.Tests
44{
45[TestFixture]
46public class BasicVehicles : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 BSPrim TestVehicle { get; set; }
53 Vector3 TestVehicleInitPosition { get; set; }
54 float simulationTimeStep = 0.089f;
55
56 [TestFixtureSetUp]
57 public void Init()
58 {
59 Dictionary<string, string> engineParams = new Dictionary<string, string>();
60 engineParams.Add("VehicleEnableAngularVerticalAttraction", "true");
61 engineParams.Add("VehicleAngularVerticalAttractionAlgorithm", "1");
62 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
63
64 PrimitiveBaseShape pbs = PrimitiveBaseShape.CreateSphere();
65 Vector3 pos = new Vector3(100.0f, 100.0f, 0f);
66 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 2f;
67 TestVehicleInitPosition = pos;
68 Vector3 size = new Vector3(1f, 1f, 1f);
69 pbs.Scale = size;
70 Quaternion rot = Quaternion.Identity;
71 bool isPhys = false;
72 uint localID = 123;
73
74 PhysicsScene.AddPrimShape("testPrim", pbs, pos, size, rot, isPhys, localID);
75 TestVehicle = (BSPrim)PhysicsScene.PhysObjects[localID];
76 // The actual prim shape creation happens at taint time
77 PhysicsScene.ProcessTaints();
78
79 }
80
81 [TestFixtureTearDown]
82 public void TearDown()
83 {
84 if (PhysicsScene != null)
85 {
86 // The Dispose() will also free any physical objects in the scene
87 PhysicsScene.Dispose();
88 PhysicsScene = null;
89 }
90 }
91
92 [TestCase(2f, 0.2f, 0.25f, 0.25f, 0.25f)]
93 [TestCase(2f, 0.2f, -0.25f, 0.25f, 0.25f)]
94 [TestCase(2f, 0.2f, 0.25f, -0.25f, 0.25f)]
95 [TestCase(2f, 0.2f, -0.25f, -0.25f, 0.25f)]
96 // [TestCase(2f, 0.2f, 0.785f, 0.0f, 0.25f) /*, "Leaning 45 degrees to the side" */]
97 // [TestCase(2f, 0.2f, 1.650f, 0.0f, 0.25f) /*, "Leaning more than 90 degrees to the side" */]
98 // [TestCase(2f, 0.2f, 2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped right" */]
99 // [TestCase(2f, 0.2f,-2.750f, 0.0f, 0.25f) /*, "Almost upside down, tipped left" */]
100 // [TestCase(2f, 0.2f, 0.0f, 0.785f, 0.25f) /*, "Tipped back 45 degrees" */]
101 // [TestCase(2f, 0.2f, 0.0f, 1.650f, 0.25f) /*, "Tipped back more than 90 degrees" */]
102 // [TestCase(2f, 0.2f, 0.0f, 2.750f, 0.25f) /*, "Almost upside down, tipped back" */]
103 // [TestCase(2f, 0.2f, 0.0f,-2.750f, 0.25f) /*, "Almost upside down, tipped forward" */]
104 public void AngularVerticalAttraction(float timeScale, float efficiency, float initRoll, float initPitch, float initYaw)
105 {
106 // Enough simulation steps to cover the timescale the operation should take
107 int simSteps = (int)(timeScale / simulationTimeStep) + 1;
108
109 // Tip the vehicle
110 Quaternion initOrientation = Quaternion.CreateFromEulers(initRoll, initPitch, initYaw);
111 TestVehicle.Orientation = initOrientation;
112
113 TestVehicle.Position = TestVehicleInitPosition;
114
115 // The vehicle controller is not enabled directly (by setting a vehicle type).
116 // Instead the appropriate values are set and calls are made just the parts of the
117 // controller we want to exercise. Stepping the physics engine then applies
118 // the actions of that one feature.
119 BSDynamics vehicleActor = TestVehicle.GetVehicleActor(true /* createIfNone */);
120 if (vehicleActor != null)
121 {
122 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, efficiency);
123 vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, timeScale);
124 // vehicleActor.enableAngularVerticalAttraction = true;
125
126 TestVehicle.IsPhysical = true;
127 PhysicsScene.ProcessTaints();
128
129 // Step the simulator a bunch of times and vertical attraction should orient the vehicle up
130 for (int ii = 0; ii < simSteps; ii++)
131 {
132 vehicleActor.ForgetKnownVehicleProperties();
133 vehicleActor.ComputeAngularVerticalAttraction();
134 vehicleActor.PushKnownChanged();
135
136 PhysicsScene.Simulate(simulationTimeStep);
137 }
138 }
139
140 TestVehicle.IsPhysical = false;
141 PhysicsScene.ProcessTaints();
142
143 // After these steps, the vehicle should be upright
144 /*
145 float finalRoll, finalPitch, finalYaw;
146 TestVehicle.Orientation.GetEulerAngles(out finalRoll, out finalPitch, out finalYaw);
147 Assert.That(finalRoll, Is.InRange(-0.01f, 0.01f));
148 Assert.That(finalPitch, Is.InRange(-0.01f, 0.01f));
149 Assert.That(finalYaw, Is.InRange(initYaw - 0.1f, initYaw + 0.1f));
150 */
151
152 Vector3 upPointer = Vector3.UnitZ * TestVehicle.Orientation;
153 Assert.That(upPointer.Z, Is.GreaterThan(0.99f));
154 }
155}
156} \ No newline at end of file
diff --git a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
index 415d808..0be1f4c 100644..100755
--- a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
@@ -1,57 +1,56 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
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 copyright 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
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 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 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 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.IO; 28using System;
29using System.Text; 29using System.Collections.Generic;
30using System.Xml; 30using System.Linq;
31using IOStream = System.IO.Stream; 31using System.Text;
32 32
33namespace OpenSim.Framework.Communications.XMPP 33using NUnit.Framework;
34{ 34using log4net;
35 public class XMPPWriter: XmlTextWriter 35
36 { 36using OpenSim.Tests.Common;
37 public XMPPWriter(TextWriter textWriter) : base(textWriter) 37
38 { 38namespace OpenSim.Region.PhysicsModule.BulletS.Tests
39 } 39{
40 40[TestFixture]
41 public XMPPWriter(IOStream stream) : this(stream, Util.UTF8) 41public class BulletSimTests : OpenSimTestCase
42 { 42{
43 } 43 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
44 44 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
45 public XMPPWriter(IOStream stream, Encoding enc) : base(stream, enc) 45
46 { 46 [TestFixtureSetUp]
47 } 47 public void Init()
48 48 {
49 public override void WriteStartDocument() 49 }
50 { 50
51 } 51 [TestFixtureTearDown]
52 52 public void TearDown()
53 public override void WriteStartDocument(bool standalone) 53 {
54 { 54 }
55 } 55}
56 } 56}
57}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
new file mode 100755
index 0000000..4eeea4d
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
@@ -0,0 +1,109 @@
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
28using System;
29using System.IO;
30using System.Collections.Generic;
31using System.Text;
32
33using Nini.Config;
34
35using OpenSim.Framework;
36using OpenSim.Region.PhysicsModules.SharedBase;
37using OpenSim.Region.PhysicsModules.Meshing;
38using OpenSim.Region.Framework.Interfaces;
39
40using OpenMetaverse;
41
42namespace OpenSim.Region.PhysicsModule.BulletS.Tests
43{
44// Utility functions for building up and tearing down the sample physics environments
45public static class BulletSimTestsUtil
46{
47 // 'engineName' is the Bullet engine to use. Either null (for unmanaged), "BulletUnmanaged" or "BulletXNA"
48 // 'params' is a set of keyValue pairs to set in the engine's configuration file (override defaults)
49 // May be 'null' if there are no overrides.
50 public static BSScene CreateBasicPhysicsEngine(Dictionary<string,string> paramOverrides)
51 {
52 IConfigSource openSimINI = new IniConfigSource();
53 IConfig startupConfig = openSimINI.AddConfig("Startup");
54 startupConfig.Set("physics", "BulletSim");
55 startupConfig.Set("meshing", "Meshmerizer");
56 startupConfig.Set("cacheSculptMaps", "false"); // meshmerizer shouldn't save maps
57
58 IConfig bulletSimConfig = openSimINI.AddConfig("BulletSim");
59 // If the caller cares, specify the bullet engine otherwise it will default to "BulletUnmanaged".
60 // bulletSimConfig.Set("BulletEngine", "BulletUnmanaged");
61 // bulletSimConfig.Set("BulletEngine", "BulletXNA");
62 bulletSimConfig.Set("MeshSculptedPrim", "false");
63 bulletSimConfig.Set("ForceSimplePrimMeshing", "true");
64 if (paramOverrides != null)
65 {
66 foreach (KeyValuePair<string, string> kvp in paramOverrides)
67 {
68 bulletSimConfig.Set(kvp.Key, kvp.Value);
69 }
70 }
71
72 // If a special directory exists, put detailed logging therein.
73 // This allows local testing/debugging without having to worry that the build engine will output logs.
74 if (Directory.Exists("physlogs"))
75 {
76 bulletSimConfig.Set("PhysicsLoggingDir","./physlogs");
77 bulletSimConfig.Set("PhysicsLoggingEnabled","True");
78 bulletSimConfig.Set("PhysicsLoggingDoFlush","True");
79 bulletSimConfig.Set("VehicleLoggingEnabled","True");
80 }
81
82 Vector3 regionExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
83
84 RegionInfo info = new RegionInfo();
85 info.RegionName = "BSTestRegion";
86 info.RegionSizeX = info.RegionSizeY = info.RegionSizeZ = Constants.RegionSize;
87 OpenSim.Region.Framework.Scenes.Scene scene = new OpenSim.Region.Framework.Scenes.Scene(info);
88
89 IMesher mesher = new OpenSim.Region.PhysicsModules.Meshing.Meshmerizer();
90 INonSharedRegionModule mod = mesher as INonSharedRegionModule;
91 mod.Initialise(openSimINI);
92 mod.AddRegion(scene);
93 mod.RegionLoaded(scene);
94
95 BSScene pScene = new BSScene();
96 mod = (pScene as INonSharedRegionModule);
97 mod.Initialise(openSimINI);
98 mod.AddRegion(scene);
99 mod.RegionLoaded(scene);
100
101 // Since the asset requestor is not initialized, any mesh or sculptie will be a cube.
102 // In the future, add a fake asset fetcher to get meshes and sculpts.
103 // bsScene.RequestAssetMethod = ???;
104
105 return pScene;
106 }
107
108}
109}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
new file mode 100644
index 0000000..c0cf19a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
@@ -0,0 +1,205 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using NUnit.Framework;
34using log4net;
35
36using OpenSim.Framework;
37using OpenSim.Region.PhysicsModule.BulletS;
38using OpenSim.Region.PhysicsModules.SharedBase;
39using OpenSim.Tests.Common;
40
41using OpenMetaverse;
42
43namespace OpenSim.Region.PhysicsModule.BulletS.Tests
44{
45[TestFixture]
46public class HullCreation : OpenSimTestCase
47{
48 // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1
49 // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1
50
51 BSScene PhysicsScene { get; set; }
52 Vector3 ObjectInitPosition;
53
54 [TestFixtureSetUp]
55 public void Init()
56 {
57
58 }
59
60 [TestFixtureTearDown]
61 public void TearDown()
62 {
63 if (PhysicsScene != null)
64 {
65 // The Dispose() will also free any physical objects in the scene
66 PhysicsScene.Dispose();
67 PhysicsScene = null;
68 }
69 }
70
71 [TestCase(7, 2, 5f, 5f, 32, 0f)] /* default hull parameters */
72 public void GeomHullConvexDecomp( int maxDepthSplit,
73 int maxDepthSplitForSimpleShapes,
74 float concavityThresholdPercent,
75 float volumeConservationThresholdPercent,
76 int maxVertices,
77 float maxSkinWidth)
78 {
79 // Setup the physics engine to use the C# version of convex decomp
80 Dictionary<string, string> engineParams = new Dictionary<string, string>();
81 engineParams.Add("MeshSculptedPrim", "true"); // ShouldMeshSculptedPrim
82 engineParams.Add("ForceSimplePrimMeshing", "false"); // ShouldForceSimplePrimMeshing
83 engineParams.Add("UseHullsForPhysicalObjects", "true"); // ShouldUseHullsForPhysicalObjects
84 engineParams.Add("ShouldRemoveZeroWidthTriangles", "true");
85 engineParams.Add("ShouldUseBulletHACD", "false");
86 engineParams.Add("ShouldUseSingleConvexHullForPrims", "true");
87 engineParams.Add("ShouldUseGImpactShapeForPrims", "false");
88 engineParams.Add("ShouldUseAssetHulls", "true");
89
90 engineParams.Add("CSHullMaxDepthSplit", maxDepthSplit.ToString());
91 engineParams.Add("CSHullMaxDepthSplitForSimpleShapes", maxDepthSplitForSimpleShapes.ToString());
92 engineParams.Add("CSHullConcavityThresholdPercent", concavityThresholdPercent.ToString());
93 engineParams.Add("CSHullVolumeConservationThresholdPercent", volumeConservationThresholdPercent.ToString());
94 engineParams.Add("CSHullMaxVertices", maxVertices.ToString());
95 engineParams.Add("CSHullMaxSkinWidth", maxSkinWidth.ToString());
96
97 PhysicsScene = BulletSimTestsUtil.CreateBasicPhysicsEngine(engineParams);
98
99 PrimitiveBaseShape pbs;
100 Vector3 pos;
101 Vector3 size;
102 Quaternion rot;
103 bool isPhys;
104
105 // Cylinder
106 pbs = PrimitiveBaseShape.CreateCylinder();
107 pos = new Vector3(100.0f, 100.0f, 0f);
108 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
109 ObjectInitPosition = pos;
110 size = new Vector3(2f, 2f, 2f);
111 pbs.Scale = size;
112 rot = Quaternion.Identity;
113 isPhys = true;
114 uint cylinderLocalID = 123;
115 PhysicsScene.AddPrimShape("testCylinder", pbs, pos, size, rot, isPhys, cylinderLocalID);
116 BSPrim primTypeCylinder = (BSPrim)PhysicsScene.PhysObjects[cylinderLocalID];
117
118 // Hollow Cylinder
119 pbs = PrimitiveBaseShape.CreateCylinder();
120 pbs.ProfileHollow = (ushort)(0.70f * 50000);
121 pos = new Vector3(110.0f, 110.0f, 0f);
122 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
123 ObjectInitPosition = pos;
124 size = new Vector3(2f, 2f, 2f);
125 pbs.Scale = size;
126 rot = Quaternion.Identity;
127 isPhys = true;
128 uint hollowCylinderLocalID = 124;
129 PhysicsScene.AddPrimShape("testHollowCylinder", pbs, pos, size, rot, isPhys, hollowCylinderLocalID);
130 BSPrim primTypeHollowCylinder = (BSPrim)PhysicsScene.PhysObjects[hollowCylinderLocalID];
131
132 // Torus
133 // ProfileCurve = Circle, PathCurve = Curve1
134 pbs = PrimitiveBaseShape.CreateSphere();
135 pbs.ProfileShape = (byte)ProfileShape.Circle;
136 pbs.PathCurve = (byte)Extrusion.Curve1;
137 pbs.PathScaleX = 100; // default hollow info as set in the viewer
138 pbs.PathScaleY = (int)(.25f / 0.01f) + 200;
139 pos = new Vector3(120.0f, 120.0f, 0f);
140 pos.Z = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos) + 10f;
141 ObjectInitPosition = pos;
142 size = new Vector3(2f, 4f, 4f);
143 pbs.Scale = size;
144 rot = Quaternion.Identity;
145 isPhys = true;
146 uint torusLocalID = 125;
147 PhysicsScene.AddPrimShape("testTorus", pbs, pos, size, rot, isPhys, torusLocalID);
148 BSPrim primTypeTorus = (BSPrim)PhysicsScene.PhysObjects[torusLocalID];
149
150 // The actual prim shape creation happens at taint time
151 PhysicsScene.ProcessTaints();
152
153 // Check out the created hull shapes and report their characteristics
154 ReportShapeGeom(primTypeCylinder);
155 ReportShapeGeom(primTypeHollowCylinder);
156 ReportShapeGeom(primTypeTorus);
157 }
158
159 [TestCase]
160 public void GeomHullBulletHACD()
161 {
162 // Cylinder
163 // Hollow Cylinder
164 // Torus
165 }
166
167 private void ReportShapeGeom(BSPrim prim)
168 {
169 if (prim != null)
170 {
171 if (prim.PhysShape.HasPhysicalShape)
172 {
173 BSShape physShape = prim.PhysShape;
174 string shapeType = physShape.GetType().ToString();
175 switch (shapeType)
176 {
177 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeNative":
178 BSShapeNative nShape = physShape as BSShapeNative;
179 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
180 break;
181 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeMesh":
182 BSShapeMesh mShape = physShape as BSShapeMesh;
183 prim.PhysScene.DetailLog("{0}, mesh, shapeInfo={1}", prim.Name, mShape.shapeInfo);
184 break;
185 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeHull":
186 // BSShapeHull hShape = physShape as BSShapeHull;
187 // prim.PhysScene.DetailLog("{0}, hull, shapeInfo={1}", prim.Name, hShape.shapeInfo);
188 break;
189 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeConvexHull":
190 BSShapeConvexHull chShape = physShape as BSShapeConvexHull;
191 prim.PhysScene.DetailLog("{0}, convexHull, shapeInfo={1}", prim.Name, chShape.shapeInfo);
192 break;
193 case "OpenSim.Region.Physics.BulletSPlugin.BSShapeCompound":
194 BSShapeCompound cShape = physShape as BSShapeCompound;
195 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
196 break;
197 default:
198 prim.PhysScene.DetailLog("{0}, type={1}", prim.Name, shapeType);
199 break;
200 }
201 }
202 }
203 }
204}
205} \ No newline at end of file