From 1d6b33bc2da3b312cff1d1802a73aacdf72b0385 Mon Sep 17 00:00:00 2001
From: Diva Canto
Date: Sun, 30 Aug 2015 20:06:53 -0700
Subject: Major renaming of Physics dlls / folders. No functional changes, just
renames.
---
.../PhysicsModules/BasicPhysics/AssemblyInfo.cs | 58 +
.../BasicPhysics/BasicPhysicsActor.cs | 303 ++
.../BasicPhysics/BasicPhysicsPlugin.cs | 64 +
.../BasicPhysics/BasicPhysicsPrim.cs | 316 ++
.../BasicPhysics/BasicPhysicsScene.cs | 210 +
.../Region/PhysicsModules/BulletS/BSAPIUnman.cs | 2120 ++++++++++
OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs | 2589 ++++++++++++
.../PhysicsModules/BulletS/BSActorAvatarMove.cs | 457 +++
.../Region/PhysicsModules/BulletS/BSActorHover.cs | 174 +
.../PhysicsModules/BulletS/BSActorLockAxis.cs | 219 +
.../PhysicsModules/BulletS/BSActorMoveToTarget.cs | 220 +
.../PhysicsModules/BulletS/BSActorSetForce.cs | 138 +
.../PhysicsModules/BulletS/BSActorSetTorque.cs | 139 +
OpenSim/Region/PhysicsModules/BulletS/BSActors.cs | 154 +
.../Region/PhysicsModules/BulletS/BSApiTemplate.cs | 763 ++++
.../Region/PhysicsModules/BulletS/BSCharacter.cs | 813 ++++
.../Region/PhysicsModules/BulletS/BSConstraint.cs | 144 +
.../PhysicsModules/BulletS/BSConstraint6Dof.cs | 180 +
.../BulletS/BSConstraintCollection.cs | 181 +
.../BulletS/BSConstraintConeTwist.cs | 54 +
.../PhysicsModules/BulletS/BSConstraintHinge.cs | 55 +
.../PhysicsModules/BulletS/BSConstraintSlider.cs | 55 +
.../PhysicsModules/BulletS/BSConstraintSpring.cs | 103 +
.../Region/PhysicsModules/BulletS/BSDynamics.cs | 1800 ++++++++
OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs | 503 +++
.../PhysicsModules/BulletS/BSLinksetCompound.cs | 477 +++
.../PhysicsModules/BulletS/BSLinksetConstraints.cs | 854 ++++
.../Region/PhysicsModules/BulletS/BSMaterials.cs | 203 +
OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs | 451 ++
OpenSim/Region/PhysicsModules/BulletS/BSParam.cs | 927 +++++
.../Region/PhysicsModules/BulletS/BSPhysObject.cs | 620 +++
OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs | 76 +
OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs | 1896 +++++++++
.../PhysicsModules/BulletS/BSPrimDisplaced.cs | 182 +
.../PhysicsModules/BulletS/BSPrimLinkable.cs | 350 ++
OpenSim/Region/PhysicsModules/BulletS/BSScene.cs | 1281 ++++++
.../PhysicsModules/BulletS/BSShapeCollection.cs | 425 ++
OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs | 1463 +++++++
.../PhysicsModules/BulletS/BSTerrainHeightmap.cs | 170 +
.../PhysicsModules/BulletS/BSTerrainManager.cs | 585 +++
.../Region/PhysicsModules/BulletS/BSTerrainMesh.cs | 441 ++
.../Region/PhysicsModules/BulletS/BulletSimData.cs | 277 ++
.../PhysicsModules/BulletS/BulletSimTODO.txt | 379 ++
.../BulletS/Properties/AssemblyInfo.cs | 33 +
.../PhysicsModules/BulletS/Tests/BasicVehicles.cs | 156 +
.../PhysicsModules/BulletS/Tests/BulletSimTests.cs | 56 +
.../BulletS/Tests/BulletSimTestsUtil.cs | 100 +
.../PhysicsModules/BulletS/Tests/HullCreation.cs | 205 +
.../ConvexDecompositionDotNet/CTri.cs | 341 ++
.../ConvexDecompositionDotNet/Concavity.cs | 233 ++
.../ConvexDecompositionDotNet/ConvexBuilder.cs | 411 ++
.../ConvexDecomposition.cs | 200 +
.../ConvexDecompositionDotNet/ConvexResult.cs | 74 +
.../ConvexDecompositionDotNet/HullClasses.cs | 171 +
.../ConvexDecompositionDotNet/HullTriangle.cs | 99 +
.../ConvexDecompositionDotNet/HullUtils.cs | 1868 +++++++++
.../ConvexDecompositionDotNet/LICENSE.txt | 28 +
.../ConvexDecompositionDotNet/Plane.cs | 99 +
.../ConvexDecompositionDotNet/PlaneTri.cs | 211 +
.../Properties/AssemblyInfo.cs | 36 +
.../ConvexDecompositionDotNet/Quaternion.cs | 209 +
.../ConvexDecompositionDotNet/README.txt | 7 +
.../ConvexDecompositionDotNet/SplitPlane.cs | 265 ++
.../ConvexDecompositionDotNet/VertexLookup.cs | 70 +
.../ConvexDecompositionDotNet/float2.cs | 70 +
.../ConvexDecompositionDotNet/float3.cs | 444 ++
.../ConvexDecompositionDotNet/float3x3.cs | 195 +
.../ConvexDecompositionDotNet/float4.cs | 170 +
.../ConvexDecompositionDotNet/float4x4.cs | 284 ++
.../ConvexDecompositionDotNet/int3.cs | 128 +
.../ConvexDecompositionDotNet/int4.cs | 66 +
.../Region/PhysicsModules/Meshing/HelperTypes.cs | 436 ++
OpenSim/Region/PhysicsModules/Meshing/Mesh.cs | 333 ++
.../Region/PhysicsModules/Meshing/Meshmerizer.cs | 971 +++++
.../Region/PhysicsModules/Meshing/PrimMesher.cs | 2324 +++++++++++
.../Meshing/Properties/AssemblyInfo.cs | 33 +
OpenSim/Region/PhysicsModules/Meshing/SculptMap.cs | 183 +
.../Region/PhysicsModules/Meshing/SculptMesh.cs | 646 +++
OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs | 58 +
OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs | 1409 +++++++
.../PhysicsModules/Ode/ODEDynamics.c_comments | 630 +++
OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs | 974 +++++
OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs | 3387 +++++++++++++++
.../PhysicsModules/Ode/ODERayCastRequestManager.cs | 434 ++
.../Region/PhysicsModules/Ode/OdePhysicsJoint.cs | 48 +
OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs | 90 +
OpenSim/Region/PhysicsModules/Ode/OdeScene.cs | 4319 ++++++++++++++++++++
.../PhysicsModules/Ode/Tests/ODETestClass.cs | 128 +
OpenSim/Region/PhysicsModules/Ode/drawstuff.cs | 98 +
OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs | 58 +
OpenSim/Region/PhysicsModules/POS/POSCharacter.cs | 341 ++
OpenSim/Region/PhysicsModules/POS/POSPlugin.cs | 64 +
OpenSim/Region/PhysicsModules/POS/POSPrim.cs | 336 ++
OpenSim/Region/PhysicsModules/POS/POSScene.cs | 273 ++
.../PhysicsModules/SharedBase/AssemblyInfo.cs | 58 +
.../PhysicsModules/SharedBase/CollisionLocker.cs | 73 +
.../Region/PhysicsModules/SharedBase/IMesher.cs | 71 +
.../SharedBase/IPhysicsParameters.cs | 73 +
.../PhysicsModules/SharedBase/NullPhysicsScene.cs | 122 +
.../PhysicsModules/SharedBase/PhysicsActor.cs | 584 +++
.../PhysicsModules/SharedBase/PhysicsJoint.cs | 55 +
.../SharedBase/PhysicsPluginManager.cs | 242 ++
.../PhysicsModules/SharedBase/PhysicsScene.cs | 361 ++
.../PhysicsModules/SharedBase/PhysicsSensor.cs | 78 +
.../PhysicsModules/SharedBase/PhysicsVector.cs | 186 +
.../PhysicsModules/SharedBase/VehicleConstants.cs | 121 +
.../Region/PhysicsModules/SharedBase/ZeroMesher.cs | 83 +
107 files changed, 48778 insertions(+)
create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs
create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
create mode 100644 OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/BulletSimTODO.txt
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/Properties/AssemblyInfo.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BasicVehicles.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs
create mode 100755 OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTestsUtil.cs
create mode 100644 OpenSim/Region/PhysicsModules/BulletS/Tests/HullCreation.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/CTri.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Concavity.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexBuilder.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexDecomposition.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/ConvexResult.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullClasses.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullTriangle.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/LICENSE.txt
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Plane.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/PlaneTri.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Properties/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/Quaternion.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/README.txt
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/SplitPlane.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/VertexLookup.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float2.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float3x3.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/float4x4.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int3.cs
create mode 100644 OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/int4.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/HelperTypes.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Mesh.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Meshmerizer.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/PrimMesher.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/Properties/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/SculptMap.cs
create mode 100644 OpenSim/Region/PhysicsModules/Meshing/SculptMesh.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODECharacter.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEDynamics.c_comments
create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEDynamics.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODEPrim.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/ODERayCastRequestManager.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/OdePhysicsJoint.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/OdePlugin.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/OdeScene.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/Tests/ODETestClass.cs
create mode 100644 OpenSim/Region/PhysicsModules/Ode/drawstuff.cs
create mode 100644 OpenSim/Region/PhysicsModules/POS/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/POS/POSCharacter.cs
create mode 100644 OpenSim/Region/PhysicsModules/POS/POSPlugin.cs
create mode 100644 OpenSim/Region/PhysicsModules/POS/POSPrim.cs
create mode 100644 OpenSim/Region/PhysicsModules/POS/POSScene.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/AssemblyInfo.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/CollisionLocker.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/IMesher.cs
create mode 100755 OpenSim/Region/PhysicsModules/SharedBase/IPhysicsParameters.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/NullPhysicsScene.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsActor.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsJoint.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsPluginManager.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsScene.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsSensor.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/PhysicsVector.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/VehicleConstants.cs
create mode 100644 OpenSim/Region/PhysicsModules/SharedBase/ZeroMesher.cs
(limited to 'OpenSim/Region/PhysicsModules')
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs
new file mode 100644
index 0000000..7d054dd
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// Information about this assembly is defined by the following
+// attributes.
+//
+// change them to the information which is associated with the assembly
+// you compile.
+
+[assembly : AssemblyTitle("BasicPhysicsPlugin")]
+[assembly : AssemblyDescription("")]
+[assembly : AssemblyConfiguration("")]
+[assembly : AssemblyCompany("http://opensimulator.org")]
+[assembly : AssemblyProduct("BasicPhysicsPlugin")]
+[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
+[assembly : AssemblyTrademark("")]
+[assembly : AssemblyCulture("")]
+
+// This sets the default COM visibility of types in the assembly to invisible.
+// If you need to expose a type to COM, use [ComVisible(true)] on that type.
+
+[assembly : ComVisible(false)]
+
+// The assembly version has following format :
+//
+// Major.Minor.Build.Revision
+//
+// You can specify all values by your own or you can build default build and revision
+// numbers with the '*' character (the default):
+
+[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
new file mode 100644
index 0000000..43fba7b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsActor.cs
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using Nini.Config;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BasicPhysicsPlugin
+{
+ public class BasicActor : PhysicsActor
+ {
+ public BasicActor(Vector3 size)
+ {
+ Size = size;
+ }
+
+ public override int PhysicsActorType
+ {
+ get { return (int) ActorTypes.Agent; }
+ set { return; }
+ }
+
+ public override Vector3 RotationalVelocity { get; set; }
+
+ public override bool SetAlwaysRun
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override uint LocalID
+ {
+ set { return; }
+ }
+
+ public override bool Grabbed
+ {
+ set { return; }
+ }
+
+ public override bool Selected
+ {
+ set { return; }
+ }
+
+ public override float Buoyancy
+ {
+ get { return 0f; }
+ set { return; }
+ }
+
+ public override bool FloatOnWater
+ {
+ set { return; }
+ }
+
+ public override bool IsPhysical
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool ThrottleUpdates
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool Flying { get; set; }
+
+ public override bool IsColliding { get; set; }
+
+ public override bool CollidingGround
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool CollidingObj
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool Stopped
+ {
+ get { return false; }
+ }
+
+ public override Vector3 Position { get; set; }
+
+ public override Vector3 Size { get; set; }
+
+ public override PrimitiveBaseShape Shape
+ {
+ set { return; }
+ }
+
+ public override float Mass
+ {
+ get { return 0f; }
+ }
+
+ public override Vector3 Force
+ {
+ get { return Vector3.Zero; }
+ set { return; }
+ }
+
+ public override int VehicleType
+ {
+ get { return 0; }
+ set { return; }
+ }
+
+ public override void VehicleFloatParam(int param, float value)
+ {
+
+ }
+
+ public override void VehicleVectorParam(int param, Vector3 value)
+ {
+
+ }
+
+ public override void VehicleRotationParam(int param, Quaternion rotation)
+ {
+
+ }
+
+ public override void VehicleFlags(int param, bool remove)
+ {
+
+ }
+
+ public override void SetVolumeDetect(int param)
+ {
+
+ }
+
+ public override Vector3 CenterOfMass
+ {
+ get { return Vector3.Zero; }
+ }
+
+ public override Vector3 GeometricCenter
+ {
+ get { return Vector3.Zero; }
+ }
+
+ public override Vector3 Velocity { get; set; }
+
+ public override Vector3 Torque
+ {
+ get { return Vector3.Zero; }
+ set { return; }
+ }
+
+ public override float CollisionScore
+ {
+ get { return 0f; }
+ set { }
+ }
+
+ public override Quaternion Orientation
+ {
+ get { return Quaternion.Identity; }
+ set { }
+ }
+
+ public override Vector3 Acceleration { get; set; }
+
+ public override bool Kinematic
+ {
+ get { return true; }
+ set { }
+ }
+
+ public override void link(PhysicsActor obj)
+ {
+ }
+
+ public override void delink()
+ {
+ }
+
+ public override void LockAngularMotion(Vector3 axis)
+ {
+ }
+
+ public override void AddForce(Vector3 force, bool pushforce)
+ {
+ }
+
+ public override void AddAngularForce(Vector3 force, bool pushforce)
+ {
+ }
+
+ public override void SetMomentum(Vector3 momentum)
+ {
+ }
+
+ public override void CrossingFailure()
+ {
+ }
+
+ public override Vector3 PIDTarget
+ {
+ set { return; }
+ }
+
+ public override bool PIDActive
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override float PIDTau
+ {
+ set { return; }
+ }
+
+ public override float PIDHoverHeight
+ {
+ set { return; }
+ }
+
+ public override bool PIDHoverActive
+ {
+ set { return; }
+ }
+
+ public override PIDHoverType PIDHoverType
+ {
+ set { return; }
+ }
+
+ public override float PIDHoverTau
+ {
+ set { return; }
+ }
+
+ public override Quaternion APIDTarget
+ {
+ set { return; }
+ }
+
+ public override bool APIDActive
+ {
+ set { return; }
+ }
+
+ public override float APIDStrength
+ {
+ set { return; }
+ }
+
+ public override float APIDDamping
+ {
+ set { return; }
+ }
+
+ public override void SubscribeEvents(int ms)
+ {
+ }
+
+ public override void UnSubscribeEvents()
+ {
+ }
+
+ public override bool SubscribedEvents()
+ {
+ return false;
+ }
+ }
+}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs
new file mode 100644
index 0000000..373c7e0
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPlugin.cs
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using Nini.Config;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BasicPhysicsPlugin
+{
+ ///
+ /// Effectively a physics plugin that simulates no physics at all.
+ ///
+ public class BasicPhysicsPlugin : IPhysicsPlugin
+ {
+ public BasicPhysicsPlugin()
+ {
+ }
+
+ public bool Init()
+ {
+ return true;
+ }
+
+ public PhysicsScene GetScene(string sceneIdentifier)
+ {
+ return new BasicScene(GetName(), sceneIdentifier);
+ }
+
+ public string GetName()
+ {
+ return ("basicphysics");
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
new file mode 100644
index 0000000..dfe4c19
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsPrim.cs
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using Nini.Config;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BasicPhysicsPlugin
+{
+ public class BasicPhysicsPrim : PhysicsActor
+ {
+ private Vector3 _size;
+// private PrimitiveBaseShape _shape;
+
+ public BasicPhysicsPrim(
+ string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape)
+ {
+ Name = name;
+ LocalID = localId;
+ Position = position;
+ Size = size;
+ Orientation = orientation;
+ Shape = shape;
+ }
+
+ public override int PhysicsActorType
+ {
+ get { return (int) ActorTypes.Agent; }
+ set { return; }
+ }
+
+ public override Vector3 RotationalVelocity { get; set; }
+
+ public override bool SetAlwaysRun
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override uint LocalID
+ {
+ set { return; }
+ }
+
+ public override bool Grabbed
+ {
+ set { return; }
+ }
+
+ public override bool Selected
+ {
+ set { return; }
+ }
+
+ public override float Buoyancy
+ {
+ get { return 0f; }
+ set { return; }
+ }
+
+ public override bool FloatOnWater
+ {
+ set { return; }
+ }
+
+ public override bool IsPhysical
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool ThrottleUpdates
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool Flying { get; set; }
+
+ public override bool IsColliding { get; set; }
+
+ public override bool CollidingGround
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool CollidingObj
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override bool Stopped
+ {
+ get { return false; }
+ }
+
+ public override Vector3 Position { get; set; }
+
+ public override Vector3 Size
+ {
+ get { return _size; }
+ set {
+ _size = value;
+ _size.Z = _size.Z / 2.0f;
+ }
+ }
+
+ public override PrimitiveBaseShape Shape
+ {
+// set { _shape = value; }
+ set {}
+ }
+
+ public override float Mass
+ {
+ get { return 0f; }
+ }
+
+ public override Vector3 Force
+ {
+ get { return Vector3.Zero; }
+ set { return; }
+ }
+
+ public override int VehicleType
+ {
+ get { return 0; }
+ set { return; }
+ }
+
+ public override void VehicleFloatParam(int param, float value)
+ {
+
+ }
+
+ public override void VehicleVectorParam(int param, Vector3 value)
+ {
+
+ }
+
+ public override void VehicleRotationParam(int param, Quaternion rotation)
+ {
+
+ }
+
+ public override void VehicleFlags(int param, bool remove)
+ {
+
+ }
+
+ public override void SetVolumeDetect(int param)
+ {
+
+ }
+
+ public override Vector3 CenterOfMass
+ {
+ get { return Vector3.Zero; }
+ }
+
+ public override Vector3 GeometricCenter
+ {
+ get { return Vector3.Zero; }
+ }
+
+ public override Vector3 Velocity { get; set; }
+
+ public override Vector3 Torque
+ {
+ get { return Vector3.Zero; }
+ set { return; }
+ }
+
+ public override float CollisionScore
+ {
+ get { return 0f; }
+ set { }
+ }
+
+ public override Quaternion Orientation { get; set; }
+
+ public override Vector3 Acceleration { get; set; }
+
+ public override bool Kinematic
+ {
+ get { return true; }
+ set { }
+ }
+
+ public override void link(PhysicsActor obj)
+ {
+ }
+
+ public override void delink()
+ {
+ }
+
+ public override void LockAngularMotion(Vector3 axis)
+ {
+ }
+
+ public override void AddForce(Vector3 force, bool pushforce)
+ {
+ }
+
+ public override void AddAngularForce(Vector3 force, bool pushforce)
+ {
+ }
+
+ public override void SetMomentum(Vector3 momentum)
+ {
+ }
+
+ public override void CrossingFailure()
+ {
+ }
+
+ public override Vector3 PIDTarget
+ {
+ set { return; }
+ }
+
+ public override bool PIDActive
+ {
+ get { return false; }
+ set { return; }
+ }
+
+ public override float PIDTau
+ {
+ set { return; }
+ }
+
+ public override float PIDHoverHeight
+ {
+ set { return; }
+ }
+
+ public override bool PIDHoverActive
+ {
+ set { return; }
+ }
+
+ public override PIDHoverType PIDHoverType
+ {
+ set { return; }
+ }
+
+ public override float PIDHoverTau
+ {
+ set { return; }
+ }
+
+ public override Quaternion APIDTarget
+ {
+ set { return; }
+ }
+
+ public override bool APIDActive
+ {
+ set { return; }
+ }
+
+ public override float APIDStrength
+ {
+ set { return; }
+ }
+
+ public override float APIDDamping
+ {
+ set { return; }
+ }
+
+ public override void SubscribeEvents(int ms)
+ {
+ }
+
+ public override void UnSubscribeEvents()
+ {
+ }
+
+ public override bool SubscribedEvents()
+ {
+ return false;
+ }
+ }
+}
diff --git a/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
new file mode 100644
index 0000000..06a205e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BasicPhysics/BasicPhysicsScene.cs
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using Nini.Config;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BasicPhysicsPlugin
+{
+ ///
+ /// This is an incomplete extremely basic physics implementation
+ ///
+ ///
+ /// Not useful for anything at the moment apart from some regression testing in other components where some form
+ /// of physics plugin is needed.
+ ///
+ public class BasicScene : PhysicsScene
+ {
+ private List _actors = new List();
+ private List _prims = new List();
+ private float[] _heightMap;
+ private Vector3 m_regionExtent;
+
+ //protected internal string sceneIdentifier;
+
+ public BasicScene(string engineType, string _sceneIdentifier)
+ {
+ EngineType = engineType;
+ Name = EngineType + "/" + _sceneIdentifier;
+ //sceneIdentifier = _sceneIdentifier;
+ }
+
+ public override void Initialise(IMesher meshmerizer, IConfigSource config)
+ {
+ throw new Exception("Should not be called.");
+ }
+
+ public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
+ {
+ m_regionExtent = regionExtent;
+ }
+
+ public override void Dispose() {}
+
+ public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
+ Vector3 size, Quaternion rotation, bool isPhysical, uint localid)
+ {
+ BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs);
+ prim.IsPhysical = isPhysical;
+
+ _prims.Add(prim);
+
+ return prim;
+ }
+
+ public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
+ {
+ BasicActor act = new BasicActor(size);
+ act.Position = position;
+ act.Velocity = velocity;
+ act.Flying = isFlying;
+ _actors.Add(act);
+ return act;
+ }
+
+ public override void RemovePrim(PhysicsActor actor)
+ {
+ BasicPhysicsPrim prim = (BasicPhysicsPrim)actor;
+ if (_prims.Contains(prim))
+ _prims.Remove(prim);
+ }
+
+ public override void RemoveAvatar(PhysicsActor actor)
+ {
+ BasicActor act = (BasicActor)actor;
+ if (_actors.Contains(act))
+ _actors.Remove(act);
+ }
+
+ public override void AddPhysicsActorTaint(PhysicsActor prim)
+ {
+ }
+
+ public override float Simulate(float timeStep)
+ {
+// Console.WriteLine("Simulating");
+
+ float fps = 0;
+ for (int i = 0; i < _actors.Count; ++i)
+ {
+ BasicActor actor = _actors[i];
+ Vector3 actorPosition = actor.Position;
+ Vector3 actorVelocity = actor.Velocity;
+
+// Console.WriteLine(
+// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
+
+ actorPosition.X += actor.Velocity.X * timeStep;
+ actorPosition.Y += actor.Velocity.Y * timeStep;
+
+ if (actor.Position.Y < 0)
+ {
+ actorPosition.Y = 0.1F;
+ }
+ else if (actor.Position.Y >= m_regionExtent.Y)
+ {
+ actorPosition.Y = (m_regionExtent.Y - 0.1f);
+ }
+
+ if (actor.Position.X < 0)
+ {
+ actorPosition.X = 0.1F;
+ }
+ else if (actor.Position.X >= m_regionExtent.X)
+ {
+ actorPosition.X = (m_regionExtent.X - 0.1f);
+ }
+
+ float terrainHeight = 0;
+ if (_heightMap != null)
+ terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X];
+
+ float height = terrainHeight + actor.Size.Z;
+// Console.WriteLine("height {0}, actorPosition {1}", height, actorPosition);
+
+ if (actor.Flying)
+ {
+ if (actor.Position.Z + (actor.Velocity.Z * timeStep) < terrainHeight + 2)
+ {
+ actorPosition.Z = height;
+ actorVelocity.Z = 0;
+ actor.IsColliding = true;
+ }
+ else
+ {
+ actorPosition.Z += actor.Velocity.Z * timeStep;
+ actor.IsColliding = false;
+ }
+ }
+ else
+ {
+ actorPosition.Z = height;
+ actorVelocity.Z = 0;
+ actor.IsColliding = true;
+ }
+
+ actor.Position = actorPosition;
+ actor.Velocity = actorVelocity;
+ }
+
+ return fps;
+ }
+
+ public override void GetResults()
+ {
+ }
+
+ public override bool IsThreaded
+ {
+ get { return (false); // for now we won't be multithreaded
+ }
+ }
+
+ public override void SetTerrain(float[] heightMap)
+ {
+ _heightMap = heightMap;
+ }
+
+ public override void DeleteTerrain()
+ {
+ }
+
+ public override void SetWaterLevel(float baseheight)
+ {
+ }
+
+ public override Dictionary GetTopColliders()
+ {
+ Dictionary returncolliders = new Dictionary();
+ return returncolliders;
+ }
+ }
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
new file mode 100755
index 0000000..3bd81d4
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs
@@ -0,0 +1,2120 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+using OpenSim.Framework;
+
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSAPIUnman : BSAPITemplate
+{
+
+private sealed class BulletWorldUnman : BulletWorld
+{
+ public IntPtr ptr;
+ public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx)
+ : base(id, physScene)
+ {
+ ptr = xx;
+ }
+}
+
+private sealed class BulletBodyUnman : BulletBody
+{
+ public IntPtr ptr;
+ public BulletBodyUnman(uint id, IntPtr xx)
+ : base(id)
+ {
+ ptr = xx;
+ }
+ public override bool HasPhysicalBody
+ {
+ get { return ptr != IntPtr.Zero; }
+ }
+ public override void Clear()
+ {
+ ptr = IntPtr.Zero;
+ }
+ public override string AddrString
+ {
+ get { return ptr.ToString("X"); }
+ }
+}
+
+private sealed class BulletShapeUnman : BulletShape
+{
+ public IntPtr ptr;
+ public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
+ : base()
+ {
+ ptr = xx;
+ shapeType = typ;
+ }
+ public override bool HasPhysicalShape
+ {
+ get { return ptr != IntPtr.Zero; }
+ }
+ public override void Clear()
+ {
+ ptr = IntPtr.Zero;
+ }
+ public override BulletShape Clone()
+ {
+ return new BulletShapeUnman(ptr, shapeType);
+ }
+ public override bool ReferenceSame(BulletShape other)
+ {
+ BulletShapeUnman otheru = other as BulletShapeUnman;
+ return (otheru != null) && (this.ptr == otheru.ptr);
+
+ }
+ public override string AddrString
+ {
+ get { return ptr.ToString("X"); }
+ }
+}
+private sealed class BulletConstraintUnman : BulletConstraint
+{
+ public BulletConstraintUnman(IntPtr xx) : base()
+ {
+ ptr = xx;
+ }
+ public IntPtr ptr;
+
+ public override void Clear()
+ {
+ ptr = IntPtr.Zero;
+ }
+ public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
+
+ // Used for log messages for a unique display of the memory/object allocated to this instance
+ public override string AddrString
+ {
+ get { return ptr.ToString("X"); }
+ }
+}
+
+// We pin the memory passed between the managed and unmanaged code.
+GCHandle m_paramsHandle;
+private GCHandle m_collisionArrayPinnedHandle;
+private GCHandle m_updateArrayPinnedHandle;
+
+// Handle to the callback used by the unmanaged code to call into the managed code.
+// Used for debug logging.
+// Need to store the handle in a persistant variable so it won't be freed.
+private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle;
+
+private BSScene PhysicsScene { get; set; }
+
+public override string BulletEngineName { get { return "BulletUnmanaged"; } }
+public override string BulletEngineVersion { get; protected set; }
+
+public BSAPIUnman(string paramName, BSScene physScene)
+{
+ PhysicsScene = physScene;
+
+ // Do something fancy with the paramName to get the right DLL implementation
+ // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc.
+ if (Util.IsWindows())
+ Util.LoadArchSpecificWindowsDll("BulletSim.dll");
+ // If not Windows, loading is performed by the
+ // Mono loader as specified in
+ // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
+}
+
+// Initialization and simulation
+public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
+ int maxCollisions, ref CollisionDesc[] collisionArray,
+ int maxUpdates, ref EntityProperties[] updateArray
+ )
+{
+ // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code
+ m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned);
+ m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned);
+ m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned);
+
+ // If Debug logging level, enable logging from the unmanaged code
+ m_DebugLogCallbackHandle = null;
+ if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled)
+ {
+ BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
+ if (PhysicsScene.PhysicsLogging.Enabled)
+ // The handle is saved in a variable to make sure it doesn't get freed after this call
+ m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog);
+ else
+ m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger);
+ }
+
+ // Get the version of the DLL
+ // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
+ // BulletEngineVersion = BulletSimAPI.GetVersion2();
+ BulletEngineVersion = "";
+
+ // Call the unmanaged code with the buffers and other information
+ return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(),
+ maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
+ maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
+ m_DebugLogCallbackHandle));
+
+}
+
+// Called directly from unmanaged code so don't do much
+private void BulletLogger(string msg)
+{
+ BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg);
+}
+
+// Called directly from unmanaged code so don't do much
+private void BulletLoggerPhysLog(string msg)
+{
+ PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg);
+}
+
+public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
+ out int updatedEntityCount, out int collidersCount)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
+}
+
+public override void Shutdown(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.Shutdown2(worldu.ptr);
+
+ if (m_paramsHandle.IsAllocated)
+ {
+ m_paramsHandle.Free();
+ }
+ if (m_collisionArrayPinnedHandle.IsAllocated)
+ {
+ m_collisionArrayPinnedHandle.Free();
+ }
+ if (m_updateArrayPinnedHandle.IsAllocated)
+ {
+ m_updateArrayPinnedHandle.Free();
+ }
+}
+
+public override bool PushUpdate(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.PushUpdate2(bodyu.ptr);
+}
+
+public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
+}
+
+// =====================================================================================
+// Mesh, hull, shape and body creation helper routines
+public override BulletShape CreateMeshShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
+ BSPhysicsShapeType.SHAPE_MESH);
+}
+
+public override BulletShape CreateGImpactShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
+ BSPhysicsShapeType.SHAPE_GIMPACT);
+}
+
+public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
+ BSPhysicsShapeType.SHAPE_HULL);
+}
+
+public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms),
+ BSPhysicsShapeType.SHAPE_HULL);
+}
+
+public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
+ BSPhysicsShapeType.SHAPE_CONVEXHULL);
+}
+
+public override BulletShape CreateConvexHullShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
+ BSPhysicsShapeType.SHAPE_CONVEXHULL);
+}
+
+public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
+}
+
+public override bool IsNativeShape(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ if (shapeu != null && shapeu.HasPhysicalShape)
+ return BSAPICPP.IsNativeShape2(shapeu.ptr);
+ return false;
+}
+
+public override void SetShapeCollisionMargin(BulletShape shape, float margin)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ if (shapeu != null && shapeu.HasPhysicalShape)
+ BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin);
+}
+
+public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
+ BSPhysicsShapeType.SHAPE_CAPSULE);
+}
+
+public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return new BulletShapeUnman(
+ BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
+ BSPhysicsShapeType.SHAPE_COMPOUND);
+
+}
+
+public override int GetNumberOfCompoundChildren(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ if (shapeu != null && shapeu.HasPhysicalShape)
+ return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
+ return 0;
+}
+
+public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
+ BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
+}
+
+public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
+}
+
+public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
+}
+
+public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
+ BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
+}
+
+public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb)
+{
+ BulletShapeUnman shapeu = pShape as BulletShapeUnman;
+ BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb);
+}
+
+public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
+}
+
+public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
+ return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType);
+}
+
+public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
+}
+
+public override CollisionObjectTypes GetBodyType(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
+}
+
+public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
+}
+
+public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
+}
+
+public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
+}
+
+public override void DestroyObject(BulletWorld world, BulletBody obj)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
+}
+
+// =====================================================================================
+// Terrain creation and helper routines
+public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
+{
+ return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
+}
+
+public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
+ float scaleFactor, float collisionMargin)
+{
+ return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
+ BSPhysicsShapeType.SHAPE_TERRAIN);
+}
+
+// =====================================================================================
+// Constraint creation and helper routines
+public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
+ frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 joinPoint,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
+ joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr,
+ frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
+ frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 pivotinA, Vector3 pivotinB,
+ Vector3 axisInA, Vector3 axisInB,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
+ pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
+ frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
+ frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 axisInA, Vector3 axisInB,
+ float ratio, bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB,
+ ratio, disableCollisionsBetweenLinkedBodies));
+}
+
+public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 pivotInA, Vector3 pivotInB,
+ bool disableCollisionsBetweenLinkedBodies)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
+ BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB,
+ disableCollisionsBetweenLinkedBodies));
+}
+
+public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
+}
+
+public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
+}
+
+public override bool SetFrames(BulletConstraint constrain,
+ Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
+}
+
+public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
+}
+
+public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
+}
+
+public override bool UseFrameOffset(BulletConstraint constrain, float enable)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
+}
+
+public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
+}
+
+public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
+}
+
+public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation);
+}
+
+public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse);
+}
+
+public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint);
+}
+
+public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss);
+}
+
+public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping);
+}
+
+public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val);
+}
+
+public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val);
+}
+
+public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse);
+}
+
+public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val);
+}
+
+public override bool CalculateTransforms(BulletConstraint constrain)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.CalculateTransforms2(constrainu.ptr);
+}
+
+public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
+}
+
+public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
+}
+
+// =====================================================================================
+// btCollisionWorld entries
+public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
+}
+
+public override void UpdateAabbs(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.UpdateAabbs2(worldu.ptr);
+}
+
+public override bool GetForceUpdateAllAabbs(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
+}
+
+public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
+}
+
+// =====================================================================================
+// btDynamicsWorld entries
+public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+
+ // Bullet resets several variables when an object is added to the world.
+ // Gravity is reset to world default depending on the static/dynamic
+ // type. Of course, the collision flags in the broadphase proxy are initialized to default.
+ Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
+
+ bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
+
+ if (ret)
+ {
+ BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
+ obj.ApplyCollisionMask(world.physicsScene);
+ }
+ return ret;
+}
+
+public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
+}
+
+public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr);
+}
+
+public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
+}
+
+public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
+}
+// =====================================================================================
+// btCollisionObject entries
+public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
+}
+
+public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
+}
+
+public override bool HasAnisotripicFriction(BulletConstraint constrain)
+{
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
+}
+
+public override void SetContactProcessingThreshold(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
+}
+
+public override float GetContactProcessingThreshold(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
+}
+
+public override bool IsStaticObject(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.IsStaticObject2(bodyu.ptr);
+}
+
+public override bool IsKinematicObject(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.IsKinematicObject2(bodyu.ptr);
+}
+
+public override bool IsStaticOrKinematicObject(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
+}
+
+public override bool HasContactResponse(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.HasContactResponse2(bodyu.ptr);
+}
+
+public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ if (worldu != null && bodyu != null)
+ {
+ // Special case to allow the caller to zero out the reference to any physical shape
+ if (shapeu != null)
+ BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
+ else
+ BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
+ }
+}
+
+public override BulletShape GetCollisionShape(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
+}
+
+public override int GetActivationState(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetActivationState2(bodyu.ptr);
+}
+
+public override void SetActivationState(BulletBody obj, int state)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetActivationState2(bodyu.ptr, state);
+}
+
+public override void SetDeactivationTime(BulletBody obj, float dtime)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
+}
+
+public override float GetDeactivationTime(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
+}
+
+public override void ForceActivationState(BulletBody obj, ActivationState state)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ForceActivationState2(bodyu.ptr, state);
+}
+
+public override void Activate(BulletBody obj, bool forceActivation)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.Activate2(bodyu.ptr, forceActivation);
+}
+
+public override bool IsActive(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.IsActive2(bodyu.ptr);
+}
+
+public override void SetRestitution(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetRestitution2(bodyu.ptr, val);
+}
+
+public override float GetRestitution(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetRestitution2(bodyu.ptr);
+}
+
+public override void SetFriction(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetFriction2(bodyu.ptr, val);
+}
+
+public override float GetFriction(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetFriction2(bodyu.ptr);
+}
+
+public override Vector3 GetPosition(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetPosition2(bodyu.ptr);
+}
+
+public override Quaternion GetOrientation(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetOrientation2(bodyu.ptr);
+}
+
+public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
+}
+
+ /*
+public override IntPtr GetBroadphaseHandle(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
+}
+
+public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
+}
+ */
+
+public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
+}
+
+public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
+}
+
+public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
+}
+
+public override float GetHitFraction(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetHitFraction2(bodyu.ptr);
+}
+
+public override void SetHitFraction(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetHitFraction2(bodyu.ptr, val);
+}
+
+public override CollisionFlags GetCollisionFlags(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
+}
+
+public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
+}
+
+public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
+}
+
+public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
+}
+
+public override float GetCcdMotionThreshold(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
+}
+
+
+public override void SetCcdMotionThreshold(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
+}
+
+public override float GetCcdSweptSphereRadius(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
+}
+
+public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
+}
+
+public override IntPtr GetUserPointer(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetUserPointer2(bodyu.ptr);
+}
+
+public override void SetUserPointer(BulletBody obj, IntPtr val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetUserPointer2(bodyu.ptr, val);
+}
+
+// =====================================================================================
+// btRigidBody entries
+public override void ApplyGravity(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyGravity2(bodyu.ptr);
+}
+
+public override void SetGravity(BulletBody obj, Vector3 val)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetGravity2(bodyu.ptr, val);
+}
+
+public override Vector3 GetGravity(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetGravity2(bodyu.ptr);
+}
+
+public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
+}
+
+public override void SetLinearDamping(BulletBody obj, float lin_damping)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
+}
+
+public override void SetAngularDamping(BulletBody obj, float ang_damping)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
+}
+
+public override float GetLinearDamping(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetLinearDamping2(bodyu.ptr);
+}
+
+public override float GetAngularDamping(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetAngularDamping2(bodyu.ptr);
+}
+
+public override float GetLinearSleepingThreshold(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
+}
+
+public override void ApplyDamping(BulletBody obj, float timeStep)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
+}
+
+public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
+}
+
+public override Vector3 GetLinearFactor(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetLinearFactor2(bodyu.ptr);
+}
+
+public override void SetLinearFactor(BulletBody obj, Vector3 factor)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
+}
+
+public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
+}
+
+// Add a force to the object as if its mass is one.
+// Deep down in Bullet: m_totalForce += force*m_linearFactor;
+public override void ApplyCentralForce(BulletBody obj, Vector3 force)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
+}
+
+// Set the force being applied to the object as if its mass is one.
+public override void SetObjectForce(BulletBody obj, Vector3 force)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetObjectForce2(bodyu.ptr, force);
+}
+
+public override Vector3 GetTotalForce(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetTotalForce2(bodyu.ptr);
+}
+
+public override Vector3 GetTotalTorque(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetTotalTorque2(bodyu.ptr);
+}
+
+public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
+}
+
+public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
+}
+
+public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
+}
+
+// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
+public override void ApplyTorque(BulletBody obj, Vector3 torque)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
+}
+
+// Apply force at the given point. Will add torque to the object.
+// Deep down in Bullet: applyCentralForce(force);
+// applyTorque(rel_pos.cross(force*m_linearFactor));
+public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
+}
+
+// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
+// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
+public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
+}
+
+// Apply impulse to the object's torque. Force is scaled by object's mass.
+// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
+public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
+}
+
+// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
+// Deep down in Bullet: applyCentralImpulse(impulse);
+// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
+public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
+}
+
+public override void ClearForces(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ClearForces2(bodyu.ptr);
+}
+
+public override void ClearAllForces(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.ClearAllForces2(bodyu.ptr);
+}
+
+public override void UpdateInertiaTensor(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
+}
+
+public override Vector3 GetLinearVelocity(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
+}
+
+public override Vector3 GetAngularVelocity(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
+}
+
+public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
+}
+
+public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
+}
+
+public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
+}
+
+public override void Translate(BulletBody obj, Vector3 trans)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.Translate2(bodyu.ptr, trans);
+}
+
+public override void UpdateDeactivation(BulletBody obj, float timeStep)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
+}
+
+public override bool WantsSleeping(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.WantsSleeping2(bodyu.ptr);
+}
+
+public override void SetAngularFactor(BulletBody obj, float factor)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
+}
+
+public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
+}
+
+public override Vector3 GetAngularFactor(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetAngularFactor2(bodyu.ptr);
+}
+
+public override bool IsInWorld(BulletWorld world, BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.IsInWorld2(bodyu.ptr);
+}
+
+public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
+}
+
+public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
+}
+
+public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
+}
+
+public override int GetNumConstraintRefs(BulletBody obj)
+{
+ BulletBodyUnman bodyu = obj as BulletBodyUnman;
+ return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
+}
+
+public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
+{
+ BulletBodyUnman bodyu = body as BulletBodyUnman;
+ return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
+}
+
+// =====================================================================================
+// btCollisionShape entries
+
+public override float GetAngularMotionDisc(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
+}
+
+public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
+}
+
+public override bool IsPolyhedral(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsPolyhedral2(shapeu.ptr);
+}
+
+public override bool IsConvex2d(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsConvex2d2(shapeu.ptr);
+}
+
+public override bool IsConvex(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsConvex2(shapeu.ptr);
+}
+
+public override bool IsNonMoving(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsNonMoving2(shapeu.ptr);
+}
+
+public override bool IsConcave(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsConcave2(shapeu.ptr);
+}
+
+public override bool IsCompound(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsCompound2(shapeu.ptr);
+}
+
+public override bool IsSoftBody(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsSoftBody2(shapeu.ptr);
+}
+
+public override bool IsInfinite(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.IsInfinite2(shapeu.ptr);
+}
+
+public override void SetLocalScaling(BulletShape shape, Vector3 scale)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
+}
+
+public override Vector3 GetLocalScaling(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.GetLocalScaling2(shapeu.ptr);
+}
+
+public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
+}
+
+public override int GetShapeType(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.GetShapeType2(shapeu.ptr);
+}
+
+public override void SetMargin(BulletShape shape, float val)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ BSAPICPP.SetMargin2(shapeu.ptr, val);
+}
+
+public override float GetMargin(BulletShape shape)
+{
+ BulletShapeUnman shapeu = shape as BulletShapeUnman;
+ return BSAPICPP.GetMargin2(shapeu.ptr);
+}
+
+// =====================================================================================
+// Debugging
+public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
+ BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
+}
+
+public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
+ BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
+}
+
+public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
+ BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
+}
+
+public override void DumpActivationInfo(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.DumpActivationInfo2(worldu.ptr);
+}
+
+public override void DumpAllInfo(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.DumpAllInfo2(worldu.ptr);
+}
+
+public override void DumpPhysicsStatistics(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
+}
+public override void ResetBroadphasePool(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.ResetBroadphasePool(worldu.ptr);
+}
+public override void ResetConstraintSolver(BulletWorld world)
+{
+ BulletWorldUnman worldu = world as BulletWorldUnman;
+ BSAPICPP.ResetConstraintSolver(worldu.ptr);
+}
+
+// =====================================================================================
+// =====================================================================================
+// =====================================================================================
+// =====================================================================================
+// =====================================================================================
+// The actual interface to the unmanaged code
+static class BSAPICPP
+{
+// ===============================================================================
+// Link back to the managed code for outputting log messages
+[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
+
+// ===============================================================================
+// Initialization and simulation
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
+ int maxCollisions, IntPtr collisionArray,
+ int maxUpdates, IntPtr updateArray,
+ DebugLogCallback logRoutine);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
+ out int updatedEntityCount, out int collidersCount);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void Shutdown2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool PushUpdate2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
+
+// =====================================================================================
+// Mesh, hull, shape and body creation helper routines
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateMeshShape2(IntPtr world,
+ int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
+ int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateGImpactShape2(IntPtr world,
+ int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
+ int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateHullShape2(IntPtr world,
+ int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateConvexHullShape2(IntPtr world,
+ int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
+ int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsNativeShape2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int GetBodyType2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
+
+// =====================================================================================
+// Terrain creation and helper routines
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
+ [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
+ float scaleFactor, float collisionMargin);
+
+// =====================================================================================
+// Constraint creation and helper routines
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 joinPoint,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 pivotinA, Vector3 pivotinB,
+ Vector3 axisInA, Vector3 axisInB,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 axisInA, Vector3 axisInB,
+ float ratio, bool disableCollisionsBetweenLinkedBodies);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
+ Vector3 pivotInA, Vector3 pivotInB,
+ bool disableCollisionsBetweenLinkedBodies);
+
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetFrames2(IntPtr constrain,
+ Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool CalculateTransforms2(IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
+
+// =====================================================================================
+// btCollisionWorld entries
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void UpdateAabbs2(IntPtr world);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
+
+// =====================================================================================
+// btDynamicsWorld entries
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
+// =====================================================================================
+// btCollisionObject entries
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool HasAnisotripicFriction2(IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetContactProcessingThreshold2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsStaticObject2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsKinematicObject2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool HasContactResponse2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetCollisionShape2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int GetActivationState2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetActivationState2(IntPtr obj, int state);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetDeactivationTime2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void Activate2(IntPtr obj, bool forceActivation);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsActive2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetRestitution2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetRestitution2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetFriction2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetFriction2(IntPtr obj);
+
+ /* Haven't defined the type 'Transform'
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Transform GetWorldTransform2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void setWorldTransform2(IntPtr obj, Transform trans);
+ */
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetPosition2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Quaternion GetOrientation2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
+
+ /*
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
+ */
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetHitFraction2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetHitFraction2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetCcdMotionThreshold2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetUserPointer2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
+
+// =====================================================================================
+// btRigidBody entries
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyGravity2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetGravity2(IntPtr obj, Vector3 val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetGravity2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetLinearDamping2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetAngularDamping2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetLinearSleepingThreshold2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetAngularSleepingThreshold2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyDamping2(IntPtr obj, float timeStep);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetLinearFactor2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
+
+ /*
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
+ */
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
+
+// Add a force to the object as if its mass is one.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
+
+// Set the force being applied to the object as if its mass is one.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetTotalForce2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetTotalTorque2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
+
+// Apply force at the given point. Will add torque to the object.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
+
+// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
+
+// Apply impulse to the object's torque. Force is scaled by object's mass.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
+
+// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ClearForces2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ClearAllForces2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void UpdateInertiaTensor2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
+
+ /*
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
+ */
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetLinearVelocity2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetAngularVelocity2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void Translate2(IntPtr obj, Vector3 trans);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool WantsSleeping2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetAngularFactor2(IntPtr obj, float factor);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetAngularFactor2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsInWorld2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int GetNumConstraintRefs2(IntPtr obj);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
+
+// =====================================================================================
+// btCollisionShape entries
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetAngularMotionDisc2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsPolyhedral2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsConvex2d2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsConvex2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsNonMoving2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsConcave2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsCompound2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsSoftBody2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern bool IsInfinite2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 GetLocalScaling2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern int GetShapeType2(IntPtr shape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetMargin2(IntPtr shape, float val);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern float GetMargin2(IntPtr shape);
+
+// =====================================================================================
+// Debugging
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpActivationInfo2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpAllInfo2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpPhysicsStatistics2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ResetBroadphasePool(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void ResetConstraintSolver(IntPtr sim);
+
+}
+
+}
+
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
new file mode 100755
index 0000000..741f8db
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs
@@ -0,0 +1,2589 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+using OpenSim.Framework;
+
+using OpenMetaverse;
+
+using BulletXNA;
+using BulletXNA.LinearMath;
+using BulletXNA.BulletCollision;
+using BulletXNA.BulletDynamics;
+using BulletXNA.BulletCollision.CollisionDispatch;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSAPIXNA : BSAPITemplate
+{
+private sealed class BulletWorldXNA : BulletWorld
+{
+ public DiscreteDynamicsWorld world;
+ public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
+ : base(id, physScene)
+ {
+ world = xx;
+ }
+}
+
+private sealed class BulletBodyXNA : BulletBody
+{
+ public CollisionObject body;
+ public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
+
+ public BulletBodyXNA(uint id, CollisionObject xx)
+ : base(id)
+ {
+ body = xx;
+ }
+ public override bool HasPhysicalBody
+ {
+ get { return body != null; }
+ }
+ public override void Clear()
+ {
+ body = null;
+ }
+ public override string AddrString
+ {
+ get { return "XNARigidBody"; }
+ }
+}
+
+private sealed class BulletShapeXNA : BulletShape
+{
+ public CollisionShape shape;
+ public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
+ : base()
+ {
+ shape = xx;
+ shapeType = typ;
+ }
+ public override bool HasPhysicalShape
+ {
+ get { return shape != null; }
+ }
+ public override void Clear()
+ {
+ shape = null;
+ }
+ public override BulletShape Clone()
+ {
+ return new BulletShapeXNA(shape, shapeType);
+ }
+ public override bool ReferenceSame(BulletShape other)
+ {
+ BulletShapeXNA otheru = other as BulletShapeXNA;
+ return (otheru != null) && (this.shape == otheru.shape);
+
+ }
+ public override string AddrString
+ {
+ get { return "XNACollisionShape"; }
+ }
+}
+private sealed class BulletConstraintXNA : BulletConstraint
+{
+ public TypedConstraint constrain;
+ public BulletConstraintXNA(TypedConstraint xx) : base()
+ {
+ constrain = xx;
+ }
+
+ public override void Clear()
+ {
+ constrain = null;
+ }
+ public override bool HasPhysicalConstraint { get { return constrain != null; } }
+
+ // Used for log messages for a unique display of the memory/object allocated to this instance
+ public override string AddrString
+ {
+ get { return "XNAConstraint"; }
+ }
+}
+ internal int m_maxCollisions;
+ internal CollisionDesc[] UpdatedCollisions;
+ internal int LastCollisionDesc = 0;
+ internal int m_maxUpdatesPerFrame;
+ internal int LastEntityProperty = 0;
+
+ internal EntityProperties[] UpdatedObjects;
+ internal Dictionary specialCollisionObjects;
+
+ private static int m_collisionsThisFrame;
+ private BSScene PhysicsScene { get; set; }
+
+ public override string BulletEngineName { get { return "BulletXNA"; } }
+ public override string BulletEngineVersion { get; protected set; }
+
+ public BSAPIXNA(string paramName, BSScene physScene)
+ {
+ PhysicsScene = physScene;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
+ CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
+ if (body != null)
+ world.RemoveRigidBody(body);
+ else if (collisionObject != null)
+ world.RemoveCollisionObject(collisionObject);
+ else
+ return false;
+ return true;
+ }
+
+ public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
+ CollisionObject collisionObject = ((BulletBodyXNA)pBody).body;
+ if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null)
+ {
+ world.RemoveCollisionObject(collisionObject);
+ world.AddCollisionObject(collisionObject);
+ }
+ return true;
+ }
+
+ public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
+ world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects);
+
+ return true;
+
+ }
+
+ public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
+ world.RemoveConstraint(constraint);
+ return true;
+ }
+
+ public override void SetRestitution(BulletBody pCollisionObject, float pRestitution)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.SetRestitution(pRestitution);
+ }
+
+ public override int GetShapeType(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return (int)shape.GetShapeType();
+ }
+ public override void SetMargin(BulletShape pShape, float pMargin)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ shape.SetMargin(pMargin);
+ }
+
+ public override float GetMargin(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.GetMargin();
+ }
+
+ public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
+ shape.SetLocalScaling(ref vec);
+
+ }
+
+ public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.SetContactProcessingThreshold(contactprocessingthreshold);
+ }
+
+ public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.SetCcdMotionThreshold(pccdMotionThreashold);
+ }
+
+ public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
+ }
+
+ public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
+ }
+
+ public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
+ existingcollisionFlags |= pcollisionFlags;
+ collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
+ return (CollisionFlags) (uint) existingcollisionFlags;
+ }
+
+ public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject cbody = (pBody as BulletBodyXNA).body;
+ RigidBody rbody = cbody as RigidBody;
+
+ // Bullet resets several variables when an object is added to the world. In particular,
+ // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
+ // type. Of course, the collision flags in the broadphase proxy are initialized to default.
+ IndexedMatrix origPos = cbody.GetWorldTransform();
+ if (rbody != null)
+ {
+ IndexedVector3 origGrav = rbody.GetGravity();
+ world.AddRigidBody(rbody);
+ rbody.SetGravity(origGrav);
+ }
+ else
+ {
+ world.AddCollisionObject(cbody);
+ }
+ cbody.SetWorldTransform(origPos);
+
+ pBody.ApplyCollisionMask(pWorld.physicsScene);
+
+ //if (body.GetBroadphaseHandle() != null)
+ // world.UpdateSingleAabb(body);
+ return true;
+ }
+
+ public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
+ }
+
+ public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ world.UpdateSingleAabb(collisionObject);
+ }
+
+ public override void UpdateAabbs(BulletWorld pWorld) {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ world.UpdateAabbs();
+ }
+ public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ return world.GetForceUpdateAllAabbs();
+
+ }
+ public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ world.SetForceUpdateAllAabbs(pForce);
+ }
+
+ public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
+ collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
+ if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0)
+ return false;
+ return true;
+ }
+
+ public override void ClearAllForces(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
+ collisionObject.SetInterpolationLinearVelocity(ref zeroVector);
+ collisionObject.SetInterpolationAngularVelocity(ref zeroVector);
+ IndexedMatrix bodytransform = collisionObject.GetWorldTransform();
+
+ collisionObject.SetInterpolationWorldTransform(ref bodytransform);
+
+ if (collisionObject is RigidBody)
+ {
+ RigidBody rigidbody = collisionObject as RigidBody;
+ rigidbody.SetLinearVelocity(zeroVector);
+ rigidbody.SetAngularVelocity(zeroVector);
+ rigidbody.ClearForces();
+ }
+ }
+
+ public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
+ collisionObject.SetInterpolationAngularVelocity(ref vec);
+ }
+
+ public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
+ body.SetAngularVelocity(ref vec);
+ }
+ public override Vector3 GetTotalForce(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetTotalForce();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override Vector3 GetTotalTorque(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetTotalTorque();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
+ body.SetInvInertiaDiagLocal(ref iv3);
+ }
+ public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
+ IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
+ body.ApplyForce(ref forceiv3, ref posiv3);
+ }
+ public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
+ IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
+ body.ApplyImpulse(ref impiv3, ref posiv3);
+ }
+
+ public override void ClearForces(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.ClearForces();
+ }
+
+ public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
+ IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
+ _orientation.W);
+ IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
+ mat._origin = vposition;
+ collisionObject.SetWorldTransform(mat);
+
+ }
+
+ public override Vector3 GetPosition(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin;
+ return new Vector3(pos.X, pos.Y, pos.Z);
+ }
+
+ public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ IndexedVector3 inertia = IndexedVector3.Zero;
+ shape.CalculateLocalInertia(pphysMass, out inertia);
+ return new Vector3(inertia.X, inertia.Y, inertia.Z);
+ }
+
+ public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ if (body != null) // Can't set mass props on collision object.
+ {
+ IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
+ body.SetMassProps(pphysMass, inertia);
+ }
+ }
+
+
+ public override void SetObjectForce(BulletBody pBody, Vector3 _force)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
+ body.SetTotalForce(ref force);
+ }
+
+ public override void SetFriction(BulletBody pCollisionObject, float _currentFriction)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ collisionObject.SetFriction(_currentFriction);
+ }
+
+ public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
+ body.SetLinearVelocity(velocity);
+ }
+
+ public override void Activate(BulletBody pCollisionObject, bool pforceactivation)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.Activate(pforceactivation);
+
+ }
+
+ public override Quaternion GetOrientation(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation();
+ return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
+ }
+
+ public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags();
+ existingcollisionFlags &= ~pcollisionFlags;
+ collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
+ return (CollisionFlags)(uint)existingcollisionFlags;
+ }
+
+ public override float GetCcdMotionThreshold(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.GetCcdSquareMotionThreshold();
+ }
+
+ public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.GetCcdSweptSphereRadius();
+
+ }
+
+ public override IntPtr GetUserPointer(BulletBody pCollisionObject)
+ {
+ CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
+ return (IntPtr)shape.GetUserPointer();
+ }
+
+ public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val)
+ {
+ CollisionObject shape = (pCollisionObject as BulletBodyXNA).body;
+ shape.SetUserPointer(val);
+ }
+
+ public override void SetGravity(BulletBody pBody, Vector3 pGravity)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ if (body != null) // Can't set collisionobject.set gravity
+ {
+ IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
+ body.SetGravity(gravity);
+ }
+ }
+
+ public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain;
+ world.RemoveConstraint(constraint);
+ return true;
+ }
+
+ public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
+ IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
+ constraint.SetLinearLowerLimit(lowlimit);
+ constraint.SetLinearUpperLimit(highlimit);
+ return true;
+ }
+
+ public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
+ IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
+ constraint.SetAngularLowerLimit(lowlimit);
+ constraint.SetAngularUpperLimit(highlimit);
+ return true;
+ }
+
+ public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ constraint.SetOverrideNumSolverIterations((int)cnt);
+ }
+
+ public override bool CalculateTransforms(BulletConstraint pConstraint)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ constraint.CalculateTransforms();
+ return true;
+ }
+
+ public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ constraint.SetEnabled((p_2 == 0) ? false : true);
+ }
+
+
+ public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
+ bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
+
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
+ IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
+ IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
+ frame2._origin = frame1v;
+
+ Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
+ puseLinearReferenceFrameA);
+ consttr.CalculateTransforms();
+ world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
+
+ return new BulletConstraintXNA(consttr);
+ }
+
+ public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1,
+ Vector3 pframe1, Quaternion pframe1rot,
+ bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB);
+ consttr.CalculateTransforms();
+ world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
+
+ return new BulletConstraintXNA(consttr);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
+ IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
+ IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
+
+ IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
+ IndexedMatrix mat = IndexedMatrix.Identity;
+ mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
+ frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
+ frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
+
+ Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
+ consttr.CalculateTransforms();
+ world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
+
+ return new BulletConstraintXNA(consttr);
+ }
+ //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
+ public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
+ IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
+ IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
+ frame2._origin = frame2v;
+ constraint.SetFrames(ref frame1, ref frame2);
+ return true;
+ }
+
+ public override Vector3 GetLinearVelocity(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetLinearVelocity();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override Vector3 GetAngularVelocity(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetAngularVelocity();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
+ IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+ public override void Translate(BulletBody pCollisionObject, Vector3 trans)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z));
+ }
+ public override void UpdateDeactivation(BulletBody pBody, float timeStep)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.UpdateDeactivation(timeStep);
+ }
+
+ public override bool WantsSleeping(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return body.WantsSleeping();
+ }
+
+ public override void SetAngularFactor(BulletBody pBody, float factor)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.SetAngularFactor(factor);
+ }
+
+ public override Vector3 GetAngularFactor(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 iv3 = body.GetAngularFactor();
+ return new Vector3(iv3.X, iv3.Y, iv3.Z);
+ }
+
+ public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ return world.IsInWorld(collisionObject);
+ }
+
+ public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
+ body.AddConstraintRef(constrain);
+ }
+
+ public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain;
+ body.RemoveConstraintRef(constrain);
+ }
+
+ public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return new BulletConstraintXNA(body.GetConstraintRef(index));
+ }
+
+ public override int GetNumConstraintRefs(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return body.GetNumConstraintRefs();
+ }
+
+ public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
+ collisionObject.SetInterpolationLinearVelocity(ref velocity);
+ }
+
+ public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ constraint.SetUseFrameOffset((onOff == 0) ? false : true);
+ return true;
+ }
+ //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
+ public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
+ {
+ Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ constraint.SetBreakingImpulseThreshold(threshold);
+ return true;
+ }
+ public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation)
+ {
+ HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint;
+ if (softness == HINGE_NOT_SPECIFIED)
+ constraint.SetLimit(low, high);
+ else
+ constraint.SetLimit(low, high, softness, bias, relaxation);
+ return true;
+ }
+ public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse)
+ {
+ Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
+ constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true));
+ return true;
+ }
+
+ public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint)
+ {
+ Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
+ if (index == SPRING_NOT_SPECIFIED)
+ {
+ constraint.SetEquilibriumPoint();
+ }
+ else
+ {
+ if (equilibriumPoint == SPRING_NOT_SPECIFIED)
+ constraint.SetEquilibriumPoint(index);
+ else
+ constraint.SetEquilibriumPoint(index, equilibriumPoint);
+ }
+ return true;
+ }
+
+ public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness)
+ {
+ Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
+ constraint.SetStiffness(index, stiffness);
+ return true;
+ }
+
+ public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping)
+ {
+ Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint;
+ constraint.SetDamping(index, damping);
+ return true;
+ }
+
+ public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val)
+ {
+ SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
+ switch (lowerUpper)
+ {
+ case SLIDER_LOWER_LIMIT:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR:
+ constraint.SetLowerLinLimit(val);
+ break;
+ case SLIDER_ANGULAR:
+ constraint.SetLowerAngLimit(val);
+ break;
+ }
+ break;
+ case SLIDER_UPPER_LIMIT:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR:
+ constraint.SetUpperLinLimit(val);
+ break;
+ case SLIDER_ANGULAR:
+ constraint.SetUpperAngLimit(val);
+ break;
+ }
+ break;
+ }
+ return true;
+ }
+ public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val)
+ {
+ SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
+ switch (softRestDamp)
+ {
+ case SLIDER_SET_SOFTNESS:
+ switch (dirLimOrtho)
+ {
+ case SLIDER_SET_DIRECTION:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break;
+ }
+ break;
+ case SLIDER_SET_LIMIT:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break;
+ }
+ break;
+ case SLIDER_SET_ORTHO:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break;
+ }
+ break;
+ }
+ break;
+ case SLIDER_SET_RESTITUTION:
+ switch (dirLimOrtho)
+ {
+ case SLIDER_SET_DIRECTION:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break;
+ }
+ break;
+ case SLIDER_SET_LIMIT:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break;
+ }
+ break;
+ case SLIDER_SET_ORTHO:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break;
+ }
+ break;
+ }
+ break;
+ case SLIDER_SET_DAMPING:
+ switch (dirLimOrtho)
+ {
+ case SLIDER_SET_DIRECTION:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break;
+ }
+ break;
+ case SLIDER_SET_LIMIT:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break;
+ }
+ break;
+ case SLIDER_SET_ORTHO:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break;
+ case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break;
+ }
+ break;
+ }
+ break;
+ }
+ return true;
+ }
+ public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse)
+ {
+ SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
+ switch (linAng)
+ {
+ case SLIDER_LINEAR:
+ constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true);
+ break;
+ case SLIDER_ANGULAR:
+ constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true);
+ break;
+ }
+ return true;
+ }
+ public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val)
+ {
+ SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint;
+ switch (forceVel)
+ {
+ case SLIDER_MOTOR_VELOCITY:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR:
+ constraint.SetTargetLinMotorVelocity(val);
+ break;
+ case SLIDER_ANGULAR:
+ constraint.SetTargetAngMotorVelocity(val);
+ break;
+ }
+ break;
+ case SLIDER_MAX_MOTOR_FORCE:
+ switch (linAng)
+ {
+ case SLIDER_LINEAR:
+ constraint.SetMaxLinMotorForce(val);
+ break;
+ case SLIDER_ANGULAR:
+ constraint.SetMaxAngMotorForce(val);
+ break;
+ }
+ break;
+ }
+ return true;
+ }
+
+ //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
+ public override void SetAngularDamping(BulletBody pBody, float angularDamping)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ float lineardamping = body.GetLinearDamping();
+ body.SetDamping(lineardamping, angularDamping);
+
+ }
+
+ public override void UpdateInertiaTensor(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ if (body != null) // can't update inertia tensor on CollisionObject
+ body.UpdateInertiaTensor();
+ }
+
+ public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
+ {
+ CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
+ shape.RecalculateLocalAabb();
+ }
+
+ //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
+ public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ uint flags = (uint)collisionObject.GetCollisionFlags();
+ return (CollisionFlags) flags;
+ }
+
+ public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.SetDamping(pLinear, pAngular);
+ }
+ //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
+ public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.SetDeactivationTime(pDeactivationTime);
+ }
+ //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
+ public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
+ }
+
+ public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ return (CollisionObjectTypes)(int) collisionObject.GetInternalType();
+ }
+
+ public override void ApplyGravity(BulletBody pBody)
+ {
+
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.ApplyGravity();
+ }
+
+ public override Vector3 GetGravity(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 gravity = body.GetGravity();
+ return new Vector3(gravity.X, gravity.Y, gravity.Z);
+ }
+
+ public override void SetLinearDamping(BulletBody pBody, float lin_damping)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ float angularDamping = body.GetAngularDamping();
+ body.SetDamping(lin_damping, angularDamping);
+ }
+
+ public override float GetLinearDamping(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return body.GetLinearDamping();
+ }
+
+ public override float GetAngularDamping(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return body.GetAngularDamping();
+ }
+
+ public override float GetLinearSleepingThreshold(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ return body.GetLinearSleepingThreshold();
+ }
+
+ public override void ApplyDamping(BulletBody pBody, float timeStep)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.ApplyDamping(timeStep);
+ }
+
+ public override Vector3 GetLinearFactor(BulletBody pBody)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 linearFactor = body.GetLinearFactor();
+ return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z);
+ }
+
+ public override void SetLinearFactor(BulletBody pBody, Vector3 factor)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z));
+ }
+
+ public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W);
+ IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat);
+ mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z);
+ body.SetCenterOfMassTransform( ref mat);
+ /* TODO: double check this */
+ }
+
+ //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
+ public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
+ body.ApplyCentralForce(ref fSum);
+ }
+ public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
+ body.ApplyCentralImpulse(ref fSum);
+ }
+ public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
+ body.ApplyTorque(ref fSum);
+ }
+ public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
+ {
+ RigidBody body = (pBody as BulletBodyXNA).rigidBody;
+ IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
+ body.ApplyTorqueImpulse(ref fSum);
+ }
+
+ public override void DestroyObject(BulletWorld pWorld, BulletBody pBody)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject co = (pBody as BulletBodyXNA).rigidBody;
+ RigidBody bo = co as RigidBody;
+ if (bo == null)
+ {
+
+ if (world.IsInWorld(co))
+ {
+ world.RemoveCollisionObject(co);
+ }
+ }
+ else
+ {
+
+ if (world.IsInWorld(bo))
+ {
+ world.RemoveRigidBody(bo);
+ }
+ }
+ if (co != null)
+ {
+ if (co.GetUserPointer() != null)
+ {
+ uint localId = (uint) co.GetUserPointer();
+ if (specialCollisionObjects.ContainsKey(localId))
+ {
+ specialCollisionObjects.Remove(localId);
+ }
+ }
+ }
+
+ }
+
+ public override void Shutdown(BulletWorld pWorld)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ world.Cleanup();
+ }
+
+ public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id)
+ {
+ CollisionShape shape1 = (pShape as BulletShapeXNA).shape;
+
+ // TODO: Turn this from a reference copy to a Value Copy.
+ BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType()));
+
+ return shape2;
+ }
+
+ public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape)
+ {
+ //TODO:
+ return false;
+ }
+ //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
+
+ public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
+ {
+ CollisionWorld world = (pWorld as BulletWorldXNA).world;
+ IndexedMatrix mat =
+ IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
+ pRawOrientation.Z, pRawOrientation.W));
+ mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ //UpdateSingleAabb(world, shape);
+ // TODO: Feed Update array into null
+ SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null);
+ RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero);
+ RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero)
+ {
+ m_mass = 0
+ };
+ /*
+ m_mass = mass;
+ m_motionState =motionState;
+ m_collisionShape = collisionShape;
+ m_localInertia = localInertia;
+ m_linearDamping = 0f;
+ m_angularDamping = 0f;
+ m_friction = 0.5f;
+ m_restitution = 0f;
+ m_linearSleepingThreshold = 0.8f;
+ m_angularSleepingThreshold = 1f;
+ m_additionalDamping = false;
+ m_additionalDampingFactor = 0.005f;
+ m_additionalLinearDampingThresholdSqr = 0.01f;
+ m_additionalAngularDampingThresholdSqr = 0.01f;
+ m_additionalAngularDampingFactor = 0.01f;
+ m_startWorldTransform = IndexedMatrix.Identity;
+ */
+ body.SetUserPointer(pLocalID);
+
+ return new BulletBodyXNA(pLocalID, body);
+ }
+
+
+ public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
+ {
+
+ IndexedMatrix mat =
+ IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
+ pRawOrientation.Z, pRawOrientation.W));
+ mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
+
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+
+ // TODO: Feed Update array into null
+ RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
+ body.SetWorldTransform(mat);
+ body.SetUserPointer(pLocalID);
+ return new BulletBodyXNA(pLocalID, body);
+ }
+ //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
+ public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
+ return (CollisionFlags)collisionObject.GetCollisionFlags();
+ }
+
+ public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain)
+ {
+
+ /* TODO */
+ return Vector3.Zero;
+ }
+ public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
+ public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
+ public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
+ public override bool IsStaticObject(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.IsStaticObject();
+
+ }
+ public override bool IsKinematicObject(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.IsKinematicObject();
+ }
+ public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.IsStaticOrKinematicObject();
+ }
+ public override bool HasContactResponse(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ return collisionObject.HasContactResponse();
+ }
+ public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
+ public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
+ public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
+ public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
+ public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
+ public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
+ public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
+ public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
+
+ //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
+ public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ collisionObject.SetHitFraction(pHitFraction);
+ }
+ //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
+ public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
+ CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
+ capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
+ capsuleShapeZ.SetLocalScaling(ref scale);
+
+ return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
+ }
+
+ public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
+ int maxCollisions, ref CollisionDesc[] collisionArray,
+ int maxUpdates, ref EntityProperties[] updateArray
+ )
+ {
+
+ UpdatedObjects = updateArray;
+ UpdatedCollisions = collisionArray;
+ /* TODO */
+ ConfigurationParameters[] configparms = new ConfigurationParameters[1];
+ configparms[0] = parms;
+ Vector3 worldExtent = maxPosition;
+ m_maxCollisions = maxCollisions;
+ m_maxUpdatesPerFrame = maxUpdates;
+ specialCollisionObjects = new Dictionary();
+
+ return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null));
+ }
+
+ private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent,
+ ConfigurationParameters[] o,
+ int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray,
+ int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray,
+ object mDebugLogCallbackHandle)
+ {
+ CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
+
+ p.angularDamping = BSParam.AngularDamping;
+ p.defaultFriction = o[0].defaultFriction;
+ p.defaultFriction = o[0].defaultFriction;
+ p.defaultDensity = o[0].defaultDensity;
+ p.defaultRestitution = o[0].defaultRestitution;
+ p.collisionMargin = o[0].collisionMargin;
+ p.gravity = o[0].gravity;
+
+ p.linearDamping = BSParam.LinearDamping;
+ p.angularDamping = BSParam.AngularDamping;
+ p.deactivationTime = BSParam.DeactivationTime;
+ p.linearSleepingThreshold = BSParam.LinearSleepingThreshold;
+ p.angularSleepingThreshold = BSParam.AngularSleepingThreshold;
+ p.ccdMotionThreshold = BSParam.CcdMotionThreshold;
+ p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius;
+ p.contactProcessingThreshold = BSParam.ContactProcessingThreshold;
+
+ p.terrainImplementation = BSParam.TerrainImplementation;
+ p.terrainFriction = BSParam.TerrainFriction;
+
+ p.terrainHitFraction = BSParam.TerrainHitFraction;
+ p.terrainRestitution = BSParam.TerrainRestitution;
+ p.terrainCollisionMargin = BSParam.TerrainCollisionMargin;
+
+ p.avatarFriction = BSParam.AvatarFriction;
+ p.avatarStandingFriction = BSParam.AvatarStandingFriction;
+ p.avatarDensity = BSParam.AvatarDensity;
+ p.avatarRestitution = BSParam.AvatarRestitution;
+ p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth;
+ p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth;
+ p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight;
+ p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold;
+
+ p.vehicleAngularDamping = BSParam.VehicleAngularDamping;
+
+ p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
+ p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
+ p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
+ p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
+ p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
+ p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
+ p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
+ p.numberOfSolverIterations = o[0].numberOfSolverIterations;
+
+ p.linksetImplementation = BSParam.LinksetImplementation;
+ p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset);
+ p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor);
+ p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
+ p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
+ p.linkConstraintERP = BSParam.LinkConstraintERP;
+ p.linkConstraintCFM = BSParam.LinkConstraintCFM;
+ p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations;
+ p.physicsLoggingFrames = o[0].physicsLoggingFrames;
+ DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
+
+ DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
+ CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
+
+
+ if (p.maxPersistantManifoldPoolSize > 0)
+ cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
+ if (p.shouldDisableContactPoolDynamicAllocation !=0)
+ m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
+ //if (p.maxCollisionAlgorithmPoolSize >0 )
+
+ DbvtBroadphase m_broadphase = new DbvtBroadphase();
+ //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
+ //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
+
+ //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
+ m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
+
+ SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
+
+ DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
+
+ world.LastCollisionDesc = 0;
+ world.LastEntityProperty = 0;
+
+ world.WorldSettings.Params = p;
+ world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
+ world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
+ if (p.shouldRandomizeSolverOrder != 0)
+ world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
+
+ world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
+ //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
+
+ if (p.shouldEnableFrictionCaching != 0)
+ world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
+
+ if (p.numberOfSolverIterations > 0)
+ world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
+
+
+ world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
+ world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
+ world.GetSolverInfo().m_globalCfm = 0.0f;
+ world.GetSolverInfo().m_tau = 0.6f;
+ world.GetSolverInfo().m_friction = 0.3f;
+ world.GetSolverInfo().m_maxErrorReduction = 20f;
+ world.GetSolverInfo().m_numIterations = 10;
+ world.GetSolverInfo().m_erp = 0.2f;
+ world.GetSolverInfo().m_erp2 = 0.1f;
+ world.GetSolverInfo().m_sor = 1.0f;
+ world.GetSolverInfo().m_splitImpulse = false;
+ world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
+ world.GetSolverInfo().m_linearSlop = 0.0f;
+ world.GetSolverInfo().m_warmstartingFactor = 0.85f;
+ world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
+ world.SetForceUpdateAllAabbs(true);
+
+ //BSParam.TerrainImplementation = 0;
+ world.SetGravity(new IndexedVector3(0,0,p.gravity));
+
+ // Turn off Pooling since globals and pooling are bad for threading.
+ BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false);
+ BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false);
+ BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false);
+ BulletGlobals.CastResultPool.SetPoolingEnabled(false);
+ BulletGlobals.SphereShapePool.SetPoolingEnabled(false);
+ BulletGlobals.DbvtNodePool.SetPoolingEnabled(false);
+ BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false);
+ BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false);
+ BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false);
+ BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false);
+ BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false);
+ BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false);
+ BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false);
+
+ BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false);
+ BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false);
+ BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false);
+ BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false);
+ BulletGlobals.GJKPool.SetPoolingEnabled(false);
+ BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false);
+ BulletGlobals.TriangleShapePool.SetPoolingEnabled(false);
+ BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false);
+ BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false);
+ BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false);
+ BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false);
+
+ return world;
+ }
+ //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
+ public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
+ {
+ Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint;
+ if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
+ {
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
+ }
+ if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
+ {
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
+ }
+ if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
+ {
+ constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
+ }
+ return true;
+ }
+
+ public override bool PushUpdate(BulletBody pCollisionObject)
+ {
+ bool ret = false;
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ RigidBody rb = collisionObject as RigidBody;
+ if (rb != null)
+ {
+ SimMotionState sms = rb.GetMotionState() as SimMotionState;
+ if (sms != null)
+ {
+ IndexedMatrix wt = IndexedMatrix.Identity;
+ sms.GetWorldTransform(out wt);
+ sms.SetWorldTransform(ref wt, true);
+ ret = true;
+ }
+ }
+ return ret;
+
+ }
+
+ public override float GetAngularMotionDisc(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.GetAngularMotionDisc();
+ }
+ public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.GetContactBreakingThreshold(defaultFactor);
+ }
+ public override bool IsCompound(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsCompound();
+ }
+ public override bool IsSoftBody(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsSoftBody();
+ }
+ public override bool IsPolyhedral(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsPolyhedral();
+ }
+ public override bool IsConvex2d(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsConvex2d();
+ }
+ public override bool IsConvex(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsConvex();
+ }
+ public override bool IsNonMoving(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsNonMoving();
+ }
+ public override bool IsConcave(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsConcave();
+ }
+ public override bool IsInfinite(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ return shape.IsInfinite();
+ }
+ public override bool IsNativeShape(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ bool ret;
+ switch (shape.GetShapeType())
+ {
+ case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
+ case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
+ case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
+ case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
+ ret = true;
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ return ret;
+ }
+
+ public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ shape.SetMargin(pMargin);
+ }
+
+ //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
+ public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ IndexedMatrix bodyTransform = new IndexedMatrix();
+ bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
+ bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
+ GhostObject gObj = new PairCachingGhostObject();
+ gObj.SetWorldTransform(bodyTransform);
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ gObj.SetCollisionShape(shape);
+ gObj.SetUserPointer(pLocalID);
+
+ if (specialCollisionObjects.ContainsKey(pLocalID))
+ specialCollisionObjects[pLocalID] = gObj;
+ else
+ specialCollisionObjects.Add(pLocalID, gObj);
+
+ // TODO: Add to Special CollisionObjects!
+ return new BulletBodyXNA(pLocalID, gObj);
+ }
+
+ public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body;
+ if (pShape == null)
+ {
+ collisionObject.SetCollisionShape(new EmptyShape());
+ }
+ else
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ collisionObject.SetCollisionShape(shape);
+ }
+ }
+ public override BulletShape GetCollisionShape(BulletBody pCollisionObject)
+ {
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ CollisionShape shape = collisionObject.GetCollisionShape();
+ return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
+ }
+
+ //(PhysicsScene.World.ptr, nativeShapeData)
+ public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionShape shape = null;
+ switch (pShapeData.Type)
+ {
+ case BSPhysicsShapeType.SHAPE_BOX:
+ shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
+ break;
+ case BSPhysicsShapeType.SHAPE_CONE:
+ shape = new ConeShapeZ(0.5f, 1.0f);
+ break;
+ case BSPhysicsShapeType.SHAPE_CYLINDER:
+ shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
+ break;
+ case BSPhysicsShapeType.SHAPE_SPHERE:
+ shape = new SphereShape(0.5f);
+ break;
+
+ }
+ if (shape != null)
+ {
+ IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
+ shape.SetMargin(world.WorldSettings.Params.collisionMargin);
+ shape.SetLocalScaling(ref scaling);
+
+ }
+ return new BulletShapeXNA(shape, pShapeData.Type);
+ }
+ //PhysicsScene.World.ptr, false
+ public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
+ {
+ return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
+ }
+
+ public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
+ {
+ CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape;
+ return compoundshape.GetNumChildShapes();
+ }
+ //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
+ public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
+ {
+ IndexedMatrix relativeTransform = new IndexedMatrix();
+ CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
+ CollisionShape addshape = (paddShape as BulletShapeXNA).shape;
+
+ relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
+ relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
+ compoundshape.AddChildShape(ref relativeTransform, addshape);
+
+ }
+
+ public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
+ {
+ CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape;
+ CollisionShape ret = null;
+ ret = compoundshape.GetChildShape(pii);
+ compoundshape.RemoveChildShapeByIndex(pii);
+ return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType()));
+ }
+
+ public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) {
+
+ if (cShape == null)
+ return null;
+ CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape;
+ CollisionShape shape = compoundShape.GetChildShape(indx);
+ BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType()));
+
+
+ return retShape;
+ }
+
+ public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin)
+ {
+ BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ switch (pin)
+ {
+ case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_BOX;
+ break;
+ case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+
+ case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
+ break;
+ case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_HULL;
+ break;
+ case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ //implicit convex shapes
+ case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_SPHERE;
+ break;
+ case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_CAPSULE;
+ break;
+ case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_CONE;
+ break;
+ case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_CONVEXHULL;
+ break;
+ case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_CYLINDER;
+ break;
+ case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ //concave shape
+ case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy!
+ case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_MESH;
+ break;
+ case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_MESH;
+ break;
+ ///used for demo integration FAST/Swift collision library and Bullet
+ case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_MESH;
+ break;
+ //terrain
+ case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP;
+ break;
+ ///Used for GIMPACT Trimesh integration
+ case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_GIMPACT;
+ break;
+ ///Multimaterial mesh
+ case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_MESH;
+ break;
+
+ case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE;
+ break;
+ case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+
+ case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_COMPOUND;
+ break;
+
+ case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_MESH;
+ break;
+ case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE:
+ ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ break;
+ }
+ return ret;
+ }
+
+ public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
+ public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ }
+
+ public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
+ {
+ StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
+ m_planeshape.SetMargin(pcollisionMargin);
+ m_planeshape.SetUserPointer(pLocalId);
+ return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
+ }
+
+ public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot,
+ bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
+
+ {
+ Generic6DofSpringConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (body1 != null && body2 != null)
+ {
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
+ IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
+ IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
+ frame2._origin = frame1v;
+
+ constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+
+ constrain.CalculateTransforms();
+ }
+
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB,
+ bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ HingeConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (rb1 != null && rb2 != null)
+ {
+ IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
+ IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
+ IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
+ IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
+ constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+ }
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 pframe1, Quaternion pframe1rot,
+ Vector3 pframe2, Quaternion pframe2rot,
+ bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ SliderConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (rb1 != null && rb2 != null)
+ {
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
+ IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
+ IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
+ frame2._origin = frame1v;
+
+ constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+ }
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 pframe1, Quaternion pframe1rot,
+ Vector3 pframe2, Quaternion pframe2rot,
+ bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ ConeTwistConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (rb1 != null && rb2 != null)
+ {
+ IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
+ IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
+ IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
+ frame1._origin = frame1v;
+
+ IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
+ IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
+ IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
+ frame2._origin = frame1v;
+
+ constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+ }
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 paxisInA, Vector3 paxisInB,
+ float pratio, bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ Generic6DofConstraint constrain = null;
+ /* BulletXNA does not have a gear constraint
+ GearConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (rb1 != null && rb2 != null)
+ {
+ IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
+ IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
+ constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+ }
+ */
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2,
+ Vector3 ppivotInA, Vector3 ppivotInB,
+ bool pdisableCollisionsBetweenLinkedBodies)
+ {
+ Point2PointConstraint constrain = null;
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody;
+ RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody;
+ if (rb1 != null && rb2 != null)
+ {
+ IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
+ IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
+ constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB);
+ world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
+ }
+ return new BulletConstraintXNA(constrain);
+ }
+
+ public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CompoundShape compoundshape = new CompoundShape(false);
+
+ compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
+ int ii = 1;
+
+ for (int i = 0; i < pHullCount; i++)
+ {
+ int vertexCount = (int) pConvHulls[ii];
+
+ IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
+ IndexedMatrix childTrans = IndexedMatrix.Identity;
+ childTrans._origin = centroid;
+
+ List virts = new List();
+ int ender = ((ii + 4) + (vertexCount*3));
+ for (int iii = ii + 4; iii < ender; iii+=3)
+ {
+
+ virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
+ }
+ ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
+ convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
+ compoundshape.AddChildShape(ref childTrans, convexShape);
+ ii += (vertexCount*3 + 4);
+ }
+
+ return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
+ }
+
+ public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms)
+ {
+ /* TODO */ return null;
+ }
+
+ public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
+ {
+ /* TODO */ return null;
+ }
+
+ public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
+ {
+ /* TODO */ return null;
+ }
+
+ public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
+ {
+ //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
+
+ for (int iter = 0; iter < pVerticesCount; iter++)
+ {
+ if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
+ if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
+ }
+
+ ObjectArray indicesarr = new ObjectArray(indices);
+ ObjectArray vertices = new ObjectArray(verticesAsFloats);
+ DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ IndexedMesh mesh = new IndexedMesh();
+ mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
+ mesh.m_numTriangles = pIndicesCount/3;
+ mesh.m_numVertices = pVerticesCount;
+ mesh.m_triangleIndexBase = indicesarr;
+ mesh.m_vertexBase = vertices;
+ mesh.m_vertexStride = 3;
+ mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
+ mesh.m_triangleIndexStride = 3;
+
+ TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
+ tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
+ BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
+ meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
+ // world.UpdateSingleAabb(meshShape);
+ return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
+
+ }
+ public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
+ {
+ // TODO:
+ return null;
+ }
+ public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount )
+ {
+
+ String fileName = "objTest3.raw";
+ String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
+ StreamWriter sw = new StreamWriter(completePath);
+ IndexedMesh mesh = new IndexedMesh();
+
+ mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
+ mesh.m_numTriangles = pIndicesCount / 3;
+ mesh.m_numVertices = pVerticesCount;
+ mesh.m_triangleIndexBase = indices;
+ mesh.m_vertexBase = vertices;
+ mesh.m_vertexStride = 3;
+ mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
+ mesh.m_triangleIndexStride = 3;
+
+ TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
+ tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
+
+
+
+ for (int i = 0; i < pVerticesCount; i++)
+ {
+
+ string s = vertices[indices[i * 3]].ToString("0.0000");
+ s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
+ s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
+
+ sw.Write(s + "\n");
+ }
+
+ sw.Close();
+ }
+ public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
+ {
+
+ String fileName = "objTest6.raw";
+ String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
+ StreamWriter sw = new StreamWriter(completePath);
+ IndexedMesh mesh = new IndexedMesh();
+
+ mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
+ mesh.m_numTriangles = pIndicesCount / 3;
+ mesh.m_numVertices = pVerticesCount;
+ mesh.m_triangleIndexBase = indices;
+ mesh.m_vertexBase = vertices;
+ mesh.m_vertexStride = 3;
+ mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
+ mesh.m_triangleIndexStride = 3;
+
+ TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
+ tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
+
+
+ sw.WriteLine("Indices");
+ sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
+ for (int iter = 0; iter < indices.Length; iter++)
+ {
+ sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
+ }
+ sw.WriteLine("VerticesFloats");
+ sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
+ for (int iter = 0; iter < vertices.Length; iter++)
+ {
+ sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
+ }
+
+ // for (int i = 0; i < pVerticesCount; i++)
+ // {
+ //
+ // string s = vertices[indices[i * 3]].ToString("0.0000");
+ // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
+ // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
+ //
+ // sw.Write(s + "\n");
+ //}
+
+ sw.Close();
+ }
+
+ public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
+ float scaleFactor, float collisionMargin)
+ {
+ const int upAxis = 2;
+ HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
+ heightMap, scaleFactor,
+ minHeight, maxHeight, upAxis,
+ false);
+ terrainShape.SetMargin(collisionMargin);
+ terrainShape.SetUseDiamondSubdivision(true);
+ terrainShape.SetUserPointer(id);
+ return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
+ }
+
+ public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
+ {
+ TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain;
+ bool onOff = ponOff != 0;
+ bool ret = false;
+
+ switch (tconstrain.GetConstraintType())
+ {
+ case TypedConstraintType.D6_CONSTRAINT_TYPE:
+ Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
+ constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
+ constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
+ constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
+ ret = true;
+ break;
+ }
+
+
+ return ret;
+
+ }
+
+ public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
+ out int updatedEntityCount, out int collidersCount)
+ {
+ /* TODO */
+ updatedEntityCount = 0;
+ collidersCount = 0;
+
+
+ int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray);
+
+ return ret;
+ }
+
+ private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
+ out int updatedEntityCount, out EntityProperties[] updatedEntities,
+ out int collidersCount, out CollisionDesc[] colliders)
+ {
+ int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
+ out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame);
+ return epic;
+ }
+
+ private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount,
+ out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates)
+ {
+ int numSimSteps = 0;
+ Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length);
+ Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length);
+ LastEntityProperty=0;
+
+
+
+
+
+
+ LastCollisionDesc=0;
+
+ updatedEntityCount = 0;
+ collidersCount = 0;
+
+
+ if (pWorld is BulletWorldXNA)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+
+ world.LastCollisionDesc = 0;
+ world.LastEntityProperty = 0;
+ numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
+
+ PersistentManifold contactManifold;
+ CollisionObject objA;
+ CollisionObject objB;
+ ManifoldPoint manifoldPoint;
+ PairCachingGhostObject pairCachingGhostObject;
+
+ m_collisionsThisFrame = 0;
+ int numManifolds = world.GetDispatcher().GetNumManifolds();
+ for (int j = 0; j < numManifolds; j++)
+ {
+ contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
+ int numContacts = contactManifold.GetNumContacts();
+ if (numContacts == 0)
+ continue;
+
+ objA = contactManifold.GetBody0() as CollisionObject;
+ objB = contactManifold.GetBody1() as CollisionObject;
+
+ manifoldPoint = contactManifold.GetContactPoint(0);
+ //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
+ // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
+
+ RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance());
+ m_collisionsThisFrame ++;
+ if (m_collisionsThisFrame >= 9999999)
+ break;
+
+
+ }
+
+ foreach (GhostObject ghostObject in specialCollisionObjects.Values)
+ {
+ pairCachingGhostObject = ghostObject as PairCachingGhostObject;
+ if (pairCachingGhostObject != null)
+ {
+ RecordGhostCollisions(pairCachingGhostObject);
+ }
+
+ }
+
+
+ updatedEntityCount = LastEntityProperty;
+ updatedEntities = UpdatedObjects;
+
+ collidersCount = LastCollisionDesc;
+ colliders = UpdatedCollisions;
+
+
+ }
+ else
+ {
+ //if (updatedEntities is null)
+ //updatedEntities = new List();
+ //updatedEntityCount = 0;
+
+
+ //collidersCount = 0;
+
+ updatedEntities = new EntityProperties[0];
+
+
+ colliders = new CollisionDesc[0];
+
+ }
+ return numSimSteps;
+ }
+ public void RecordGhostCollisions(PairCachingGhostObject obj)
+ {
+ IOverlappingPairCache cache = obj.GetOverlappingPairCache();
+ ObjectArray pairs = cache.GetOverlappingPairArray();
+
+ DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world;
+ PersistentManifoldArray manifoldArray = new PersistentManifoldArray();
+ BroadphasePair collisionPair;
+ PersistentManifold contactManifold;
+
+ CollisionObject objA;
+ CollisionObject objB;
+
+ ManifoldPoint pt;
+
+ int numPairs = pairs.Count;
+
+ for (int i = 0; i < numPairs; i++)
+ {
+ manifoldArray.Clear();
+ if (LastCollisionDesc < UpdatedCollisions.Length)
+ break;
+ collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1);
+ if (collisionPair == null)
+ continue;
+
+ collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray);
+ for (int j = 0; j < manifoldArray.Count; j++)
+ {
+ contactManifold = manifoldArray[j];
+ int numContacts = contactManifold.GetNumContacts();
+ objA = contactManifold.GetBody0() as CollisionObject;
+ objB = contactManifold.GetBody1() as CollisionObject;
+ for (int p = 0; p < numContacts; p++)
+ {
+ pt = contactManifold.GetContactPoint(p);
+ if (pt.GetDistance() < 0.0f)
+ {
+ RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance());
+ break;
+ }
+ }
+ }
+ }
+
+ }
+ private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration)
+ {
+
+ IndexedVector3 contactNormal = norm;
+ if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
+ (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
+ {
+ return;
+ }
+ uint idA = (uint)objA.GetUserPointer();
+ uint idB = (uint)objB.GetUserPointer();
+ if (idA > idB)
+ {
+ uint temp = idA;
+ idA = idB;
+ idB = temp;
+ contactNormal = -contactNormal;
+ }
+
+ //ulong collisionID = ((ulong) idA << 32) | idB;
+
+ CollisionDesc cDesc = new CollisionDesc()
+ {
+ aID = idA,
+ bID = idB,
+ point = new Vector3(contact.X,contact.Y,contact.Z),
+ normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z),
+ penetration = penetration
+
+ };
+ if (world.LastCollisionDesc < world.UpdatedCollisions.Length)
+ world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc);
+ m_collisionsThisFrame++;
+
+
+ }
+ private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject)
+ {
+ EntityProperties ent = new EntityProperties();
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody;
+ IndexedMatrix transform = collisionObject.GetWorldTransform();
+ IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity();
+ IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity();
+ IndexedQuaternion rotation = transform.GetRotation();
+ ent.Acceleration = Vector3.Zero;
+ ent.ID = (uint)collisionObject.GetUserPointer();
+ ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
+ ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
+ ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
+ ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
+ return ent;
+ }
+
+ public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */
+ return false; }
+
+ public override Vector3 GetLocalScaling(BulletShape pShape)
+ {
+ CollisionShape shape = (pShape as BulletShapeXNA).shape;
+ IndexedVector3 scale = shape.GetLocalScaling();
+ return new Vector3(scale.X,scale.Y,scale.Z);
+ }
+
+ public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
+ {
+ DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world;
+ if (world != null)
+ {
+ if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
+ {
+ CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body;
+
+ IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
+ IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
+ using (
+ ClosestNotMeRayResultCallback rayCallback =
+ new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
+ )
+ {
+ world.RayTest(ref rOrigin, ref rEnd, rayCallback);
+ if (rayCallback.HasHit())
+ {
+ IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
+ }
+ return rayCallback.HasHit();
+ }
+ }
+ }
+ return false;
+ }
+}
+
+
+
+
+ public class SimMotionState : DefaultMotionState
+ {
+ public RigidBody Rigidbody;
+ public Vector3 ZeroVect;
+
+ private IndexedMatrix m_xform;
+
+ private EntityProperties m_properties;
+ private EntityProperties m_lastProperties;
+ private BSAPIXNA m_world;
+
+ const float POSITION_TOLERANCE = 0.05f;
+ const float VELOCITY_TOLERANCE = 0.001f;
+ const float ROTATION_TOLERANCE = 0.01f;
+ const float ANGULARVELOCITY_TOLERANCE = 0.01f;
+
+ public SimMotionState(BSAPIXNA pWorld, uint id, IndexedMatrix starTransform, object frameUpdates)
+ {
+ IndexedQuaternion OrientationQuaterion = starTransform.GetRotation();
+ m_properties = new EntityProperties()
+ {
+ ID = id,
+ Position = new Vector3(starTransform._origin.X, starTransform._origin.Y,starTransform._origin.Z),
+ Rotation = new Quaternion(OrientationQuaterion.X,OrientationQuaterion.Y,OrientationQuaterion.Z,OrientationQuaterion.W)
+ };
+ m_lastProperties = new EntityProperties()
+ {
+ ID = id,
+ Position = new Vector3(starTransform._origin.X, starTransform._origin.Y, starTransform._origin.Z),
+ Rotation = new Quaternion(OrientationQuaterion.X, OrientationQuaterion.Y, OrientationQuaterion.Z, OrientationQuaterion.W)
+ };
+ m_world = pWorld;
+ m_xform = starTransform;
+ }
+
+ public override void GetWorldTransform(out IndexedMatrix worldTrans)
+ {
+ worldTrans = m_xform;
+ }
+
+ public override void SetWorldTransform(IndexedMatrix worldTrans)
+ {
+ SetWorldTransform(ref worldTrans);
+ }
+
+ public override void SetWorldTransform(ref IndexedMatrix worldTrans)
+ {
+ SetWorldTransform(ref worldTrans, false);
+ }
+ public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force)
+ {
+ m_xform = worldTrans;
+ // Put the new transform into m_properties
+ IndexedQuaternion OrientationQuaternion = m_xform.GetRotation();
+ IndexedVector3 LinearVelocityVector = Rigidbody.GetLinearVelocity();
+ IndexedVector3 AngularVelocityVector = Rigidbody.GetAngularVelocity();
+ m_properties.Position = new Vector3(m_xform._origin.X, m_xform._origin.Y, m_xform._origin.Z);
+ m_properties.Rotation = new Quaternion(OrientationQuaternion.X, OrientationQuaternion.Y,
+ OrientationQuaternion.Z, OrientationQuaternion.W);
+ // A problem with stock Bullet is that we don't get an event when an object is deactivated.
+ // This means that the last non-zero values for linear and angular velocity
+ // are left in the viewer who does dead reconning and the objects look like
+ // they float off.
+ // BulletSim ships with a patch to Bullet which creates such an event.
+ m_properties.Velocity = new Vector3(LinearVelocityVector.X, LinearVelocityVector.Y, LinearVelocityVector.Z);
+ m_properties.RotationalVelocity = new Vector3(AngularVelocityVector.X, AngularVelocityVector.Y, AngularVelocityVector.Z);
+
+ if (force
+
+ || !AlmostEqual(ref m_lastProperties.Position, ref m_properties.Position, POSITION_TOLERANCE)
+ || !AlmostEqual(ref m_properties.Rotation, ref m_lastProperties.Rotation, ROTATION_TOLERANCE)
+ // If the Velocity and AngularVelocity are zero, most likely the object has
+ // been deactivated. If they both are zero and they have become zero recently,
+ // make sure a property update is sent so the zeros make it to the viewer.
+ || ((m_properties.Velocity == ZeroVect && m_properties.RotationalVelocity == ZeroVect)
+ &&
+ (m_properties.Velocity != m_lastProperties.Velocity ||
+ m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity))
+ // If Velocity and AngularVelocity are non-zero but have changed, send an update.
+ || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE)
+ ||
+ !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity,
+ ANGULARVELOCITY_TOLERANCE)
+ )
+
+
+ {
+ // Add this update to the list of updates for this frame.
+ m_lastProperties = m_properties;
+ if (m_world.LastEntityProperty < m_world.UpdatedObjects.Length)
+ m_world.UpdatedObjects[m_world.LastEntityProperty++]=(m_properties);
+
+ //(*m_updatesThisFrame)[m_properties.ID] = &m_properties;
+ }
+
+
+
+
+ }
+ public override void SetRigidBody(RigidBody body)
+ {
+ Rigidbody = body;
+ }
+ internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon)
+ {
+ return
+ (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
+ (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
+ (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon)));
+ }
+
+ internal static bool AlmostEqual(ref Quaternion v1, ref Quaternion v2, float nEpsilon)
+ {
+ return
+ (((v1.X - nEpsilon) < v2.X) && (v2.X < (v1.X + nEpsilon))) &&
+ (((v1.Y - nEpsilon) < v2.Y) && (v2.Y < (v1.Y + nEpsilon))) &&
+ (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) &&
+ (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon)));
+ }
+
+ }
+}
+
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
new file mode 100755
index 0000000..bde4557
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorAvatarMove : BSActor
+{
+ BSVMotor m_velocityMotor;
+
+ // Set to true if we think we're going up stairs.
+ // This state is remembered because collisions will turn on and off as we go up stairs.
+ int m_walkingUpStairs;
+ // The amount the step up is applying. Used to smooth stair walking.
+ float m_lastStepUp;
+
+ // Jumping happens over several frames. If use applies up force while colliding, start the
+ // jump and allow the jump to continue for this number of frames.
+ int m_jumpFrames = 0;
+ float m_jumpVelocity = 0f;
+
+ public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_velocityMotor = null;
+ m_walkingUpStairs = 0;
+ m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ base.SetEnabled(false);
+ DeactivateAvatarMove();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
+
+ // If the object is physically active, add the hoverer prestep action
+ if (isActive)
+ {
+ ActivateAvatarMove();
+ }
+ else
+ {
+ DeactivateAvatarMove();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ // Nothing to do for the hoverer since it is all software at pre-step action time.
+ }
+
+ // Usually called when target velocity changes to set the current velocity and the target
+ // into the movement motor.
+ public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
+ {
+ m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate()
+ {
+ if (m_velocityMotor != null)
+ {
+// if (targ == OMV.Vector3.Zero)
+// Util.PrintCallStack();
+//
+// Console.WriteLine("SetVelocityAndTarget, {0} {1}", vel, targ);
+ m_velocityMotor.Reset();
+ m_velocityMotor.SetTarget(targ);
+ m_velocityMotor.SetCurrent(vel);
+ m_velocityMotor.Enabled = true;
+ }
+ });
+ }
+
+ // If a hover motor has not been created, create one and start the hovering.
+ private void ActivateAvatarMove()
+ {
+ if (m_velocityMotor == null)
+ {
+ // Infinite decay and timescale values so motor only changes current to target values.
+ m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
+ 0.2f, // time scale
+ BSMotor.Infinite, // decay time scale
+ 1f // efficiency
+ );
+ m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold;
+ // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
+ SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
+
+ m_physicsScene.BeforeStep += Mover;
+ m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty;
+
+ m_walkingUpStairs = 0;
+ }
+ }
+
+ private void DeactivateAvatarMove()
+ {
+ if (m_velocityMotor != null)
+ {
+ m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty;
+ m_physicsScene.BeforeStep -= Mover;
+ m_velocityMotor = null;
+ }
+ }
+
+ // Called just before the simulation step. Update the vertical position for hoverness.
+ private void Mover(float timeStep)
+ {
+ // Don't do movement while the object is selected.
+ if (!isActive)
+ return;
+
+ // TODO: Decide if the step parameters should be changed depending on the avatar's
+ // state (flying, colliding, ...). There is code in ODE to do this.
+
+ // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
+ // specified for the avatar is the one that should be used. For falling, if the avatar
+ // is not flying and is not colliding then it is presumed to be falling and the Z
+ // component is not fooled with (thus allowing gravity to do its thing).
+ // When the avatar is standing, though, the user has specified a velocity of zero and
+ // the avatar should be standing. But if the avatar is pushed by something in the world
+ // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
+ // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
+ // errors can creap in and the avatar will slowly float off in some direction.
+ // So, the problem is that, when an avatar is standing, we cannot tell creaping error
+ // from real pushing.
+ // The code below uses whether the collider is static or moving to decide whether to zero motion.
+
+ m_velocityMotor.Step(timeStep);
+ m_controllingPrim.IsStationary = false;
+
+ // If we're not supposed to be moving, make sure things are zero.
+ if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
+ {
+ // The avatar shouldn't be moving
+ m_velocityMotor.Zero();
+
+ if (m_controllingPrim.IsColliding)
+ {
+ // If we are colliding with a stationary object, presume we're standing and don't move around
+ if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect)
+ {
+ m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
+ m_controllingPrim.IsStationary = true;
+ m_controllingPrim.ZeroMotion(true /* inTaintTime */);
+ }
+
+ // Standing has more friction on the ground
+ if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
+ {
+ m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
+ m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
+ }
+ }
+ else
+ {
+ if (m_controllingPrim.Flying)
+ {
+ // Flying and not colliding and velocity nearly zero.
+ m_controllingPrim.ZeroMotion(true /* inTaintTime */);
+ }
+ else
+ {
+ //We are falling but are not touching any keys make sure not falling too fast
+ if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
+ {
+
+ OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass;
+ m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce);
+ }
+
+ }
+ }
+
+ m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
+ m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
+ }
+ else
+ {
+ // Supposed to be moving.
+ OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
+
+ if (m_controllingPrim.Friction != BSParam.AvatarFriction)
+ {
+ // Probably starting to walk. Set friction to moving friction.
+ m_controllingPrim.Friction = BSParam.AvatarFriction;
+ m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
+ }
+
+ if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
+ {
+ stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
+ }
+
+ // Colliding and not flying with an upward force. The avatar must be trying to jump.
+ if (!m_controllingPrim.Flying && m_controllingPrim.IsColliding && stepVelocity.Z > 0)
+ {
+ // We allow the upward force to happen for this many frames.
+ m_jumpFrames = BSParam.AvatarJumpFrames;
+ m_jumpVelocity = stepVelocity.Z;
+ }
+
+ // The case where the avatar is not colliding and is not flying is special.
+ // The avatar is either falling or jumping and the user can be applying force to the avatar
+ // (force in some direction or force up or down).
+ // If the avatar has negative Z velocity and is not colliding, presume we're falling and keep the velocity.
+ // If the user is trying to apply upward force but we're not colliding, assume the avatar
+ // is trying to jump and don't apply the upward force if not touching the ground any more.
+ if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
+ {
+ // If upward velocity is being applied, this must be a jump and only allow that to go on so long
+ if (m_jumpFrames > 0)
+ {
+ // Since not touching the ground, only apply upward force for so long.
+ m_jumpFrames--;
+ stepVelocity.Z = m_jumpVelocity;
+ }
+ else
+ {
+
+ // Since we're not affected by anything, the avatar must be falling and we do not want that to be too fast.
+ if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity)
+ {
+
+ stepVelocity.Z = BSParam.AvatarTerminalVelocity;
+ }
+ else
+ {
+ stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
+ }
+ }
+ // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
+ }
+
+ //Alicia: Maintain minimum height when flying.
+ // SL has a flying effect that keeps the avatar flying above the ground by some margin
+ if (m_controllingPrim.Flying)
+ {
+ float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition)
+ + BSParam.AvatarFlyingGroundMargin;
+
+ if( m_controllingPrim.Position.Z < hover_height)
+ {
+ stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce;
+ }
+ }
+
+ // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
+ OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
+
+ // Add special movement force to allow avatars to walk up stepped surfaces.
+ moveForce += WalkUpStairs();
+
+ m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
+ m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
+ m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
+ }
+ }
+
+ // Called just as the property update is received from the physics engine.
+ // Do any mode necessary for avatar movement.
+ private void Process_OnPreUpdateProperty(ref EntityProperties entprop)
+ {
+ // Don't change position if standing on a stationary object.
+ if (m_controllingPrim.IsStationary)
+ {
+ entprop.Position = m_controllingPrim.RawPosition;
+ entprop.Velocity = OMV.Vector3.Zero;
+ m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation);
+ }
+
+ }
+
+ // Decide if the character is colliding with a low object and compute a force to pop the
+ // avatar up so it can walk up and over the low objects.
+ private OMV.Vector3 WalkUpStairs()
+ {
+ OMV.Vector3 ret = OMV.Vector3.Zero;
+
+ m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
+ m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
+ m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
+
+ // Check for stairs climbing if colliding, not flying and moving forward
+ if ( m_controllingPrim.IsColliding
+ && !m_controllingPrim.Flying
+ && m_controllingPrim.TargetVelocitySpeed > 0.1f )
+ {
+ // The range near the character's feet where we will consider stairs
+ // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
+ // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
+ // from the height. Revisit size and this computation when height is scaled properly.
+ float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge;
+ float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
+
+ // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
+ // Find the highest 'good' collision.
+ OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
+ foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
+ {
+ // Don't care about collisions with the terrain
+ if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
+ {
+ BSPhysObject collisionObject;
+ if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject))
+ {
+ if (!collisionObject.IsVolumeDetect)
+ {
+ OMV.Vector3 touchPosition = kvp.Value.Position;
+ m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
+ m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
+ if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
+ {
+ // This contact is within the 'near the feet' range.
+ // The step is presumed to be more or less vertical. Thus the Z component should
+ // be nearly horizontal.
+ OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
+ OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
+ const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles
+ // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}",
+ // m_controllingPrim.LocalID, directionFacing, touchNormal,
+ // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) );
+ if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle
+ && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle)
+ {
+ // The normal should be our contact point to the object so it is pointing away
+ // thus the difference between our facing orientation and the normal should be small.
+ float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
+ if (diff < BSParam.AvatarStepApproachFactor)
+ {
+ if (highestTouchPosition.Z < touchPosition.Z)
+ highestTouchPosition = touchPosition;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ m_walkingUpStairs = 0;
+ // If there is a good step sensing, move the avatar over the step.
+ if (highestTouchPosition != OMV.Vector3.Zero)
+ {
+ // Remember that we are going up stairs. This is needed because collisions
+ // will stop when we move up so this smoothes out that effect.
+ m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
+
+ m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
+ ret = ComputeStairCorrection(m_lastStepUp);
+ m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
+ m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
+ }
+ }
+ else
+ {
+ // If we used to be going up stairs but are not now, smooth the case where collision goes away while
+ // we are bouncing up the stairs.
+ if (m_walkingUpStairs > 0)
+ {
+ m_walkingUpStairs--;
+ ret = ComputeStairCorrection(m_lastStepUp);
+ }
+ }
+
+ return ret;
+ }
+
+ private OMV.Vector3 ComputeStairCorrection(float stepUp)
+ {
+ OMV.Vector3 ret = OMV.Vector3.Zero;
+ OMV.Vector3 displacement = OMV.Vector3.Zero;
+
+ if (stepUp > 0f)
+ {
+ // Found the stairs contact point. Push up a little to raise the character.
+ if (BSParam.AvatarStepForceFactor > 0f)
+ {
+ float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
+ ret = new OMV.Vector3(0f, 0f, upForce);
+ }
+
+ // Also move the avatar up for the new height
+ if (BSParam.AvatarStepUpCorrectionFactor > 0f)
+ {
+ // Move the avatar up related to the height of the collision
+ displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
+ m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
+ }
+ else
+ {
+ if (BSParam.AvatarStepUpCorrectionFactor < 0f)
+ {
+ // Move the avatar up about the specified step height
+ displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
+ m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
+ }
+ }
+ m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}",
+ m_controllingPrim.LocalID, stepUp, displacement, ret);
+
+ }
+ return ret;
+ }
+}
+}
+
+
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
new file mode 100755
index 0000000..e54c27b
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorHover : BSActor
+{
+ private BSFMotor m_hoverMotor;
+
+ public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_hoverMotor = null;
+ m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ get { return Enabled; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ Enabled = false;
+ DeactivateHover();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
+
+ // If not active any more, turn me off
+ if (!m_controllingPrim.HoverActive)
+ {
+ SetEnabled(false);
+ }
+
+ // If the object is physically active, add the hoverer prestep action
+ if (isActive)
+ {
+ ActivateHover();
+ }
+ else
+ {
+ DeactivateHover();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ // Nothing to do for the hoverer since it is all software at pre-step action time.
+ }
+
+ // If a hover motor has not been created, create one and start the hovering.
+ private void ActivateHover()
+ {
+ if (m_hoverMotor == null)
+ {
+ // Turning the target on
+ m_hoverMotor = new BSFMotor("BSActorHover",
+ m_controllingPrim.HoverTau, // timeScale
+ BSMotor.Infinite, // decay time scale
+ 1f // efficiency
+ );
+ m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
+ m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
+ m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
+
+ m_physicsScene.BeforeStep += Hoverer;
+ }
+ }
+
+ private void DeactivateHover()
+ {
+ if (m_hoverMotor != null)
+ {
+ m_physicsScene.BeforeStep -= Hoverer;
+ m_hoverMotor = null;
+ }
+ }
+
+ // Called just before the simulation step. Update the vertical position for hoverness.
+ private void Hoverer(float timeStep)
+ {
+ // Don't do hovering while the object is selected.
+ if (!isActive)
+ return;
+
+ m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
+ m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
+ float targetHeight = m_hoverMotor.Step(timeStep);
+
+ // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
+ // Compute the amount of force to push us there.
+ float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
+ // Undo anything the object thinks it's doing at the moment
+ moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
+
+ m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
+ m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
+ m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
+ }
+
+ // Based on current position, determine what we should be hovering at now.
+ // Must recompute often. What if we walked offa cliff>
+ private float ComputeCurrentHoverHeight()
+ {
+ float ret = m_controllingPrim.HoverHeight;
+ float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
+
+ switch (m_controllingPrim.HoverType)
+ {
+ case PIDHoverType.Ground:
+ ret = groundHeight + m_controllingPrim.HoverHeight;
+ break;
+ case PIDHoverType.GroundAndWater:
+ float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
+ if (groundHeight > waterHeight)
+ {
+ ret = groundHeight + m_controllingPrim.HoverHeight;
+ }
+ else
+ {
+ ret = waterHeight + m_controllingPrim.HoverHeight;
+ }
+ break;
+ }
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
new file mode 100755
index 0000000..3b3c161
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorLockAxis : BSActor
+{
+ private BSConstraint LockAxisConstraint = null;
+ private bool HaveRegisteredForBeforeStepCallback = false;
+
+ // The lock access flags (which axises were locked) when the contraint was built.
+ // Used to see if locking has changed since when the constraint was built.
+ OMV.Vector3 LockAxisLinearFlags;
+ OMV.Vector3 LockAxisAngularFlags;
+
+ public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
+ LockAxisConstraint = null;
+ HaveRegisteredForBeforeStepCallback = false;
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ Enabled = false;
+ UnRegisterForBeforeStepCallback();
+ RemoveAxisLockConstraint();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ // Since the axis logging is done with a constraint, Refresh() time is good for
+ // changing parameters but this needs to wait until the prim/linkset is physically
+ // constructed. Therefore, the constraint itself is placed at pre-step time.
+
+ // If all the axis are free, we don't need to exist
+ // Refresh() only turns off. Enabling is done by InitializeAxisActor()
+ // whenever parameters are changed.
+ // This leaves 'enable' free to turn off an actor when it is not wanted to run.
+ if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
+ && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
+ {
+ Enabled = false;
+ }
+
+ if (isActive)
+ {
+ RegisterForBeforeStepCallback();
+ }
+ else
+ {
+ RemoveDependencies();
+ UnRegisterForBeforeStepCallback();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ RemoveAxisLockConstraint();
+ }
+
+ private void RegisterForBeforeStepCallback()
+ {
+ if (!HaveRegisteredForBeforeStepCallback)
+ {
+ m_physicsScene.BeforeStep += PhysicsScene_BeforeStep;
+ HaveRegisteredForBeforeStepCallback = true;
+ }
+ }
+
+ private void UnRegisterForBeforeStepCallback()
+ {
+ if (HaveRegisteredForBeforeStepCallback)
+ {
+ m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep;
+ HaveRegisteredForBeforeStepCallback = false;
+ }
+ }
+
+ private void PhysicsScene_BeforeStep(float timestep)
+ {
+ // If all the axis are free, we don't need to exist
+ if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree
+ && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree)
+ {
+ Enabled = false;
+ }
+
+ // If the object is physically active, add the axis locking constraint
+ if (isActive)
+ {
+ // Check to see if the locking parameters have changed
+ if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags
+ || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags)
+ {
+ // The locking has changed. Remove the old constraint and build a new one
+ RemoveAxisLockConstraint();
+ }
+
+ AddAxisLockConstraint();
+ }
+ else
+ {
+ RemoveAxisLockConstraint();
+ }
+ }
+
+ // Note that this relies on being called at TaintTime
+ private void AddAxisLockConstraint()
+ {
+ if (LockAxisConstraint == null)
+ {
+ // Lock that axis by creating a 6DOF constraint that has one end in the world and
+ // the other in the object.
+ // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
+ // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
+
+ // Remove any existing axis constraint (just to be sure)
+ RemoveAxisLockConstraint();
+
+ BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
+ OMV.Vector3.Zero, OMV.Quaternion.Identity,
+ false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
+ LockAxisConstraint = axisConstrainer;
+ m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
+
+ // Remember the clocking being inforced so we can notice if they have changed
+ LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis;
+ LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis;
+
+ // The constraint is tied to the world and oriented to the prim.
+
+ if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh))
+ {
+ m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits",
+ m_controllingPrim.LocalID);
+ }
+
+ if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh))
+ {
+ m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits",
+ m_controllingPrim.LocalID);
+ }
+
+ m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
+ m_controllingPrim.LocalID,
+ m_controllingPrim.LockedLinearAxisLow,
+ m_controllingPrim.LockedLinearAxisHigh,
+ m_controllingPrim.LockedAngularAxisLow,
+ m_controllingPrim.LockedAngularAxisHigh);
+
+ // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
+ axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
+
+ axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
+
+ RegisterForBeforeStepCallback();
+ }
+ }
+
+ private void RemoveAxisLockConstraint()
+ {
+ UnRegisterForBeforeStepCallback();
+ if (LockAxisConstraint != null)
+ {
+ m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
+ LockAxisConstraint = null;
+ m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID);
+ }
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
new file mode 100755
index 0000000..1145006
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorMoveToTarget : BSActor
+{
+ private BSVMotor m_targetMotor;
+
+ public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_targetMotor = null;
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ // MoveToTarget only works on physical prims
+ get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ Enabled = false;
+ DeactivateMoveToTarget();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}",
+ m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive,
+ m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau );
+
+ // If not active any more...
+ if (!m_controllingPrim.MoveToTargetActive)
+ {
+ Enabled = false;
+ }
+
+ if (isActive)
+ {
+ ActivateMoveToTarget();
+ }
+ else
+ {
+ DeactivateMoveToTarget();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ // Nothing to do for the moveToTarget since it is all software at pre-step action time.
+ }
+
+ // If a hover motor has not been created, create one and start the hovering.
+ private void ActivateMoveToTarget()
+ {
+ if (m_targetMotor == null)
+ {
+ // We're taking over after this.
+ m_controllingPrim.ZeroMotion(true);
+
+ /* Someday use the PID controller
+ m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString());
+ m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau;
+ m_targetMotor.Efficiency = 1f;
+ */
+ m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(),
+ m_controllingPrim.MoveToTargetTau, // timeScale
+ BSMotor.Infinite, // decay time scale
+ 1f // efficiency
+ );
+ m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
+ m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
+ m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
+
+ // m_physicsScene.BeforeStep += Mover;
+ m_physicsScene.BeforeStep += Mover2;
+ }
+ else
+ {
+ // If already allocated, make sure the target and other paramters are current
+ m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
+ m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
+ }
+ }
+
+ private void DeactivateMoveToTarget()
+ {
+ if (m_targetMotor != null)
+ {
+ // m_physicsScene.BeforeStep -= Mover;
+ m_physicsScene.BeforeStep -= Mover2;
+ m_targetMotor = null;
+ }
+ }
+
+ // Origional mover that set the objects position to move to the target.
+ // The problem was that gravity would keep trying to push the object down so
+ // the overall downward velocity would increase to infinity.
+ // Called just before the simulation step.
+ private void Mover(float timeStep)
+ {
+ // Don't do hovering while the object is selected.
+ if (!isActive)
+ return;
+
+ OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
+
+ // 'movePosition' is where we'd like the prim to be at this moment.
+ OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
+
+ // If we are very close to our target, turn off the movement motor.
+ if (m_targetMotor.ErrorIsZero())
+ {
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}",
+ m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
+ m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
+ m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
+ // Setting the position does not cause the physics engine to generate a property update. Force it.
+ m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
+ }
+ else
+ {
+ m_controllingPrim.ForcePosition = movePosition;
+ // Setting the position does not cause the physics engine to generate a property update. Force it.
+ m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
+ }
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}",
+ m_controllingPrim.LocalID, origPosition, movePosition);
+ }
+
+ // Version of mover that applies forces to move the physical object to the target.
+ // Also overcomes gravity so the object doesn't just drop to the ground.
+ // Called just before the simulation step.
+ private void Mover2(float timeStep)
+ {
+ // Don't do hovering while the object is selected.
+ if (!isActive)
+ return;
+
+ OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
+ OMV.Vector3 addedForce = OMV.Vector3.Zero;
+
+ // CorrectionVector is the movement vector required this step
+ OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition);
+
+ // If we are very close to our target, turn off the movement motor.
+ if (m_targetMotor.ErrorIsZero())
+ {
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}",
+ m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
+ m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
+ m_controllingPrim.ForceVelocity = OMV.Vector3.Zero;
+ // Setting the position does not cause the physics engine to generate a property update. Force it.
+ m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody);
+ }
+ else
+ {
+ // First force to move us there -- the motor return a timestep scaled value.
+ addedForce = correctionVector / timeStep;
+ // Remove the existing velocity (only the moveToTarget force counts)
+ addedForce -= m_controllingPrim.RawVelocity;
+ // Overcome gravity.
+ addedForce -= m_controllingPrim.Gravity;
+
+ // Add enough force to overcome the mass of the object
+ addedForce *= m_controllingPrim.Mass;
+
+ m_controllingPrim.AddForce(addedForce, false /* pushForce */, true /* inTaintTime */);
+ }
+ m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}",
+ m_controllingPrim.LocalID, origPosition, addedForce);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
new file mode 100755
index 0000000..4e81363
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorSetForce : BSActor
+{
+ BSFMotor m_forceMotor;
+
+ public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_forceMotor = null;
+ m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ Enabled = false;
+ DeactivateSetForce();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
+
+ // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
+ if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
+ {
+ m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
+ Enabled = false;
+ return;
+ }
+
+ // If the object is physically active, add the hoverer prestep action
+ if (isActive)
+ {
+ ActivateSetForce();
+ }
+ else
+ {
+ DeactivateSetForce();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ // Nothing to do for the hoverer since it is all software at pre-step action time.
+ }
+
+ // If a hover motor has not been created, create one and start the hovering.
+ private void ActivateSetForce()
+ {
+ if (m_forceMotor == null)
+ {
+ // A fake motor that might be used someday
+ m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f);
+
+ m_physicsScene.BeforeStep += Mover;
+ }
+ }
+
+ private void DeactivateSetForce()
+ {
+ if (m_forceMotor != null)
+ {
+ m_physicsScene.BeforeStep -= Mover;
+ m_forceMotor = null;
+ }
+ }
+
+ // Called just before the simulation step. Update the vertical position for hoverness.
+ private void Mover(float timeStep)
+ {
+ // Don't do force while the object is selected.
+ if (!isActive)
+ return;
+
+ m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
+ if (m_controllingPrim.PhysBody.HasPhysicalBody)
+ {
+ m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
+ m_controllingPrim.ActivateIfPhysical(false);
+ }
+
+ // TODO:
+ }
+}
+}
+
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
new file mode 100755
index 0000000..79e1d38
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorSetTorque : BSActor
+{
+ BSFMotor m_torqueMotor;
+
+ public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ : base(physicsScene, pObj, actorName)
+ {
+ m_torqueMotor = null;
+ m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
+ }
+
+ // BSActor.isActive
+ public override bool isActive
+ {
+ get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
+ }
+
+ // Release any connections and resources used by the actor.
+ // BSActor.Dispose()
+ public override void Dispose()
+ {
+ Enabled = false;
+ DeactivateSetTorque();
+ }
+
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ // Called at taint-time.
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
+
+ // If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
+ if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
+ {
+ m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName);
+ Enabled = false;
+ return;
+ }
+
+ // If the object is physically active, add the hoverer prestep action
+ if (isActive)
+ {
+ ActivateSetTorque();
+ }
+ else
+ {
+ DeactivateSetTorque();
+ }
+ }
+
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ // Called at taint-time.
+ // BSActor.RemoveDependencies()
+ public override void RemoveDependencies()
+ {
+ // Nothing to do for the hoverer since it is all software at pre-step action time.
+ }
+
+ // If a hover motor has not been created, create one and start the hovering.
+ private void ActivateSetTorque()
+ {
+ if (m_torqueMotor == null)
+ {
+ // A fake motor that might be used someday
+ m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f);
+
+ m_physicsScene.BeforeStep += Mover;
+ }
+ }
+
+ private void DeactivateSetTorque()
+ {
+ if (m_torqueMotor != null)
+ {
+ m_physicsScene.BeforeStep -= Mover;
+ m_torqueMotor = null;
+ }
+ }
+
+ // Called just before the simulation step. Update the vertical position for hoverness.
+ private void Mover(float timeStep)
+ {
+ // Don't do force while the object is selected.
+ if (!isActive)
+ return;
+
+ m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
+ if (m_controllingPrim.PhysBody.HasPhysicalBody)
+ {
+ m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
+ m_controllingPrim.ActivateIfPhysical(false);
+ }
+
+ // TODO:
+ }
+}
+}
+
+
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
new file mode 100755
index 0000000..7f45e2c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSActorCollection
+{
+ private Dictionary m_actors;
+
+ public BSActorCollection()
+ {
+ m_actors = new Dictionary();
+ }
+ public void Add(string name, BSActor actor)
+ {
+ lock (m_actors)
+ {
+ if (!m_actors.ContainsKey(name))
+ {
+ m_actors[name] = actor;
+ }
+ }
+ }
+ public bool RemoveAndRelease(string name)
+ {
+ bool ret = false;
+ lock (m_actors)
+ {
+ if (m_actors.ContainsKey(name))
+ {
+ BSActor beingRemoved = m_actors[name];
+ m_actors.Remove(name);
+ beingRemoved.Dispose();
+ ret = true;
+ }
+ }
+ return ret;
+ }
+ public void Clear()
+ {
+ lock (m_actors)
+ {
+ ForEachActor(a => a.Dispose());
+ m_actors.Clear();
+ }
+ }
+ public void Dispose()
+ {
+ Clear();
+ }
+ public bool HasActor(string name)
+ {
+ return m_actors.ContainsKey(name);
+ }
+ public bool TryGetActor(string actorName, out BSActor theActor)
+ {
+ return m_actors.TryGetValue(actorName, out theActor);
+ }
+ public void ForEachActor(Action act)
+ {
+ lock (m_actors)
+ {
+ foreach (KeyValuePair kvp in m_actors)
+ act(kvp.Value);
+ }
+ }
+
+ public void Enable(bool enabl)
+ {
+ ForEachActor(a => a.SetEnabled(enabl));
+ }
+ public void Refresh()
+ {
+ ForEachActor(a => a.Refresh());
+ }
+ public void RemoveDependencies()
+ {
+ ForEachActor(a => a.RemoveDependencies());
+ }
+}
+
+// =============================================================================
+///
+/// Each physical object can have 'actors' who are pushing the object around.
+/// This can be used for hover, locking axis, making vehicles, etc.
+/// Each physical object can have multiple actors acting on it.
+///
+/// An actor usually registers itself with physics scene events (pre-step action)
+/// and modifies the parameters on the host physical object.
+///
+public abstract class BSActor
+{
+ protected BSScene m_physicsScene { get; private set; }
+ protected BSPhysObject m_controllingPrim { get; private set; }
+ public virtual bool Enabled { get; set; }
+ public string ActorName { get; private set; }
+
+ public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
+ {
+ m_physicsScene = physicsScene;
+ m_controllingPrim = pObj;
+ ActorName = actorName;
+ Enabled = true;
+ }
+
+ // Return 'true' if activily updating the prim
+ public virtual bool isActive
+ {
+ get { return Enabled; }
+ }
+
+ // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
+ // Anyone else should assign true/false to 'Enabled'.
+ public void SetEnabled(bool setEnabled)
+ {
+ Enabled = setEnabled;
+ }
+ // Release any connections and resources used by the actor.
+ public abstract void Dispose();
+ // Called when physical parameters (properties set in Bullet) need to be re-applied.
+ public abstract void Refresh();
+ // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
+ // Register a prestep action to restore physical requirements before the next simulation step.
+ public abstract void RemoveDependencies();
+
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
new file mode 100644
index 0000000..8491c0f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs
@@ -0,0 +1,763 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin {
+
+ // Constraint type values as defined by Bullet
+public enum ConstraintType : int
+{
+ POINT2POINT_CONSTRAINT_TYPE = 3,
+ HINGE_CONSTRAINT_TYPE,
+ CONETWIST_CONSTRAINT_TYPE,
+ D6_CONSTRAINT_TYPE,
+ SLIDER_CONSTRAINT_TYPE,
+ CONTACT_CONSTRAINT_TYPE,
+ D6_SPRING_CONSTRAINT_TYPE,
+ GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82
+ FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82
+ MAX_CONSTRAINT_TYPE, // last type defined by Bullet
+ //
+ BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving
+}
+
+// ===============================================================================
+[StructLayout(LayoutKind.Sequential)]
+public struct ConvexHull
+{
+ Vector3 Offset;
+ int VertexCount;
+ Vector3[] Vertices;
+}
+public enum BSPhysicsShapeType
+{
+ SHAPE_UNKNOWN = 0,
+ SHAPE_CAPSULE = 1,
+ SHAPE_BOX = 2,
+ SHAPE_CONE = 3,
+ SHAPE_CYLINDER = 4,
+ SHAPE_SPHERE = 5,
+ SHAPE_MESH = 6,
+ SHAPE_HULL = 7,
+ // following defined by BulletSim
+ SHAPE_GROUNDPLANE = 20,
+ SHAPE_TERRAIN = 21,
+ SHAPE_COMPOUND = 22,
+ SHAPE_HEIGHTMAP = 23,
+ SHAPE_AVATAR = 24,
+ SHAPE_CONVEXHULL= 25,
+ SHAPE_GIMPACT = 26,
+};
+
+// The native shapes have predefined shape hash keys
+public enum FixedShapeKey : ulong
+{
+ KEY_NONE = 0,
+ KEY_BOX = 1,
+ KEY_SPHERE = 2,
+ KEY_CONE = 3,
+ KEY_CYLINDER = 4,
+ KEY_CAPSULE = 5,
+ KEY_AVATAR = 6,
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public struct ShapeData
+{
+ public UInt32 ID;
+ public BSPhysicsShapeType Type;
+ public Vector3 Position;
+ public Quaternion Rotation;
+ public Vector3 Velocity;
+ public Vector3 Scale;
+ public float Mass;
+ public float Buoyancy;
+ public System.UInt64 HullKey;
+ public System.UInt64 MeshKey;
+ public float Friction;
+ public float Restitution;
+ public float Collidable; // true of things bump into this
+ public float Static; // true if a static object. Otherwise gravity, etc.
+ public float Solid; // true if object cannot be passed through
+ public Vector3 Size;
+
+ // note that bools are passed as floats since bool size changes by language and architecture
+ public const float numericTrue = 1f;
+ public const float numericFalse = 0f;
+}
+[StructLayout(LayoutKind.Sequential)]
+public struct SweepHit
+{
+ public UInt32 ID;
+ public float Fraction;
+ public Vector3 Normal;
+ public Vector3 Point;
+}
+[StructLayout(LayoutKind.Sequential)]
+public struct RaycastHit
+{
+ public UInt32 ID;
+ public float Fraction;
+ public Vector3 Normal;
+}
+[StructLayout(LayoutKind.Sequential)]
+public struct CollisionDesc
+{
+ public UInt32 aID;
+ public UInt32 bID;
+ public Vector3 point;
+ public Vector3 normal;
+ public float penetration;
+}
+[StructLayout(LayoutKind.Sequential)]
+public struct EntityProperties
+{
+ public UInt32 ID;
+ public Vector3 Position;
+ public Quaternion Rotation;
+ public Vector3 Velocity;
+ public Vector3 Acceleration;
+ public Vector3 RotationalVelocity;
+
+ public override string ToString()
+ {
+ StringBuilder buff = new StringBuilder();
+ buff.Append("");
+ return buff.ToString();
+ }
+}
+
+// Format of this structure must match the definition in the C++ code
+// NOTE: adding the X causes compile breaks if used. These are unused symbols
+// that can be removed from both here and the unmanaged definition of this structure.
+[StructLayout(LayoutKind.Sequential)]
+public struct ConfigurationParameters
+{
+ public float defaultFriction;
+ public float defaultDensity;
+ public float defaultRestitution;
+ public float collisionMargin;
+ public float gravity;
+
+ public float maxPersistantManifoldPoolSize;
+ public float maxCollisionAlgorithmPoolSize;
+ public float shouldDisableContactPoolDynamicAllocation;
+ public float shouldForceUpdateAllAabbs;
+ public float shouldRandomizeSolverOrder;
+ public float shouldSplitSimulationIslands;
+ public float shouldEnableFrictionCaching;
+ public float numberOfSolverIterations;
+ public float useSingleSidedMeshes;
+ public float globalContactBreakingThreshold;
+
+ public float physicsLoggingFrames;
+
+ public const float numericTrue = 1f;
+ public const float numericFalse = 0f;
+}
+
+// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library.
+[StructLayout(LayoutKind.Sequential)]
+public struct HACDParams
+{
+ // usual default values
+ public float maxVerticesPerHull; // 100
+ public float minClusters; // 2
+ public float compacityWeight; // 0.1
+ public float volumeWeight; // 0.0
+ public float concavity; // 100
+ public float addExtraDistPoints; // false
+ public float addNeighboursDistPoints; // false
+ public float addFacesPoints; // false
+ public float shouldAdjustCollisionMargin; // false
+ // VHACD
+ public float whichHACD; // zero if Bullet HACD, non-zero says VHACD
+ // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
+ public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage
+ public float vHACDdepth; // 20 max number of clipping stages
+ public float vHACDconcavity; // 0.0025 maximum concavity
+ public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane
+ public float vHACDconvexHullDownsampling; // 4 precision of hull gen process
+ public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes
+ public float vHACDbeta; // 0.05 bias toward clipping along revolution axis
+ public float vHACDgamma; // 0.00125 max concavity when merging
+ public float vHACDpca; // 0 on/off normalizing mesh before decomp
+ public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based
+ public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull
+ public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls
+}
+
+// The states a bullet collision object can have
+public enum ActivationState : uint
+{
+ ACTIVE_TAG = 1,
+ ISLAND_SLEEPING,
+ WANTS_DEACTIVATION,
+ DISABLE_DEACTIVATION,
+ DISABLE_SIMULATION,
+}
+
+public enum CollisionObjectTypes : int
+{
+ CO_COLLISION_OBJECT = 1 << 0,
+ CO_RIGID_BODY = 1 << 1,
+ CO_GHOST_OBJECT = 1 << 2,
+ CO_SOFT_BODY = 1 << 3,
+ CO_HF_FLUID = 1 << 4,
+ CO_USER_TYPE = 1 << 5,
+}
+
+// Values used by Bullet and BulletSim to control object properties.
+// Bullet's "CollisionFlags" has more to do with operations on the
+// object (if collisions happen, if gravity effects it, ...).
+public enum CollisionFlags : uint
+{
+ CF_STATIC_OBJECT = 1 << 0,
+ CF_KINEMATIC_OBJECT = 1 << 1,
+ CF_NO_CONTACT_RESPONSE = 1 << 2,
+ CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
+ CF_CHARACTER_OBJECT = 1 << 4,
+ CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
+ CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
+ // Following used by BulletSim to control collisions and updates
+ BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed
+ BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level
+ BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking
+ BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape
+ BS_NONE = 0,
+ BS_ALL = 0x7FFF // collision flags are a signed short
+};
+
+// Values f collisions groups and masks
+public enum CollisionFilterGroups : uint
+{
+ // Don't use the bit definitions!! Define the use in a
+ // filter/mask definition below. This way collision interactions
+ // are more easily found and debugged.
+ BNoneGroup = 0,
+ BDefaultGroup = 1 << 0, // 0001
+ BStaticGroup = 1 << 1, // 0002
+ BKinematicGroup = 1 << 2, // 0004
+ BDebrisGroup = 1 << 3, // 0008
+ BSensorTrigger = 1 << 4, // 0010
+ BCharacterGroup = 1 << 5, // 0020
+ BAllGroup = 0x0007FFF, // collision flags are a signed short
+ // Filter groups defined by BulletSim
+ BGroundPlaneGroup = 1 << 8, // 0400
+ BTerrainGroup = 1 << 9, // 0800
+ BRaycastGroup = 1 << 10, // 1000
+ BSolidGroup = 1 << 11, // 2000
+ // BLinksetGroup = xx // a linkset proper is either static or dynamic
+ BLinksetChildGroup = 1 << 12, // 4000
+};
+
+// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
+// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
+public enum ConstraintParams : int
+{
+ BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
+ BT_CONSTRAINT_STOP_ERP,
+ BT_CONSTRAINT_CFM,
+ BT_CONSTRAINT_STOP_CFM,
+};
+public enum ConstraintParamAxis : int
+{
+ AXIS_LINEAR_X = 0,
+ AXIS_LINEAR_Y,
+ AXIS_LINEAR_Z,
+ AXIS_ANGULAR_X,
+ AXIS_ANGULAR_Y,
+ AXIS_ANGULAR_Z,
+ AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls
+ AXIS_ANGULAR_ALL,
+ AXIS_ALL
+};
+
+public abstract class BSAPITemplate
+{
+// Returns the name of the underlying Bullet engine
+public abstract string BulletEngineName { get; }
+public abstract string BulletEngineVersion { get; protected set;}
+
+// Initialization and simulation
+public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
+ int maxCollisions, ref CollisionDesc[] collisionArray,
+ int maxUpdates, ref EntityProperties[] updateArray
+ );
+
+public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
+ out int updatedEntityCount, out int collidersCount);
+
+public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value);
+
+public abstract void Shutdown(BulletWorld sim);
+
+public abstract bool PushUpdate(BulletBody obj);
+
+// =====================================================================================
+// Mesh, hull, shape and body creation helper routines
+public abstract BulletShape CreateMeshShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices );
+
+public abstract BulletShape CreateGImpactShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices );
+
+public abstract BulletShape CreateHullShape(BulletWorld world,
+ int hullCount, float[] hulls);
+
+public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms);
+
+public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
+
+public abstract BulletShape CreateConvexHullShape(BulletWorld world,
+ int indicesCount, int[] indices,
+ int verticesCount, float[] vertices );
+
+public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
+
+public abstract bool IsNativeShape(BulletShape shape);
+
+public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
+
+public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
+
+public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
+
+public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
+
+public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
+
+public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
+
+public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
+
+public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
+
+public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb);
+
+public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
+
+public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id);
+
+public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
+
+public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
+
+public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
+
+public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
+
+public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot);
+
+public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
+
+// =====================================================================================
+public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin);
+
+public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
+ float scaleFactor, float collisionMargin);
+
+// =====================================================================================
+// Constraint creation and helper routines
+public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 joinPoint,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1loc, Quaternion frame1rot,
+ Vector3 frame2loc, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 pivotinA, Vector3 pivotinB,
+ Vector3 axisInA, Vector3 axisInB,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 axisInA, Vector3 axisInB,
+ float ratio, bool disableCollisionsBetweenLinkedBodies);
+
+public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 pivotInA, Vector3 pivotInB,
+ bool disableCollisionsBetweenLinkedBodies);
+
+public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
+
+public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
+
+public abstract bool SetFrames(BulletConstraint constrain,
+ Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
+
+public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
+
+public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
+
+public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
+
+public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
+
+public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
+
+public const int HINGE_NOT_SPECIFIED = -1;
+public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation);
+
+public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse);
+
+public const int SPRING_NOT_SPECIFIED = -1;
+public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint);
+
+public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss);
+
+public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping);
+
+public const int SLIDER_LOWER_LIMIT = 0;
+public const int SLIDER_UPPER_LIMIT = 1;
+public const int SLIDER_LINEAR = 2;
+public const int SLIDER_ANGULAR = 3;
+public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val);
+
+public const int SLIDER_SET_SOFTNESS = 4;
+public const int SLIDER_SET_RESTITUTION = 5;
+public const int SLIDER_SET_DAMPING = 6;
+public const int SLIDER_SET_DIRECTION = 7;
+public const int SLIDER_SET_LIMIT = 8;
+public const int SLIDER_SET_ORTHO = 9;
+public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val);
+
+public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse);
+
+public const int SLIDER_MOTOR_VELOCITY = 10;
+public const int SLIDER_MAX_MOTOR_FORCE = 11;
+public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val);
+
+public abstract bool CalculateTransforms(BulletConstraint constrain);
+
+public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
+
+public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
+
+// =====================================================================================
+// btCollisionWorld entries
+public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
+
+public abstract void UpdateAabbs(BulletWorld world);
+
+public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
+
+public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
+
+// =====================================================================================
+// btDynamicsWorld entries
+// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
+public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
+
+public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
+
+public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj);
+
+public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
+
+public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
+// =====================================================================================
+// btCollisionObject entries
+public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
+
+public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
+
+public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
+
+public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
+
+public abstract float GetContactProcessingThreshold(BulletBody obj);
+
+public abstract bool IsStaticObject(BulletBody obj);
+
+public abstract bool IsKinematicObject(BulletBody obj);
+
+public abstract bool IsStaticOrKinematicObject(BulletBody obj);
+
+public abstract bool HasContactResponse(BulletBody obj);
+
+public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
+
+public abstract BulletShape GetCollisionShape(BulletBody obj);
+
+public abstract int GetActivationState(BulletBody obj);
+
+public abstract void SetActivationState(BulletBody obj, int state);
+
+public abstract void SetDeactivationTime(BulletBody obj, float dtime);
+
+public abstract float GetDeactivationTime(BulletBody obj);
+
+public abstract void ForceActivationState(BulletBody obj, ActivationState state);
+
+public abstract void Activate(BulletBody obj, bool forceActivation);
+
+public abstract bool IsActive(BulletBody obj);
+
+public abstract void SetRestitution(BulletBody obj, float val);
+
+public abstract float GetRestitution(BulletBody obj);
+
+public abstract void SetFriction(BulletBody obj, float val);
+
+public abstract float GetFriction(BulletBody obj);
+
+public abstract Vector3 GetPosition(BulletBody obj);
+
+public abstract Quaternion GetOrientation(BulletBody obj);
+
+public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
+
+// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
+
+// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
+
+public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
+
+public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
+
+public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
+
+public abstract float GetHitFraction(BulletBody obj);
+
+public abstract void SetHitFraction(BulletBody obj, float val);
+
+public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
+
+public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
+
+public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
+
+public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
+
+public abstract float GetCcdMotionThreshold(BulletBody obj);
+
+public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
+
+public abstract float GetCcdSweptSphereRadius(BulletBody obj);
+
+public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
+
+public abstract IntPtr GetUserPointer(BulletBody obj);
+
+public abstract void SetUserPointer(BulletBody obj, IntPtr val);
+
+// =====================================================================================
+// btRigidBody entries
+public abstract void ApplyGravity(BulletBody obj);
+
+public abstract void SetGravity(BulletBody obj, Vector3 val);
+
+public abstract Vector3 GetGravity(BulletBody obj);
+
+public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
+
+public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
+
+public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
+
+public abstract float GetLinearDamping(BulletBody obj);
+
+public abstract float GetAngularDamping(BulletBody obj);
+
+public abstract float GetLinearSleepingThreshold(BulletBody obj);
+
+public abstract void ApplyDamping(BulletBody obj, float timeStep);
+
+public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
+
+public abstract Vector3 GetLinearFactor(BulletBody obj);
+
+public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
+
+public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
+
+// Add a force to the object as if its mass is one.
+public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
+
+// Set the force being applied to the object as if its mass is one.
+public abstract void SetObjectForce(BulletBody obj, Vector3 force);
+
+public abstract Vector3 GetTotalForce(BulletBody obj);
+
+public abstract Vector3 GetTotalTorque(BulletBody obj);
+
+public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
+
+public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
+
+public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
+
+public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
+
+// Apply force at the given point. Will add torque to the object.
+public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
+
+// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
+public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
+
+// Apply impulse to the object's torque. Force is scaled by object's mass.
+public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
+
+// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
+public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
+
+public abstract void ClearForces(BulletBody obj);
+
+public abstract void ClearAllForces(BulletBody obj);
+
+public abstract void UpdateInertiaTensor(BulletBody obj);
+
+public abstract Vector3 GetLinearVelocity(BulletBody obj);
+
+public abstract Vector3 GetAngularVelocity(BulletBody obj);
+
+public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
+
+public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
+
+public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
+
+public abstract void Translate(BulletBody obj, Vector3 trans);
+
+public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
+
+public abstract bool WantsSleeping(BulletBody obj);
+
+public abstract void SetAngularFactor(BulletBody obj, float factor);
+
+public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
+
+public abstract Vector3 GetAngularFactor(BulletBody obj);
+
+public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
+
+public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
+
+public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
+
+public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
+
+public abstract int GetNumConstraintRefs(BulletBody obj);
+
+public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask);
+
+// =====================================================================================
+// btCollisionShape entries
+
+public abstract float GetAngularMotionDisc(BulletShape shape);
+
+public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
+
+public abstract bool IsPolyhedral(BulletShape shape);
+
+public abstract bool IsConvex2d(BulletShape shape);
+
+public abstract bool IsConvex(BulletShape shape);
+
+public abstract bool IsNonMoving(BulletShape shape);
+
+public abstract bool IsConcave(BulletShape shape);
+
+public abstract bool IsCompound(BulletShape shape);
+
+public abstract bool IsSoftBody(BulletShape shape);
+
+public abstract bool IsInfinite(BulletShape shape);
+
+public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
+
+public abstract Vector3 GetLocalScaling(BulletShape shape);
+
+public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
+
+public abstract int GetShapeType(BulletShape shape);
+
+public abstract void SetMargin(BulletShape shape, float val);
+
+public abstract float GetMargin(BulletShape shape);
+
+// =====================================================================================
+// Debugging
+public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
+
+public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
+
+public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
+
+public virtual void DumpActivationInfo(BulletWorld sim) { }
+
+public virtual void DumpAllInfo(BulletWorld sim) { }
+
+public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
+
+public virtual void ResetBroadphasePool(BulletWorld sim) { }
+
+public virtual void ResetConstraintSolver(BulletWorld sim) { }
+
+};
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
new file mode 100644
index 0000000..9c3f160
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
@@ -0,0 +1,813 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using log4net;
+using OMV = OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSCharacter : BSPhysObject
+{
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly string LogHeader = "[BULLETS CHAR]";
+
+ // private bool _stopped;
+ private OMV.Vector3 _size;
+ private bool _grabbed;
+ private bool _selected;
+ private float _mass;
+ private float _avatarVolume;
+ private float _collisionScore;
+ private OMV.Vector3 _acceleration;
+ private int _physicsActorType;
+ private bool _isPhysical;
+ private bool _flying;
+ private bool _setAlwaysRun;
+ private bool _throttleUpdates;
+ private bool _floatOnWater;
+ private OMV.Vector3 _rotationalVelocity;
+ private bool _kinematic;
+ private float _buoyancy;
+
+ private BSActorAvatarMove m_moveActor;
+ private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
+
+ private OMV.Vector3 _PIDTarget;
+ private float _PIDTau;
+
+// public override OMV.Vector3 RawVelocity
+// { get { return base.RawVelocity; }
+// set {
+// if (value != base.RawVelocity)
+// Util.PrintCallStack();
+// Console.WriteLine("Set rawvel to {0}", value);
+// base.RawVelocity = value; }
+// }
+
+ // Avatars are always complete (in the physics engine sense)
+ public override bool IsIncomplete { get { return false; } }
+
+ public BSCharacter(
+ uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying)
+
+ : base(parent_scene, localID, avName, "BSCharacter")
+ {
+ _physicsActorType = (int)ActorTypes.Agent;
+ RawPosition = pos;
+
+ _flying = isFlying;
+ RawOrientation = OMV.Quaternion.Identity;
+ RawVelocity = vel;
+ _buoyancy = ComputeBuoyancyFromFlying(isFlying);
+ Friction = BSParam.AvatarStandingFriction;
+ Density = BSParam.AvatarDensity;
+
+ // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
+ // replace with the default values.
+ _size = size;
+ if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
+ if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
+
+ // The dimensions of the physical capsule are kept in the scale.
+ // Physics creates a unit capsule which is scaled by the physics engine.
+ Scale = ComputeAvatarScale(_size);
+ // set _avatarVolume and _mass based on capsule size, _density and Scale
+ ComputeAvatarVolumeAndMass();
+
+ DetailLog(
+ "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
+ LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
+
+ // do actual creation in taint time
+ PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
+ {
+ DetailLog("{0},BSCharacter.create,taint", LocalID);
+
+ // New body and shape into PhysBody and PhysShape
+ PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
+
+ // The avatar's movement is controlled by this motor that speeds up and slows down
+ // the avatar seeking to reach the motor's target speed.
+ // This motor runs as a prestep action for the avatar so it will keep the avatar
+ // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
+ m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
+ PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
+
+ SetPhysicalProperties();
+
+ IsInitialized = true;
+ });
+ return;
+ }
+
+ // called when this character is being destroyed and the resources should be released
+ public override void Destroy()
+ {
+ IsInitialized = false;
+
+ base.Destroy();
+
+ DetailLog("{0},BSCharacter.Destroy", LocalID);
+ PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
+ {
+ PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
+ PhysBody.Clear();
+ PhysShape.Dereference(PhysScene);
+ PhysShape = new BSShapeNull();
+ });
+ }
+
+ private void SetPhysicalProperties()
+ {
+ PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
+
+ ForcePosition = RawPosition;
+
+ // Set the velocity
+ if (m_moveActor != null)
+ m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
+
+ ForceVelocity = RawVelocity;
+ TargetVelocity = RawVelocity;
+
+ // This will enable or disable the flying buoyancy of the avatar.
+ // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
+ Flying = _flying;
+
+ PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
+ PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
+ PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
+ PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
+ if (BSParam.CcdMotionThreshold > 0f)
+ {
+ PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
+ PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
+ }
+
+ UpdatePhysicalMassProperties(RawMass, false);
+
+ // Make so capsule does not fall over
+ PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
+
+ // The avatar mover sets some parameters.
+ PhysicalActors.Refresh();
+
+ PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
+
+ PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
+
+ // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
+ PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
+ PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
+
+ // Do this after the object has been added to the world
+ if (BSParam.AvatarToAvatarCollisionsByDefault)
+ PhysBody.collisionType = CollisionType.Avatar;
+ else
+ PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
+
+ PhysBody.ApplyCollisionMask(PhysScene);
+ }
+
+ public override void RequestPhysicsterseUpdate()
+ {
+ base.RequestPhysicsterseUpdate();
+ }
+
+ // No one calls this method so I don't know what it could possibly mean
+ public override bool Stopped { get { return false; } }
+
+ public override OMV.Vector3 Size {
+ get
+ {
+ // Avatar capsule size is kept in the scale parameter.
+ return _size;
+ }
+
+ set {
+ // This is how much the avatar size is changing. Positive means getting bigger.
+ // The avatar altitude must be adjusted for this change.
+ float heightChange = value.Z - _size.Z;
+
+ _size = value;
+ // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
+ // replace with the default values.
+ if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
+ if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
+
+ Scale = ComputeAvatarScale(_size);
+ ComputeAvatarVolumeAndMass();
+ DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
+ LocalID, _size, Scale, Density, _avatarVolume, RawMass);
+
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
+ {
+ if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
+ {
+ PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
+ UpdatePhysicalMassProperties(RawMass, true);
+
+ // Adjust the avatar's position to account for the increase/decrease in size
+ ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
+
+ // Make sure this change appears as a property update event
+ PhysScene.PE.PushUpdate(PhysBody);
+ }
+ });
+
+ }
+ }
+
+ public override PrimitiveBaseShape Shape
+ {
+ set { BaseShape = value; }
+ }
+
+ public override bool Grabbed {
+ set { _grabbed = value; }
+ }
+ public override bool Selected {
+ set { _selected = value; }
+ }
+ public override bool IsSelected
+ {
+ get { return _selected; }
+ }
+ public override void CrossingFailure() { return; }
+ public override void link(PhysicsActor obj) { return; }
+ public override void delink() { return; }
+
+ // Set motion values to zero.
+ // Do it to the properties so the values get set in the physics engine.
+ // Push the setting of the values to the viewer.
+ // Called at taint time!
+ public override void ZeroMotion(bool inTaintTime)
+ {
+ RawVelocity = OMV.Vector3.Zero;
+ _acceleration = OMV.Vector3.Zero;
+ _rotationalVelocity = OMV.Vector3.Zero;
+
+ // Zero some other properties directly into the physics engine
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ PhysScene.PE.ClearAllForces(PhysBody);
+ });
+ }
+
+ public override void ZeroAngularMotion(bool inTaintTime)
+ {
+ _rotationalVelocity = OMV.Vector3.Zero;
+
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
+ PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
+ // The next also get rid of applied linear force but the linear velocity is untouched.
+ PhysScene.PE.ClearForces(PhysBody);
+ }
+ });
+ }
+
+
+ public override void LockAngularMotion(OMV.Vector3 axis) { return; }
+
+ public override OMV.Vector3 Position {
+ get {
+ // Don't refetch the position because this function is called a zillion times
+ // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
+ return RawPosition;
+ }
+ set {
+ RawPosition = value;
+
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
+ {
+ DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
+ PositionSanityCheck();
+ ForcePosition = RawPosition;
+ });
+ }
+ }
+ public override OMV.Vector3 ForcePosition {
+ get {
+ RawPosition = PhysScene.PE.GetPosition(PhysBody);
+ return RawPosition;
+ }
+ set {
+ RawPosition = value;
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
+ }
+ }
+ }
+
+
+ // Check that the current position is sane and, if not, modify the position to make it so.
+ // Check for being below terrain or on water.
+ // Returns 'true' of the position was made sane by some action.
+ private bool PositionSanityCheck()
+ {
+ bool ret = false;
+
+ // TODO: check for out of bounds
+ if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
+ {
+ // The character is out of the known/simulated area.
+ // Force the avatar position to be within known. ScenePresence will use the position
+ // plus the velocity to decide if the avatar is moving out of the region.
+ RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
+ DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
+ return true;
+ }
+
+ // If below the ground, move the avatar up
+ float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
+ if (Position.Z < terrainHeight)
+ {
+ DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
+ RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
+ ret = true;
+ }
+ if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
+ {
+ float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
+ if (Position.Z < waterHeight)
+ {
+ RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ // A version of the sanity check that also makes sure a new position value is
+ // pushed back to the physics engine. This routine would be used by anyone
+ // who is not already pushing the value.
+ private bool PositionSanityCheck(bool inTaintTime)
+ {
+ bool ret = false;
+ if (PositionSanityCheck())
+ {
+ // The new position value must be pushed into the physics engine but we can't
+ // just assign to "Position" because of potential call loops.
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
+ {
+ DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
+ ForcePosition = RawPosition;
+ });
+ ret = true;
+ }
+ return ret;
+ }
+
+ public override float Mass { get { return _mass; } }
+
+ // used when we only want this prim's mass and not the linkset thing
+ public override float RawMass {
+ get {return _mass; }
+ }
+ public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
+ {
+ OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
+ PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
+ }
+
+ public override OMV.Vector3 Force {
+ get { return RawForce; }
+ set {
+ RawForce = value;
+ // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
+ PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
+ {
+ DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
+ if (PhysBody.HasPhysicalBody)
+ PhysScene.PE.SetObjectForce(PhysBody, RawForce);
+ });
+ }
+ }
+
+ // Avatars don't do vehicles
+ public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
+ public override void VehicleFloatParam(int param, float value) { }
+ public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
+ public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
+ public override void VehicleFlags(int param, bool remove) { }
+
+ // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
+ public override void SetVolumeDetect(int param) { return; }
+ public override bool IsVolumeDetect { get { return false; } }
+
+ public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
+ public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
+
+ // Sets the target in the motor. This starts the changing of the avatar's velocity.
+ public override OMV.Vector3 TargetVelocity
+ {
+ get
+ {
+ return base.m_targetVelocity;
+ }
+ set
+ {
+ DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
+ m_targetVelocity = value;
+ OMV.Vector3 targetVel = value;
+ if (_setAlwaysRun && !_flying)
+ targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
+
+ if (m_moveActor != null)
+ m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
+ }
+ }
+ // Directly setting velocity means this is what the user really wants now.
+ public override OMV.Vector3 Velocity {
+ get { return RawVelocity; }
+ set {
+ RawVelocity = value;
+ OMV.Vector3 vel = RawVelocity;
+
+ DetailLog("{0}: set Velocity = {1}", LocalID, value);
+
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
+ {
+ if (m_moveActor != null)
+ m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
+
+ DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
+ ForceVelocity = vel;
+ });
+ }
+ }
+
+ public override OMV.Vector3 ForceVelocity {
+ get { return RawVelocity; }
+ set {
+ PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
+// Util.PrintCallStack();
+ DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
+
+ RawVelocity = value;
+ PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
+ PhysScene.PE.Activate(PhysBody, true);
+ }
+ }
+
+ public override OMV.Vector3 Torque {
+ get { return RawTorque; }
+ set { RawTorque = value;
+ }
+ }
+
+ public override float CollisionScore {
+ get { return _collisionScore; }
+ set { _collisionScore = value;
+ }
+ }
+ public override OMV.Vector3 Acceleration {
+ get { return _acceleration; }
+ set { _acceleration = value; }
+ }
+ public override OMV.Quaternion Orientation {
+ get { return RawOrientation; }
+ set {
+ // Orientation is set zillions of times when an avatar is walking. It's like
+ // the viewer doesn't trust us.
+ if (RawOrientation != value)
+ {
+ RawOrientation = value;
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
+ {
+ // Bullet assumes we know what we are doing when forcing orientation
+ // so it lets us go against all the rules and just compensates for them later.
+ // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
+ // This keeps us from flipping the capsule over which the veiwer does not understand.
+ float oRoll, oPitch, oYaw;
+ RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
+ OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
+ // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
+ // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
+ // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
+ ForceOrientation = trimmedOrientation;
+ });
+ }
+ }
+ }
+ // Go directly to Bullet to get/set the value.
+ public override OMV.Quaternion ForceOrientation
+ {
+ get
+ {
+ RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
+ return RawOrientation;
+ }
+ set
+ {
+ RawOrientation = value;
+ if (PhysBody.HasPhysicalBody)
+ {
+ // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
+ PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
+ }
+ }
+ }
+ public override int PhysicsActorType {
+ get { return _physicsActorType; }
+ set { _physicsActorType = value;
+ }
+ }
+ public override bool IsPhysical {
+ get { return _isPhysical; }
+ set { _isPhysical = value;
+ }
+ }
+ public override bool IsSolid {
+ get { return true; }
+ }
+ public override bool IsStatic {
+ get { return false; }
+ }
+ public override bool IsPhysicallyActive {
+ get { return true; }
+ }
+ public override bool Flying {
+ get { return _flying; }
+ set {
+ _flying = value;
+
+ // simulate flying by changing the effect of gravity
+ Buoyancy = ComputeBuoyancyFromFlying(_flying);
+ }
+ }
+ // Flying is implimented by changing the avatar's buoyancy.
+ // Would this be done better with a vehicle type?
+ private float ComputeBuoyancyFromFlying(bool ifFlying) {
+ return ifFlying ? 1f : 0f;
+ }
+ public override bool
+ SetAlwaysRun {
+ get { return _setAlwaysRun; }
+ set { _setAlwaysRun = value; }
+ }
+ public override bool ThrottleUpdates {
+ get { return _throttleUpdates; }
+ set { _throttleUpdates = value; }
+ }
+ public override bool FloatOnWater {
+ set {
+ _floatOnWater = value;
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ if (_floatOnWater)
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
+ else
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
+ }
+ });
+ }
+ }
+ public override OMV.Vector3 RotationalVelocity {
+ get { return _rotationalVelocity; }
+ set { _rotationalVelocity = value; }
+ }
+ public override OMV.Vector3 ForceRotationalVelocity {
+ get { return _rotationalVelocity; }
+ set { _rotationalVelocity = value; }
+ }
+ public override bool Kinematic {
+ get { return _kinematic; }
+ set { _kinematic = value; }
+ }
+ // neg=fall quickly, 0=1g, 1=0g, pos=float up
+ public override float Buoyancy {
+ get { return _buoyancy; }
+ set { _buoyancy = value;
+ PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
+ {
+ DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
+ ForceBuoyancy = _buoyancy;
+ });
+ }
+ }
+ public override float ForceBuoyancy {
+ get { return _buoyancy; }
+ set {
+ PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
+
+ _buoyancy = value;
+ DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
+ // Buoyancy is faked by changing the gravity applied to the object
+ float grav = BSParam.Gravity * (1f - _buoyancy);
+ Gravity = new OMV.Vector3(0f, 0f, grav);
+ if (PhysBody.HasPhysicalBody)
+ PhysScene.PE.SetGravity(PhysBody, Gravity);
+ }
+ }
+
+ // Used for MoveTo
+ public override OMV.Vector3 PIDTarget {
+ set { _PIDTarget = value; }
+ }
+
+ public override bool PIDActive { get; set; }
+
+ public override float PIDTau {
+ set { _PIDTau = value; }
+ }
+
+ public override void AddForce(OMV.Vector3 force, bool pushforce)
+ {
+ // Since this force is being applied in only one step, make this a force per second.
+ OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
+ AddForce(addForce, pushforce, false);
+ }
+ public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
+ if (force.IsFinite())
+ {
+ OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
+ // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
+
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
+ {
+ // Bullet adds this central force to the total force for this tick
+ // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
+ }
+ });
+ }
+ else
+ {
+ m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
+ return;
+ }
+ }
+
+ public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
+ }
+ public override void SetMomentum(OMV.Vector3 momentum) {
+ }
+
+ private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
+ {
+ OMV.Vector3 newScale = size;
+
+ // Bullet's capsule total height is the "passed height + radius * 2";
+ // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
+ // The number we pass in for 'scaling' is the multiplier to get that base
+ // shape to be the size desired.
+ // So, when creating the scale for the avatar height, we take the passed height
+ // (size.Z) and remove the caps.
+ // An oddity of the Bullet capsule implementation is that it presumes the Y
+ // dimension is the radius of the capsule. Even though some of the code allows
+ // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
+
+ // Scale is multiplier of radius with one of "0.5"
+
+ float heightAdjust = BSParam.AvatarHeightMidFudge;
+ if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
+ {
+ const float AVATAR_LOW = 1.1f;
+ const float AVATAR_MID = 1.775f; // 1.87f
+ const float AVATAR_HI = 2.45f;
+ // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
+ float midHeightOffset = size.Z - AVATAR_MID;
+ if (midHeightOffset < 0f)
+ {
+ // Small avatar. Add the adjustment based on the distance from midheight
+ heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
+ }
+ else
+ {
+ // Large avatar. Add the adjustment based on the distance from midheight
+ heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
+ }
+ }
+ if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
+ {
+ newScale.X = size.X / 2f;
+ newScale.Y = size.Y / 2f;
+ // The total scale height is the central cylindar plus the caps on the two ends.
+ newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
+ }
+ else
+ {
+ newScale.Z = size.Z + heightAdjust;
+ }
+ // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
+
+ // If smaller than the endcaps, just fake like we're almost that small
+ if (newScale.Z < 0)
+ newScale.Z = 0.1f;
+
+ DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
+ LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
+
+ return newScale;
+ }
+
+ // set _avatarVolume and _mass based on capsule size, _density and Scale
+ private void ComputeAvatarVolumeAndMass()
+ {
+ _avatarVolume = (float)(
+ Math.PI
+ * Size.X / 2f
+ * Size.Y / 2f // the area of capsule cylinder
+ * Size.Z // times height of capsule cylinder
+ + 1.33333333f
+ * Math.PI
+ * Size.X / 2f
+ * Math.Min(Size.X, Size.Y) / 2
+ * Size.Y / 2f // plus the volume of the capsule end caps
+ );
+ _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
+ }
+
+ // The physics engine says that properties have updated. Update same and inform
+ // the world that things have changed.
+ public override void UpdateProperties(EntityProperties entprop)
+ {
+ // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
+ TriggerPreUpdatePropertyAction(ref entprop);
+
+ RawPosition = entprop.Position;
+ RawOrientation = entprop.Rotation;
+
+ // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
+ // and will send agent updates to the clients if velocity changes by more than
+ // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
+ // extra updates.
+ //
+ // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
+ // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
+ // This is most noticeable in level flight and can be seen with
+ // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
+ // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
+ // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
+ // has not yet been identified.
+ //
+ // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
+ // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
+// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
+ RawVelocity = entprop.Velocity;
+
+ _acceleration = entprop.Acceleration;
+ _rotationalVelocity = entprop.RotationalVelocity;
+
+ // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
+ if (PositionSanityCheck(true))
+ {
+ DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
+ entprop.Position = RawPosition;
+ }
+
+ // remember the current and last set values
+ LastEntityProperties = CurrentEntityProperties;
+ CurrentEntityProperties = entprop;
+
+ // Tell the linkset about value changes
+ // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
+
+ // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
+ // PhysScene.PostUpdate(this);
+
+ DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
+ LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
new file mode 100755
index 0000000..b47e9a8
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public abstract class BSConstraint : IDisposable
+{
+ private static string LogHeader = "[BULLETSIM CONSTRAINT]";
+
+ protected BulletWorld m_world;
+ protected BSScene PhysicsScene;
+ protected BulletBody m_body1;
+ protected BulletBody m_body2;
+ protected BulletConstraint m_constraint;
+ protected bool m_enabled = false;
+
+ public BulletBody Body1 { get { return m_body1; } }
+ public BulletBody Body2 { get { return m_body2; } }
+ public BulletConstraint Constraint { get { return m_constraint; } }
+ public abstract ConstraintType Type { get; }
+ public bool IsEnabled { get { return m_enabled; } }
+
+ public BSConstraint(BulletWorld world)
+ {
+ m_world = world;
+ PhysicsScene = m_world.physicsScene;
+ }
+
+ public virtual void Dispose()
+ {
+ if (m_enabled)
+ {
+ m_enabled = false;
+ if (m_constraint.HasPhysicalConstraint)
+ {
+ bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
+ m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
+ m_body1.ID,
+ m_body1.ID, m_body1.AddrString,
+ m_body2.ID, m_body2.AddrString,
+ success);
+ m_constraint.Clear();
+ }
+ }
+ }
+
+ public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high);
+ ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
+ }
+ return ret;
+ }
+
+ public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high);
+ ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
+ }
+ return ret;
+ }
+
+ public virtual bool SetSolverIterations(float cnt)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
+ ret = true;
+ }
+ return ret;
+ }
+
+ public virtual bool CalculateTransforms()
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ // Recompute the internal transforms
+ PhysicsScene.PE.CalculateTransforms(m_constraint);
+ ret = true;
+ }
+ return ret;
+ }
+
+ // Reset this constraint making sure it has all its internal structures
+ // recomputed and is enabled and ready to go.
+ public virtual bool RecomputeConstraintVariables(float mass)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ ret = CalculateTransforms();
+ if (ret)
+ {
+ // Setting an object's mass to zero (making it static like when it's selected)
+ // automatically disables the constraints.
+ // If the link is enabled, be sure to set the constraint itself to enabled.
+ PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
+ }
+ else
+ {
+ m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
+ }
+ }
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
new file mode 100755
index 0000000..7fcb75c
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public class BSConstraint6Dof : BSConstraint
+{
+ private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
+
+ public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
+
+ public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_enabled = false;
+ }
+
+ // Create a btGeneric6DofConstraint
+ public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1, Quaternion frame1rot,
+ Vector3 frame2, Quaternion frame2rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
+ frame1, frame1rot,
+ frame2, frame2rot,
+ useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+ PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
+ m_body1.ID, world.worldID,
+ obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
+ PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
+ m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ }
+
+ // 6 Dof constraint based on a midpoint between the two constrained bodies
+ public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 joinPoint,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
+ {
+ world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
+ BSScene.DetailLogZero, world.worldID,
+ obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
+ world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
+ LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
+ m_enabled = false;
+ }
+ else
+ {
+ m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
+ joinPoint,
+ useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+
+ PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
+ m_body1.ID, world.worldID, m_constraint.AddrString,
+ obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
+
+ if (!m_constraint.HasPhysicalConstraint)
+ {
+ world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
+ LogHeader, obj1.ID, obj2.ID);
+ m_enabled = false;
+ }
+ else
+ {
+ m_enabled = true;
+ }
+ }
+ }
+
+ // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object
+ public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj1; // Look out for confusion down the road
+ m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1,
+ frameInBloc, frameInBrot,
+ useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+ PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}",
+ m_body1.ID, world.worldID, obj1.ID, obj1.AddrString);
+ PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}",
+ m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies);
+ }
+
+ public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
+ ret = true;
+ }
+ return ret;
+ }
+
+ public bool SetCFMAndERP(float cfm, float erp)
+ {
+ bool ret = false;
+ if (m_enabled)
+ {
+ PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
+ PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
+ PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
+ ret = true;
+ }
+ return ret;
+ }
+
+ public bool UseFrameOffset(bool useOffset)
+ {
+ bool ret = false;
+ float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
+ if (m_enabled)
+ ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
+ return ret;
+ }
+
+ public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
+ {
+ bool ret = false;
+ float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
+ if (m_enabled)
+ {
+ ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
+ m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
+ BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
+ }
+ return ret;
+ }
+
+ public bool SetBreakingImpulseThreshold(float threshold)
+ {
+ bool ret = false;
+ if (m_enabled)
+ ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
new file mode 100755
index 0000000..5c8d94e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using log4net;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSConstraintCollection : IDisposable
+{
+ // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
+
+ delegate bool ConstraintAction(BSConstraint constrain);
+
+ private List m_constraints;
+ private BulletWorld m_world;
+
+ public BSConstraintCollection(BulletWorld world)
+ {
+ m_world = world;
+ m_constraints = new List();
+ }
+
+ public void Dispose()
+ {
+ this.Clear();
+ }
+
+ public void Clear()
+ {
+ lock (m_constraints)
+ {
+ foreach (BSConstraint cons in m_constraints)
+ {
+ cons.Dispose();
+ }
+ m_constraints.Clear();
+ }
+ }
+
+ public bool AddConstraint(BSConstraint cons)
+ {
+ lock (m_constraints)
+ {
+ // There is only one constraint between any bodies. Remove any old just to make sure.
+ RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
+
+ m_constraints.Add(cons);
+ }
+
+ return true;
+ }
+
+ // Get the constraint between two bodies. There can be only one.
+ // Return 'true' if a constraint was found.
+ public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
+ {
+ bool found = false;
+ BSConstraint foundConstraint = null;
+
+ uint lookingID1 = body1.ID;
+ uint lookingID2 = body2.ID;
+ lock (m_constraints)
+ {
+ foreach (BSConstraint constrain in m_constraints)
+ {
+ if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
+ || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
+ {
+ foundConstraint = constrain;
+ found = true;
+ break;
+ }
+ }
+ }
+ returnConstraint = foundConstraint;
+ return found;
+ }
+
+ // Remove any constraint between the passed bodies.
+ // Presumed there is only one such constraint possible.
+ // Return 'true' if a constraint was found and destroyed.
+ public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
+ {
+ bool ret = false;
+ lock (m_constraints)
+ {
+ BSConstraint constrain;
+ if (this.TryGetConstraint(body1, body2, out constrain))
+ {
+ // remove the constraint from our collection
+ ret = RemoveAndDestroyConstraint(constrain);
+ }
+ }
+
+ return ret;
+ }
+
+ // The constraint MUST exist in the collection
+ // Could be called if the constraint was previously removed.
+ // Return 'true' if the constraint was actually removed and disposed.
+ public bool RemoveAndDestroyConstraint(BSConstraint constrain)
+ {
+ bool removed = false;
+ lock (m_constraints)
+ {
+ // remove the constraint from our collection
+ removed = m_constraints.Remove(constrain);
+ }
+ // Dispose() is safe to call multiple times
+ constrain.Dispose();
+ return removed;
+ }
+
+ // Remove all constraints that reference the passed body.
+ // Return 'true' if any constraints were destroyed.
+ public bool RemoveAndDestroyConstraint(BulletBody body1)
+ {
+ List toRemove = new List();
+ uint lookingID = body1.ID;
+ lock (m_constraints)
+ {
+ foreach (BSConstraint constrain in m_constraints)
+ {
+ if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
+ {
+ toRemove.Add(constrain);
+ }
+ }
+ foreach (BSConstraint constrain in toRemove)
+ {
+ m_constraints.Remove(constrain);
+ constrain.Dispose();
+ }
+ }
+ return (toRemove.Count > 0);
+ }
+
+ public bool RecalculateAllConstraints()
+ {
+ bool ret = false;
+ lock (m_constraints)
+ {
+ foreach (BSConstraint constrain in m_constraints)
+ {
+ constrain.CalculateTransforms();
+ ret = true;
+ }
+ }
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
new file mode 100755
index 0000000..7a76a9a
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSConstraintConeTwist : BSConstraint
+{
+ public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } }
+
+ public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2,
+ frameInAloc, frameInArot, frameInBloc, frameInBrot,
+ disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+ }
+}
+
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
new file mode 100755
index 0000000..ed89f63
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintHinge.cs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSConstraintHinge : BSConstraint
+{
+ public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
+
+ public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 pivotInA, Vector3 pivotInB,
+ Vector3 axisInA, Vector3 axisInB,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
+ pivotInA, pivotInB, axisInA, axisInB,
+ useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+ }
+
+}
+
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
new file mode 100755
index 0000000..37cfa07
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSConstraintSlider : BSConstraint
+{
+ public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } }
+
+ public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frameInAloc, Quaternion frameInArot,
+ Vector3 frameInBloc, Quaternion frameInBrot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+ : base(world)
+ {
+ m_body1 = obj1;
+ m_body2 = obj2;
+ m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2,
+ frameInAloc, frameInArot, frameInBloc, frameInBrot,
+ useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+ }
+
+}
+
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
new file mode 100755
index 0000000..8e7ddff
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSConstraintSpring : BSConstraint6Dof
+{
+ public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } }
+
+ public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2,
+ Vector3 frame1Loc, Quaternion frame1Rot,
+ Vector3 frame2Loc, Quaternion frame2Rot,
+ bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
+ :base(world, obj1, obj2)
+ {
+ m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2,
+ frame1Loc, frame1Rot, frame2Loc, frame2Rot,
+ useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ m_enabled = true;
+
+ PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
+ obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
+ PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}",
+ m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
+ }
+
+ public bool SetAxisEnable(int pIndex, bool pAxisEnable)
+ {
+ PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}",
+ m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable);
+ PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable));
+ return true;
+ }
+
+ public bool SetStiffness(int pIndex, float pStiffness)
+ {
+ PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}",
+ m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness);
+ PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness);
+ return true;
+ }
+
+ public bool SetDamping(int pIndex, float pDamping)
+ {
+ PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}",
+ m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping);
+ PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping);
+ return true;
+ }
+
+ public bool SetEquilibriumPoint(int pIndex, float pEqPoint)
+ {
+ PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}",
+ m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint);
+ return true;
+ }
+
+ public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq)
+ {
+ PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}",
+ m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y);
+ PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z);
+ return true;
+ }
+
+}
+
+}
\ No newline at end of file
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
new file mode 100644
index 0000000..c6d6331
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSDynamics.cs
@@ -0,0 +1,1800 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
+ * are Copyright (c) 2009 Linden Research, Inc and are used under their license
+ * of Creative Commons Attribution-Share Alike 3.0
+ * (http://creativecommons.org/licenses/by-sa/3.0/).
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+ public sealed class BSDynamics : BSActor
+ {
+#pragma warning disable 414
+ private static string LogHeader = "[BULLETSIM VEHICLE]";
+#pragma warning restore 414
+
+ // the prim this dynamic controller belongs to
+ private BSPrimLinkable ControllingPrim { get; set; }
+
+ private bool m_haveRegisteredForSceneEvents;
+
+ // mass of the vehicle fetched each time we're calles
+ private float m_vehicleMass;
+
+ // Vehicle properties
+ public Vehicle Type { get; set; }
+
+ // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
+ private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
+ // HOVER_TERRAIN_ONLY
+ // HOVER_GLOBAL_HEIGHT
+ // NO_DEFLECTION_UP
+ // HOVER_WATER_ONLY
+ // HOVER_UP_ONLY
+ // LIMIT_MOTOR_UP
+ // LIMIT_ROLL_ONLY
+ private Vector3 m_BlockingEndPoint = Vector3.Zero;
+ private Quaternion m_RollreferenceFrame = Quaternion.Identity;
+ private Quaternion m_referenceFrame = Quaternion.Identity;
+
+ // Linear properties
+ private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
+ private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
+ private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
+ private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
+ private Vector3 m_linearFrictionTimescale = Vector3.Zero;
+ private float m_linearMotorDecayTimescale = 1;
+ private float m_linearMotorTimescale = 1;
+ private Vector3 m_lastLinearVelocityVector = Vector3.Zero;
+ private Vector3 m_lastPositionVector = Vector3.Zero;
+ // private bool m_LinearMotorSetLastFrame = false;
+ // private Vector3 m_linearMotorOffset = Vector3.Zero;
+
+ //Angular properties
+ private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
+ private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
+ // private int m_angularMotorApply = 0; // application frame counter
+ private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
+ private float m_angularMotorTimescale = 1; // motor angular velocity ramp up rate
+ private float m_angularMotorDecayTimescale = 1; // motor angular velocity decay rate
+ private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
+ private Vector3 m_lastAngularVelocity = Vector3.Zero;
+ private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
+
+ //Deflection properties
+ private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
+ private float m_angularDeflectionEfficiency = 0;
+ private float m_angularDeflectionTimescale = 0;
+ private float m_linearDeflectionEfficiency = 0;
+ private float m_linearDeflectionTimescale = 0;
+
+ //Banking properties
+ private float m_bankingEfficiency = 0;
+ private float m_bankingMix = 1;
+ private float m_bankingTimescale = 0;
+
+ //Hover and Buoyancy properties
+ private BSVMotor m_hoverMotor = new BSVMotor("Hover");
+ private float m_VhoverHeight = 0f;
+ private float m_VhoverEfficiency = 0f;
+ private float m_VhoverTimescale = 0f;
+ private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
+ // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
+ private float m_VehicleBuoyancy = 0f;
+ private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
+
+ //Attractor properties
+ private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
+ private float m_verticalAttractionEfficiency = 1.0f; // damped
+ private float m_verticalAttractionCutoff = 500f; // per the documentation
+ // Timescale > cutoff means no vert attractor.
+ private float m_verticalAttractionTimescale = 510f;
+
+ // Just some recomputed constants:
+#pragma warning disable 414
+ static readonly float TwoPI = ((float)Math.PI) * 2f;
+ static readonly float FourPI = ((float)Math.PI) * 4f;
+ static readonly float PIOverFour = ((float)Math.PI) / 4f;
+ static readonly float PIOverTwo = ((float)Math.PI) / 2f;
+#pragma warning restore 414
+
+ public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
+ : base(myScene, myPrim, actorName)
+ {
+ Type = Vehicle.TYPE_NONE;
+ m_haveRegisteredForSceneEvents = false;
+
+ ControllingPrim = myPrim as BSPrimLinkable;
+ if (ControllingPrim == null)
+ {
+ // THIS CANNOT HAPPEN!!
+ }
+ VDetailLog("{0},Creation", ControllingPrim.LocalID);
+ }
+
+ // Return 'true' if this vehicle is doing vehicle things
+ public bool IsActive
+ {
+ get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
+ }
+
+ // Return 'true' if this a vehicle that should be sitting on the ground
+ public bool IsGroundVehicle
+ {
+ get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
+ }
+
+ #region Vehicle parameter setting
+ public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
+ {
+ VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
+ float clampTemp;
+
+ switch (pParam)
+ {
+ case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
+ m_angularDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
+ break;
+ case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
+ m_angularDeflectionTimescale = ClampInRange(0.25f, pValue, 120);
+ break;
+ case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
+ m_angularMotorDecayTimescale = ClampInRange(0.25f, pValue, 120);
+ m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
+ break;
+ case Vehicle.ANGULAR_MOTOR_TIMESCALE:
+ m_angularMotorTimescale = ClampInRange(0.25f, pValue, 120);
+ m_angularMotor.TimeScale = m_angularMotorTimescale;
+ break;
+ case Vehicle.BANKING_EFFICIENCY:
+ m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
+ break;
+ case Vehicle.BANKING_MIX:
+ m_bankingMix = ClampInRange(0.01f, pValue, 1);
+ break;
+ case Vehicle.BANKING_TIMESCALE:
+ m_bankingTimescale = ClampInRange(0.25f, pValue, 120);
+ break;
+ case Vehicle.BUOYANCY:
+ m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
+ m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
+ break;
+ case Vehicle.HOVER_EFFICIENCY:
+ m_VhoverEfficiency = ClampInRange(0.01f, pValue, 1f);
+ break;
+ case Vehicle.HOVER_HEIGHT:
+ m_VhoverHeight = ClampInRange(0f, pValue, 1000000f);
+ break;
+ case Vehicle.HOVER_TIMESCALE:
+ m_VhoverTimescale = ClampInRange(0.01f, pValue, 120);
+ break;
+ case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
+ m_linearDeflectionEfficiency = ClampInRange(0f, pValue, 1f);
+ break;
+ case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
+ m_linearDeflectionTimescale = ClampInRange(0.01f, pValue, 120);
+ break;
+ case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
+ m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
+ m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
+ break;
+ case Vehicle.LINEAR_MOTOR_TIMESCALE:
+ m_linearMotorTimescale = ClampInRange(0.01f, pValue, 120);
+ m_linearMotor.TimeScale = m_linearMotorTimescale;
+ break;
+ case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
+ m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
+ m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
+ break;
+ case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
+ m_verticalAttractionTimescale = ClampInRange(0.01f, pValue, 120);
+ m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
+ break;
+
+ // These are vector properties but the engine lets you use a single float value to
+ // set all of the components to the same value
+ case Vehicle.ANGULAR_FRICTION_TIMESCALE:
+ clampTemp = ClampInRange(0.01f, pValue, 120);
+ m_angularFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
+ break;
+ case Vehicle.ANGULAR_MOTOR_DIRECTION:
+ clampTemp = ClampInRange(-TwoPI, pValue, TwoPI);
+ m_angularMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
+ m_angularMotor.Zero();
+ m_angularMotor.SetTarget(m_angularMotorDirection);
+ break;
+ case Vehicle.LINEAR_FRICTION_TIMESCALE:
+ clampTemp = ClampInRange(0.01f, pValue, 120);
+ m_linearFrictionTimescale = new Vector3(clampTemp, clampTemp, clampTemp);
+ break;
+ case Vehicle.LINEAR_MOTOR_DIRECTION:
+ clampTemp = ClampInRange(-BSParam.MaxLinearVelocity, pValue, BSParam.MaxLinearVelocity);
+ m_linearMotorDirection = new Vector3(clampTemp, clampTemp, clampTemp);
+ m_linearMotorDirectionLASTSET = new Vector3(clampTemp, clampTemp, clampTemp);
+ m_linearMotor.SetTarget(m_linearMotorDirection);
+ break;
+ case Vehicle.LINEAR_MOTOR_OFFSET:
+ clampTemp = ClampInRange(-1000, pValue, 1000);
+ m_linearMotorOffset = new Vector3(clampTemp, clampTemp, clampTemp);
+ break;
+
+ }
+ }//end ProcessFloatVehicleParam
+
+ internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
+ {
+ VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
+ switch (pParam)
+ {
+ case Vehicle.ANGULAR_FRICTION_TIMESCALE:
+ pValue.X = ClampInRange(0.25f, pValue.X, 120);
+ pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
+ pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
+ m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ break;
+ case Vehicle.ANGULAR_MOTOR_DIRECTION:
+ // Limit requested angular speed to 2 rps= 4 pi rads/sec
+ pValue.X = ClampInRange(-FourPI, pValue.X, FourPI);
+ pValue.Y = ClampInRange(-FourPI, pValue.Y, FourPI);
+ pValue.Z = ClampInRange(-FourPI, pValue.Z, FourPI);
+ m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_angularMotor.Zero();
+ m_angularMotor.SetTarget(m_angularMotorDirection);
+ break;
+ case Vehicle.LINEAR_FRICTION_TIMESCALE:
+ pValue.X = ClampInRange(0.25f, pValue.X, 120);
+ pValue.Y = ClampInRange(0.25f, pValue.Y, 120);
+ pValue.Z = ClampInRange(0.25f, pValue.Z, 120);
+ m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ break;
+ case Vehicle.LINEAR_MOTOR_DIRECTION:
+ pValue.X = ClampInRange(-BSParam.MaxLinearVelocity, pValue.X, BSParam.MaxLinearVelocity);
+ pValue.Y = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Y, BSParam.MaxLinearVelocity);
+ pValue.Z = ClampInRange(-BSParam.MaxLinearVelocity, pValue.Z, BSParam.MaxLinearVelocity);
+ m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_linearMotor.SetTarget(m_linearMotorDirection);
+ break;
+ case Vehicle.LINEAR_MOTOR_OFFSET:
+ // Not sure the correct range to limit this variable
+ pValue.X = ClampInRange(-1000, pValue.X, 1000);
+ pValue.Y = ClampInRange(-1000, pValue.Y, 1000);
+ pValue.Z = ClampInRange(-1000, pValue.Z, 1000);
+ m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ break;
+ case Vehicle.BLOCK_EXIT:
+ // Not sure the correct range to limit this variable
+ pValue.X = ClampInRange(-10000, pValue.X, 10000);
+ pValue.Y = ClampInRange(-10000, pValue.Y, 10000);
+ pValue.Z = ClampInRange(-10000, pValue.Z, 10000);
+ m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ break;
+ }
+ }//end ProcessVectorVehicleParam
+
+ internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
+ {
+ VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
+ switch (pParam)
+ {
+ case Vehicle.REFERENCE_FRAME:
+ m_referenceFrame = pValue;
+ break;
+ case Vehicle.ROLL_FRAME:
+ m_RollreferenceFrame = pValue;
+ break;
+ }
+ }//end ProcessRotationVehicleParam
+
+ internal void ProcessVehicleFlags(int pParam, bool remove)
+ {
+ VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
+ VehicleFlag parm = (VehicleFlag)pParam;
+ if (pParam == -1)
+ m_flags = (VehicleFlag)0;
+ else
+ {
+ if (remove)
+ m_flags &= ~parm;
+ else
+ m_flags |= parm;
+ }
+ }
+
+ public void ProcessTypeChange(Vehicle pType)
+ {
+ VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
+ // Set Defaults For Type
+ Type = pType;
+ switch (pType)
+ {
+ case Vehicle.TYPE_NONE:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 0;
+ m_linearMotorDecayTimescale = 0;
+ m_linearFrictionTimescale = new Vector3(0, 0, 0);
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorDecayTimescale = 0;
+ m_angularMotorTimescale = 0;
+ m_angularFrictionTimescale = new Vector3(0, 0, 0);
+
+ m_VhoverHeight = 0;
+ m_VhoverEfficiency = 0;
+ m_VhoverTimescale = 0;
+ m_VehicleBuoyancy = 0;
+
+ m_linearDeflectionEfficiency = 1;
+ m_linearDeflectionTimescale = 1;
+
+ m_angularDeflectionEfficiency = 0;
+ m_angularDeflectionTimescale = 1000;
+
+ m_verticalAttractionEfficiency = 0;
+ m_verticalAttractionTimescale = 0;
+
+ m_bankingEfficiency = 0;
+ m_bankingTimescale = 1000;
+ m_bankingMix = 1;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags = (VehicleFlag)0;
+
+ break;
+
+ case Vehicle.TYPE_SLED:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 1000;
+ m_linearMotorDecayTimescale = 120;
+ m_linearFrictionTimescale = new Vector3(30, 1, 1000);
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorTimescale = 1000;
+ m_angularMotorDecayTimescale = 120;
+ m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
+
+ m_VhoverHeight = 0;
+ m_VhoverEfficiency = 10; // TODO: this looks wrong!!
+ m_VhoverTimescale = 10;
+ m_VehicleBuoyancy = 0;
+
+ m_linearDeflectionEfficiency = 1;
+ m_linearDeflectionTimescale = 1;
+
+ m_angularDeflectionEfficiency = 1;
+ m_angularDeflectionTimescale = 1000;
+
+ m_verticalAttractionEfficiency = 0;
+ m_verticalAttractionTimescale = 0;
+
+ m_bankingEfficiency = 0;
+ m_bankingTimescale = 10;
+ m_bankingMix = 1;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
+ | VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT
+ | VehicleFlag.HOVER_UP_ONLY);
+ m_flags |= (VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.LIMIT_MOTOR_UP);
+
+ break;
+ case Vehicle.TYPE_CAR:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 1;
+ m_linearMotorDecayTimescale = 60;
+ m_linearFrictionTimescale = new Vector3(100, 2, 1000);
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorTimescale = 1;
+ m_angularMotorDecayTimescale = 0.8f;
+ m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
+
+ m_VhoverHeight = 0;
+ m_VhoverEfficiency = 0;
+ m_VhoverTimescale = 1000;
+ m_VehicleBuoyancy = 0;
+
+ m_linearDeflectionEfficiency = 1;
+ m_linearDeflectionTimescale = 2;
+
+ m_angularDeflectionEfficiency = 0;
+ m_angularDeflectionTimescale = 10;
+
+ m_verticalAttractionEfficiency = 1f;
+ m_verticalAttractionTimescale = 10f;
+
+ m_bankingEfficiency = -0.2f;
+ m_bankingMix = 1;
+ m_bankingTimescale = 1;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
+ | VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT);
+ m_flags |= (VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.LIMIT_MOTOR_UP
+ | VehicleFlag.HOVER_UP_ONLY);
+ break;
+ case Vehicle.TYPE_BOAT:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 5;
+ m_linearMotorDecayTimescale = 60;
+ m_linearFrictionTimescale = new Vector3(10, 3, 2);
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorTimescale = 4;
+ m_angularMotorDecayTimescale = 4;
+ m_angularFrictionTimescale = new Vector3(10,10,10);
+
+ m_VhoverHeight = 0;
+ m_VhoverEfficiency = 0.5f;
+ m_VhoverTimescale = 2;
+ m_VehicleBuoyancy = 1;
+
+ m_linearDeflectionEfficiency = 0.5f;
+ m_linearDeflectionTimescale = 3;
+
+ m_angularDeflectionEfficiency = 0.5f;
+ m_angularDeflectionTimescale = 5;
+
+ m_verticalAttractionEfficiency = 0.5f;
+ m_verticalAttractionTimescale = 5f;
+
+ m_bankingEfficiency = -0.3f;
+ m_bankingMix = 0.8f;
+ m_bankingTimescale = 1;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT
+ | VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.HOVER_UP_ONLY);
+ m_flags |= (VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_MOTOR_UP
+ | VehicleFlag.HOVER_WATER_ONLY);
+ break;
+ case Vehicle.TYPE_AIRPLANE:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 2;
+ m_linearMotorDecayTimescale = 60;
+ m_linearFrictionTimescale = new Vector3(200, 10, 5);
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorTimescale = 4;
+ m_angularMotorDecayTimescale = 4;
+ m_angularFrictionTimescale = new Vector3(20, 20, 20);
+
+ m_VhoverHeight = 0;
+ m_VhoverEfficiency = 0.5f;
+ m_VhoverTimescale = 1000;
+ m_VehicleBuoyancy = 0;
+
+ m_linearDeflectionEfficiency = 0.5f;
+ m_linearDeflectionTimescale = 3;
+
+ m_angularDeflectionEfficiency = 1;
+ m_angularDeflectionTimescale = 2;
+
+ m_verticalAttractionEfficiency = 0.9f;
+ m_verticalAttractionTimescale = 2f;
+
+ m_bankingEfficiency = 1;
+ m_bankingMix = 0.7f;
+ m_bankingTimescale = 2;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
+ | VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT
+ | VehicleFlag.HOVER_UP_ONLY
+ | VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_MOTOR_UP);
+ m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
+ break;
+ case Vehicle.TYPE_BALLOON:
+ m_linearMotorDirection = Vector3.Zero;
+ m_linearMotorTimescale = 5;
+ m_linearFrictionTimescale = new Vector3(5, 5, 5);
+ m_linearMotorDecayTimescale = 60;
+
+ m_angularMotorDirection = Vector3.Zero;
+ m_angularMotorTimescale = 6;
+ m_angularFrictionTimescale = new Vector3(10, 10, 10);
+ m_angularMotorDecayTimescale = 10;
+
+ m_VhoverHeight = 5;
+ m_VhoverEfficiency = 0.8f;
+ m_VhoverTimescale = 10;
+ m_VehicleBuoyancy = 1;
+
+ m_linearDeflectionEfficiency = 0;
+ m_linearDeflectionTimescale = 5;
+
+ m_angularDeflectionEfficiency = 0;
+ m_angularDeflectionTimescale = 5;
+
+ m_verticalAttractionEfficiency = 1f;
+ m_verticalAttractionTimescale = 100f;
+
+ m_bankingEfficiency = 0;
+ m_bankingMix = 0.7f;
+ m_bankingTimescale = 5;
+
+ m_referenceFrame = Quaternion.Identity;
+
+ m_referenceFrame = Quaternion.Identity;
+ m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
+ | VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_UP_ONLY
+ | VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_MOTOR_UP);
+ m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT);
+ break;
+ }
+
+ m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
+ // m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+
+ m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
+ // m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+
+ /* Not implemented
+ m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
+ BSMotor.Infinite, BSMotor.InfiniteVector,
+ m_verticalAttractionEfficiency);
+ // Z goes away and we keep X and Y
+ m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+ */
+
+ if (this.Type == Vehicle.TYPE_NONE)
+ {
+ UnregisterForSceneEvents();
+ }
+ else
+ {
+ RegisterForSceneEvents();
+ }
+
+ // Update any physical parameters based on this type.
+ Refresh();
+ }
+ #endregion // Vehicle parameter setting
+
+ // BSActor.Refresh()
+ public override void Refresh()
+ {
+ // If asking for a refresh, reset the physical parameters before the next simulation step.
+ // Called whether active or not since the active state may be updated before the next step.
+ m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
+ {
+ SetPhysicalParameters();
+ });
+ }
+
+ // Some of the properties of this prim may have changed.
+ // Do any updating needed for a vehicle
+ private void SetPhysicalParameters()
+ {
+ if (IsActive)
+ {
+ // Remember the mass so we don't have to fetch it every step
+ m_vehicleMass = ControllingPrim.TotalMass;
+
+ // Friction affects are handled by this vehicle code
+ // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
+ // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
+ ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
+ ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
+
+ // Moderate angular movement introduced by Bullet.
+ // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
+ // Maybe compute linear and angular factor and damping from params.
+ m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
+ m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
+ m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
+
+ // Vehicles report collision events so we know when it's on the ground
+ // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
+ ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
+
+ // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
+ // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
+ // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
+ // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
+ ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
+
+ // Set the gravity for the vehicle depending on the buoyancy
+ // TODO: what should be done if prim and vehicle buoyancy differ?
+ m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
+ // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
+ // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
+ ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
+
+ VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
+ ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
+ BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
+ BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
+ );
+ }
+ else
+ {
+ if (ControllingPrim.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
+ // ControllingPrim.Linkset.RemoveFromPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
+ }
+ }
+
+ // BSActor.RemoveBodyDependencies
+ public override void RemoveDependencies()
+ {
+ Refresh();
+ }
+
+ // BSActor.Release()
+ public override void Dispose()
+ {
+ VDetailLog("{0},Dispose", ControllingPrim.LocalID);
+ UnregisterForSceneEvents();
+ Type = Vehicle.TYPE_NONE;
+ Enabled = false;
+ return;
+ }
+
+ private void RegisterForSceneEvents()
+ {
+ if (!m_haveRegisteredForSceneEvents)
+ {
+ m_physicsScene.BeforeStep += this.Step;
+ m_physicsScene.AfterStep += this.PostStep;
+ ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
+ m_haveRegisteredForSceneEvents = true;
+ }
+ }
+
+ private void UnregisterForSceneEvents()
+ {
+ if (m_haveRegisteredForSceneEvents)
+ {
+ m_physicsScene.BeforeStep -= this.Step;
+ m_physicsScene.AfterStep -= this.PostStep;
+ ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
+ m_haveRegisteredForSceneEvents = false;
+ }
+ }
+
+ private void PreUpdateProperty(ref EntityProperties entprop)
+ {
+ // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
+ // TODO: handle physics introduced by Bullet with computed vehicle physics.
+ if (IsActive)
+ {
+ entprop.RotationalVelocity = Vector3.Zero;
+ }
+ }
+
+ #region Known vehicle value functions
+ // Vehicle physical parameters that we buffer from constant getting and setting.
+ // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
+ // Changing is remembered and the parameter is stored back into the physics engine only if updated.
+ // This does two things: 1) saves continuious calls into unmanaged code, and
+ // 2) signals when a physics property update must happen back to the simulator
+ // to update values modified for the vehicle.
+ private int m_knownChanged;
+ private int m_knownHas;
+ private float m_knownTerrainHeight;
+ private float m_knownWaterLevel;
+ private Vector3 m_knownPosition;
+ private Vector3 m_knownVelocity;
+ private Vector3 m_knownForce;
+ private Vector3 m_knownForceImpulse;
+ private Quaternion m_knownOrientation;
+ private Vector3 m_knownRotationalVelocity;
+ private Vector3 m_knownRotationalForce;
+ private Vector3 m_knownRotationalImpulse;
+
+ private const int m_knownChangedPosition = 1 << 0;
+ private const int m_knownChangedVelocity = 1 << 1;
+ private const int m_knownChangedForce = 1 << 2;
+ private const int m_knownChangedForceImpulse = 1 << 3;
+ private const int m_knownChangedOrientation = 1 << 4;
+ private const int m_knownChangedRotationalVelocity = 1 << 5;
+ private const int m_knownChangedRotationalForce = 1 << 6;
+ private const int m_knownChangedRotationalImpulse = 1 << 7;
+ private const int m_knownChangedTerrainHeight = 1 << 8;
+ private const int m_knownChangedWaterLevel = 1 << 9;
+
+ public void ForgetKnownVehicleProperties()
+ {
+ m_knownHas = 0;
+ m_knownChanged = 0;
+ }
+ // Push all the changed values back into the physics engine
+ public void PushKnownChanged()
+ {
+ if (m_knownChanged != 0)
+ {
+ if ((m_knownChanged & m_knownChangedPosition) != 0)
+ ControllingPrim.ForcePosition = m_knownPosition;
+
+ if ((m_knownChanged & m_knownChangedOrientation) != 0)
+ ControllingPrim.ForceOrientation = m_knownOrientation;
+
+ if ((m_knownChanged & m_knownChangedVelocity) != 0)
+ {
+ ControllingPrim.ForceVelocity = m_knownVelocity;
+ // Fake out Bullet by making it think the velocity is the same as last time.
+ // Bullet does a bunch of smoothing for changing parameters.
+ // Since the vehicle is demanding this setting, we override Bullet's smoothing
+ // by telling Bullet the value was the same last time.
+ // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
+ }
+
+ if ((m_knownChanged & m_knownChangedForce) != 0)
+ ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
+
+ if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
+ ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
+
+ if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
+ {
+ ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
+ // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
+ }
+
+ if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
+ ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
+
+ if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
+ {
+ ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
+ }
+
+ // If we set one of the values (ie, the physics engine didn't do it) we must force
+ // an UpdateProperties event to send the changes up to the simulator.
+ m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
+ }
+ m_knownChanged = 0;
+ }
+
+ // Since the computation of terrain height can be a little involved, this routine
+ // is used to fetch the height only once for each vehicle simulation step.
+ Vector3 lastRememberedHeightPos = new Vector3(-1, -1, -1);
+ private float GetTerrainHeight(Vector3 pos)
+ {
+ if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
+ {
+ lastRememberedHeightPos = pos;
+ m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
+ m_knownHas |= m_knownChangedTerrainHeight;
+ }
+ return m_knownTerrainHeight;
+ }
+
+ // Since the computation of water level can be a little involved, this routine
+ // is used ot fetch the level only once for each vehicle simulation step.
+ Vector3 lastRememberedWaterHeightPos = new Vector3(-1, -1, -1);
+ private float GetWaterLevel(Vector3 pos)
+ {
+ if ((m_knownHas & m_knownChangedWaterLevel) == 0 || pos != lastRememberedWaterHeightPos)
+ {
+ lastRememberedWaterHeightPos = pos;
+ m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
+ m_knownHas |= m_knownChangedWaterLevel;
+ }
+ return m_knownWaterLevel;
+ }
+
+ private Vector3 VehiclePosition
+ {
+ get
+ {
+ if ((m_knownHas & m_knownChangedPosition) == 0)
+ {
+ m_knownPosition = ControllingPrim.ForcePosition;
+ m_knownHas |= m_knownChangedPosition;
+ }
+ return m_knownPosition;
+ }
+ set
+ {
+ m_knownPosition = value;
+ m_knownChanged |= m_knownChangedPosition;
+ m_knownHas |= m_knownChangedPosition;
+ }
+ }
+
+ private Quaternion VehicleOrientation
+ {
+ get
+ {
+ if ((m_knownHas & m_knownChangedOrientation) == 0)
+ {
+ m_knownOrientation = ControllingPrim.ForceOrientation;
+ m_knownHas |= m_knownChangedOrientation;
+ }
+ return m_knownOrientation;
+ }
+ set
+ {
+ m_knownOrientation = value;
+ m_knownChanged |= m_knownChangedOrientation;
+ m_knownHas |= m_knownChangedOrientation;
+ }
+ }
+
+ private Vector3 VehicleVelocity
+ {
+ get
+ {
+ if ((m_knownHas & m_knownChangedVelocity) == 0)
+ {
+ m_knownVelocity = ControllingPrim.ForceVelocity;
+ m_knownHas |= m_knownChangedVelocity;
+ }
+ return m_knownVelocity;
+ }
+ set
+ {
+ m_knownVelocity = value;
+ m_knownChanged |= m_knownChangedVelocity;
+ m_knownHas |= m_knownChangedVelocity;
+ }
+ }
+
+ private void VehicleAddForce(Vector3 pForce)
+ {
+ if ((m_knownHas & m_knownChangedForce) == 0)
+ {
+ m_knownForce = Vector3.Zero;
+ m_knownHas |= m_knownChangedForce;
+ }
+ m_knownForce += pForce;
+ m_knownChanged |= m_knownChangedForce;
+ }
+
+ private void VehicleAddForceImpulse(Vector3 pImpulse)
+ {
+ if ((m_knownHas & m_knownChangedForceImpulse) == 0)
+ {
+ m_knownForceImpulse = Vector3.Zero;
+ m_knownHas |= m_knownChangedForceImpulse;
+ }
+ m_knownForceImpulse += pImpulse;
+ m_knownChanged |= m_knownChangedForceImpulse;
+ }
+
+ private Vector3 VehicleRotationalVelocity
+ {
+ get
+ {
+ if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
+ {
+ m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
+ m_knownHas |= m_knownChangedRotationalVelocity;
+ }
+ return (Vector3)m_knownRotationalVelocity;
+ }
+ set
+ {
+ m_knownRotationalVelocity = value;
+ m_knownChanged |= m_knownChangedRotationalVelocity;
+ m_knownHas |= m_knownChangedRotationalVelocity;
+ }
+ }
+ private void VehicleAddAngularForce(Vector3 aForce)
+ {
+ if ((m_knownHas & m_knownChangedRotationalForce) == 0)
+ {
+ m_knownRotationalForce = Vector3.Zero;
+ }
+ m_knownRotationalForce += aForce;
+ m_knownChanged |= m_knownChangedRotationalForce;
+ m_knownHas |= m_knownChangedRotationalForce;
+ }
+ private void VehicleAddRotationalImpulse(Vector3 pImpulse)
+ {
+ if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
+ {
+ m_knownRotationalImpulse = Vector3.Zero;
+ m_knownHas |= m_knownChangedRotationalImpulse;
+ }
+ m_knownRotationalImpulse += pImpulse;
+ m_knownChanged |= m_knownChangedRotationalImpulse;
+ }
+
+ // Vehicle relative forward velocity
+ private Vector3 VehicleForwardVelocity
+ {
+ get
+ {
+ return VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleFrameOrientation));
+ }
+ }
+
+ private float VehicleForwardSpeed
+ {
+ get
+ {
+ return VehicleForwardVelocity.X;
+ }
+ }
+ private Quaternion VehicleFrameOrientation
+ {
+ get
+ {
+ return VehicleOrientation * m_referenceFrame;
+ }
+ }
+
+ #endregion // Known vehicle value functions
+
+ // One step of the vehicle properties for the next 'pTimestep' seconds.
+ internal void Step(float pTimestep)
+ {
+ if (!IsActive) return;
+
+ ForgetKnownVehicleProperties();
+
+ MoveLinear(pTimestep);
+ MoveAngular(pTimestep);
+
+ LimitRotation(pTimestep);
+
+ // remember the position so next step we can limit absolute movement effects
+ m_lastPositionVector = VehiclePosition;
+
+ // If we forced the changing of some vehicle parameters, update the values and
+ // for the physics engine to note the changes so an UpdateProperties event will happen.
+ PushKnownChanged();
+
+ if (m_physicsScene.VehiclePhysicalLoggingEnabled)
+ m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
+
+ VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
+ ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
+ }
+
+ // Called after the simulation step
+ internal void PostStep(float pTimestep)
+ {
+ if (!IsActive) return;
+
+ if (m_physicsScene.VehiclePhysicalLoggingEnabled)
+ m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
+ }
+
+ // Apply the effect of the linear motor and other linear motions (like hover and float).
+ private void MoveLinear(float pTimestep)
+ {
+ ComputeLinearVelocity(pTimestep);
+
+ ComputeLinearDeflection(pTimestep);
+
+ ComputeLinearTerrainHeightCorrection(pTimestep);
+
+ ComputeLinearHover(pTimestep);
+
+ ComputeLinearBlockingEndPoint(pTimestep);
+
+ ComputeLinearMotorUp(pTimestep);
+
+ ApplyGravity(pTimestep);
+
+ // If not changing some axis, reduce out velocity
+ if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
+ {
+ Vector3 vel = VehicleVelocity;
+ if ((m_flags & (VehicleFlag.NO_X)) != 0)
+ {
+ vel.X = 0;
+ }
+ if ((m_flags & (VehicleFlag.NO_Y)) != 0)
+ {
+ vel.Y = 0;
+ }
+ if ((m_flags & (VehicleFlag.NO_Z)) != 0)
+ {
+ vel.Z = 0;
+ }
+ VehicleVelocity = vel;
+ }
+
+ // ==================================================================
+ // Clamp high or low velocities
+ float newVelocityLengthSq = VehicleVelocity.LengthSquared();
+ if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
+ {
+ Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
+ VehicleVelocity /= VehicleVelocity.Length();
+ VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
+ VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
+ ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
+ }
+ else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
+ {
+ Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
+ VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
+ ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
+ VehicleVelocity = Vector3.Zero;
+ }
+
+ VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
+
+ } // end MoveLinear()
+
+ public void ComputeLinearVelocity(float pTimestep)
+ {
+ // Step the motor from the current value. Get the correction needed this step.
+ Vector3 origVelW = VehicleVelocity; // DEBUG
+ Vector3 currentVelV = VehicleForwardVelocity;
+ Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
+
+ // Friction reduces vehicle motion based on absolute speed. Slow vehicle down by friction.
+ Vector3 frictionFactorV = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
+ linearMotorCorrectionV -= (currentVelV * frictionFactorV);
+
+ // Motor is vehicle coordinates. Rotate it to world coordinates
+ Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleFrameOrientation;
+
+ // If we're a ground vehicle, don't add any upward Z movement
+ if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
+ {
+ if (linearMotorVelocityW.Z > 0f)
+ linearMotorVelocityW.Z = 0f;
+ }
+
+ // Add this correction to the velocity to make it faster/slower.
+ VehicleVelocity += linearMotorVelocityW;
+
+ VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},tgt={3},correctV={4},correctW={5},newVelW={6},fricFact={7}",
+ ControllingPrim.LocalID, origVelW, currentVelV, m_linearMotor.TargetValue, linearMotorCorrectionV,
+ linearMotorVelocityW, VehicleVelocity, frictionFactorV);
+ }
+
+ //Given a Deflection Effiency and a Velocity, Returns a Velocity that is Partially Deflected onto the X Axis
+ //Clamped so that a DeflectionTimescale of less then 1 does not increase force over original velocity
+ private void ComputeLinearDeflection(float pTimestep)
+ {
+ Vector3 linearDeflectionV = Vector3.Zero;
+ Vector3 velocityV = VehicleForwardVelocity;
+
+ if (BSParam.VehicleEnableLinearDeflection)
+ {
+ // Velocity in Y and Z dimensions is movement to the side or turning.
+ // Compute deflection factor from the to the side and rotational velocity
+ linearDeflectionV.Y = SortedClampInRange(0, (velocityV.Y * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Y);
+ linearDeflectionV.Z = SortedClampInRange(0, (velocityV.Z * m_linearDeflectionEfficiency) / m_linearDeflectionTimescale, velocityV.Z);
+
+ // Velocity to the side and around is corrected and moved into the forward direction
+ linearDeflectionV.X += Math.Abs(linearDeflectionV.Y);
+ linearDeflectionV.X += Math.Abs(linearDeflectionV.Z);
+
+ // Scale the deflection to the fractional simulation time
+ linearDeflectionV *= pTimestep;
+
+ // Subtract the sideways and rotational velocity deflection factors while adding the correction forward
+ linearDeflectionV *= new Vector3(1, -1, -1);
+
+ // Correction is vehicle relative. Convert to world coordinates.
+ Vector3 linearDeflectionW = linearDeflectionV * VehicleFrameOrientation;
+
+ // Optionally, if not colliding, don't effect world downward velocity. Let falling things fall.
+ if (BSParam.VehicleLinearDeflectionNotCollidingNoZ && !m_controllingPrim.HasSomeCollision)
+ {
+ linearDeflectionW.Z = 0f;
+ }
+
+ VehicleVelocity += linearDeflectionW;
+
+ VDetailLog("{0}, MoveLinear,LinearDeflection,linDefEff={1},linDefTS={2},linDeflectionV={3}",
+ ControllingPrim.LocalID, m_linearDeflectionEfficiency, m_linearDeflectionTimescale, linearDeflectionV);
+ }
+ }
+
+ public void ComputeLinearTerrainHeightCorrection(float pTimestep)
+ {
+ // If below the terrain, move us above the ground a little.
+ // TODO: Consider taking the rotated size of the object or possibly casting a ray.
+ if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
+ {
+ // Force position because applying force won't get the vehicle through the terrain
+ Vector3 newPosition = VehiclePosition;
+ newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
+ VehiclePosition = newPosition;
+ VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
+ ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
+ }
+ }
+
+ public void ComputeLinearHover(float pTimestep)
+ {
+ // m_VhoverEfficiency: 0=bouncy, 1=totally damped
+ // m_VhoverTimescale: time to achieve height
+ if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0 && (m_VhoverHeight > 0) && (m_VhoverTimescale < 300))
+ {
+ // We should hover, get the target height
+ if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
+ {
+ m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
+ }
+ if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
+ {
+ m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
+ }
+ if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
+ {
+ m_VhoverTargetHeight = m_VhoverHeight;
+ }
+ if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
+ {
+ // If body is already heigher, use its height as target height
+ if (VehiclePosition.Z > m_VhoverTargetHeight)
+ {
+ m_VhoverTargetHeight = VehiclePosition.Z;
+
+ // A 'misfeature' of this flag is that if the vehicle is above it's hover height,
+ // the vehicle's buoyancy goes away. This is an SL bug that got used by so many
+ // scripts that it could not be changed.
+ // So, if above the height, reapply gravity if buoyancy had it turned off.
+ if (m_VehicleBuoyancy != 0)
+ {
+ Vector3 appliedGravity = ControllingPrim.ComputeGravity(ControllingPrim.Buoyancy) * m_vehicleMass;
+ VehicleAddForce(appliedGravity);
+ }
+ }
+ }
+
+ if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
+ {
+ if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
+ {
+ Vector3 pos = VehiclePosition;
+ pos.Z = m_VhoverTargetHeight;
+ VehiclePosition = pos;
+
+ VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
+ }
+ }
+ else
+ {
+ // Error is positive if below the target and negative if above.
+ Vector3 hpos = VehiclePosition;
+ float verticalError = m_VhoverTargetHeight - hpos.Z;
+ float verticalCorrection = verticalError / m_VhoverTimescale;
+ verticalCorrection *= m_VhoverEfficiency;
+
+ hpos.Z += verticalCorrection;
+ VehiclePosition = hpos;
+
+ // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
+ Vector3 vel = VehicleVelocity;
+ vel.Z = 0f;
+ VehicleVelocity = vel;
+
+ /*
+ float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
+ Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
+ verticalCorrection *= m_vehicleMass;
+
+ // TODO: implement m_VhoverEfficiency correctly
+ VehicleAddForceImpulse(verticalCorrection);
+ */
+
+ VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
+ ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
+ m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
+ verticalError, verticalCorrection);
+ }
+ }
+ }
+
+ public bool ComputeLinearBlockingEndPoint(float pTimestep)
+ {
+ bool changed = false;
+
+ Vector3 pos = VehiclePosition;
+ Vector3 posChange = pos - m_lastPositionVector;
+ if (m_BlockingEndPoint != Vector3.Zero)
+ {
+ if (pos.X >= (m_BlockingEndPoint.X - (float)1))
+ {
+ pos.X -= posChange.X + 1;
+ changed = true;
+ }
+ if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
+ {
+ pos.Y -= posChange.Y + 1;
+ changed = true;
+ }
+ if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
+ {
+ pos.Z -= posChange.Z + 1;
+ changed = true;
+ }
+ if (pos.X <= 0)
+ {
+ pos.X += posChange.X + 1;
+ changed = true;
+ }
+ if (pos.Y <= 0)
+ {
+ pos.Y += posChange.Y + 1;
+ changed = true;
+ }
+ if (changed)
+ {
+ VehiclePosition = pos;
+ VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
+ ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
+ }
+ }
+ return changed;
+ }
+
+ // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
+ // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
+ // used with conjunction with banking: the strength of the banking will decay when the
+ // vehicle no longer experiences collisions. The decay timescale is the same as
+ // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
+ // when they are in mid jump.
+ // TODO: this code is wrong. Also, what should it do for boats (height from water)?
+ // This is just using the ground and a general collision check. Should really be using
+ // a downward raycast to find what is below.
+ public void ComputeLinearMotorUp(float pTimestep)
+ {
+ if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
+ {
+ // This code tries to decide if the object is not on the ground and then pushing down
+ /*
+ float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
+ distanceAboveGround = VehiclePosition.Z - targetHeight;
+ // Not colliding if the vehicle is off the ground
+ if (!Prim.HasSomeCollision)
+ {
+ // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
+ VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
+ }
+ // TODO: this calculation is wrong. From the description at
+ // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
+ // has a decay factor. This says this force should
+ // be computed with a motor.
+ // TODO: add interaction with banking.
+ VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
+ Prim.LocalID, distanceAboveGround, Prim.HasSomeCollision, ret);
+ */
+
+ // Another approach is to measure if we're going up. If going up and not colliding,
+ // the vehicle is in the air. Fix that by pushing down.
+ if (!ControllingPrim.HasSomeCollision && VehicleVelocity.Z > 0.1)
+ {
+ // Get rid of any of the velocity vector that is pushing us up.
+ float upVelocity = VehicleVelocity.Z;
+ VehicleVelocity += new Vector3(0, 0, -upVelocity);
+
+ /*
+ // If we're pointed up into the air, we should nose down
+ Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
+ // The rotation around the Y axis is pitch up or down
+ if (pointingDirection.Y > 0.01f)
+ {
+ float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
+ Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
+ // Rotate into world coordinates and apply to vehicle
+ angularCorrectionVector *= VehicleOrientation;
+ VehicleAddAngularForce(angularCorrectionVector);
+ VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
+ Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
+ }
+ */
+ VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
+ ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, upVelocity, VehicleVelocity);
+ }
+ }
+ }
+
+ private void ApplyGravity(float pTimeStep)
+ {
+ Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
+
+ // Hack to reduce downward force if the vehicle is probably sitting on the ground
+ if (ControllingPrim.HasSomeCollision && IsGroundVehicle)
+ appliedGravity *= BSParam.VehicleGroundGravityFudge;
+
+ VehicleAddForce(appliedGravity);
+
+ VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={5}",
+ ControllingPrim.LocalID, m_VehicleGravity,
+ ControllingPrim.HasSomeCollision, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
+ }
+
+ // =======================================================================
+ // =======================================================================
+ // Apply the effect of the angular motor.
+ // The 'contribution' is how much angular correction velocity each function wants.
+ // All the contributions are added together and the resulting velocity is
+ // set directly on the vehicle.
+ private void MoveAngular(float pTimestep)
+ {
+ ComputeAngularTurning(pTimestep);
+
+ ComputeAngularVerticalAttraction();
+
+ ComputeAngularDeflection();
+
+ ComputeAngularBanking();
+
+ // ==================================================================
+ if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
+ {
+ // The vehicle is not adding anything angular wise.
+ VehicleRotationalVelocity = Vector3.Zero;
+ VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
+ }
+ else
+ {
+ VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
+ }
+
+ // ==================================================================
+ //Offset section
+ if (m_linearMotorOffset != Vector3.Zero)
+ {
+ //Offset of linear velocity doesn't change the linear velocity,
+ // but causes a torque to be applied, for example...
+ //
+ // IIIII >>> IIIII
+ // IIIII >>> IIIII
+ // IIIII >>> IIIII
+ // ^
+ // | Applying a force at the arrow will cause the object to move forward, but also rotate
+ //
+ //
+ // The torque created is the linear velocity crossed with the offset
+
+ // TODO: this computation should be in the linear section
+ // because that is where we know the impulse being applied.
+ Vector3 torqueFromOffset = Vector3.Zero;
+ // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
+ if (float.IsNaN(torqueFromOffset.X))
+ torqueFromOffset.X = 0;
+ if (float.IsNaN(torqueFromOffset.Y))
+ torqueFromOffset.Y = 0;
+ if (float.IsNaN(torqueFromOffset.Z))
+ torqueFromOffset.Z = 0;
+
+ VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
+ VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
+ }
+
+ }
+
+ private void ComputeAngularTurning(float pTimestep)
+ {
+ // The user wants this many radians per second angular change?
+ Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
+ Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleFrameOrientation);
+ Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
+
+ // ==================================================================
+ // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
+ // This flag prevents linear deflection parallel to world z-axis. This is useful
+ // for preventing ground vehicles with large linear deflection, like bumper cars,
+ // from climbing their linear deflection into the sky.
+ // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
+ // TODO: This is here because this is where ODE put it but documentation says it
+ // is a linear effect. Where should this check go?
+ //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
+ // {
+ // angularMotorContributionV.X = 0f;
+ // angularMotorContributionV.Y = 0f;
+ // }
+
+ // Reduce any velocity by friction.
+ Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
+ angularMotorContributionV -= (currentAngularV * frictionFactorW);
+
+ Vector3 angularMotorContributionW = angularMotorContributionV * VehicleFrameOrientation;
+ VehicleRotationalVelocity += angularMotorContributionW;
+
+ VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
+ ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
+ }
+
+ // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
+ // Some vehicles, like boats, should always keep their up-side up. This can be done by
+ // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
+ // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
+ // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
+ // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
+ // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
+ // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
+ public void ComputeAngularVerticalAttraction()
+ {
+
+ // If vertical attaction timescale is reasonable
+ if (BSParam.VehicleEnableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
+ {
+ Vector3 vehicleUpAxis = Vector3.UnitZ * VehicleFrameOrientation;
+ switch (BSParam.VehicleAngularVerticalAttractionAlgorithm)
+ {
+ case 0:
+ {
+ //Another formula to try got from :
+ //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
+
+ // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
+ // since only computing half the distance between the angles.
+ float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
+
+ // Make a prediction of where the up axis will be when this is applied rather then where it is now as
+ // this makes for a smoother adjustment and less fighting between the various forces.
+ Vector3 predictedUp = vehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
+
+ // This is only half the distance to the target so it will take 2 seconds to complete the turn.
+ Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
+
+ if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != 0)
+ {
+ Vector3 vehicleForwardAxis = Vector3.UnitX * VehicleFrameOrientation;
+ torqueVector = ProjectVector(torqueVector, vehicleForwardAxis);
+ }
+
+ // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
+ Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
+
+ VehicleRotationalVelocity += vertContributionV;
+
+ VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
+ ControllingPrim.LocalID,
+ verticalAttractionSpeed,
+ vehicleUpAxis,
+ predictedUp,
+ torqueVector,
+ vertContributionV);
+ break;
+ }
+ case 1:
+ {
+ // Possible solution derived from a discussion at:
+ // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
+
+ // Create a rotation that is only the vehicle's rotation around Z
+ Vector3 currentEulerW = Vector3.Zero;
+ VehicleFrameOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
+ Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
+
+ // Create the axis that is perpendicular to the up vector and the rotated up vector.
+ Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleFrameOrientation);
+ // Compute the angle between those to vectors.
+ double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation)));
+ // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
+
+ // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
+ // TODO: add 'efficiency'.
+ // differenceAngle /= m_verticalAttractionTimescale;
+
+ // Create the quaterian representing the correction angle
+ Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
+
+ // Turn that quaternion into Euler values to make it into velocities to apply.
+ Vector3 vertContributionW = Vector3.Zero;
+ correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
+ vertContributionW *= -1f;
+ vertContributionW /= m_verticalAttractionTimescale;
+
+ VehicleRotationalVelocity += vertContributionW;
+
+ VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
+ ControllingPrim.LocalID,
+ vehicleUpAxis,
+ differenceAxisW,
+ differenceAngle,
+ correctionRotationW,
+ vertContributionW);
+ break;
+ }
+ case 2:
+ {
+ Vector3 vertContributionV = Vector3.Zero;
+ Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
+
+ // Take a vector pointing up and convert it from world to vehicle relative coords.
+ Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleFrameOrientation);
+
+ // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
+ // is now:
+ // leaning to one side: rotated around the X axis with the Y value going
+ // from zero (nearly straight up) to one (completely to the side)) or
+ // leaning front-to-back: rotated around the Y axis with the value of X being between
+ // zero and one.
+ // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
+
+ // Y error means needed rotation around X axis and visa versa.
+ // Since the error goes from zero to one, the asin is the corresponding angle.
+ vertContributionV.X = (float)Math.Asin(verticalError.Y);
+ // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
+ vertContributionV.Y = -(float)Math.Asin(verticalError.X);
+
+ // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
+ if (verticalError.Z < 0f)
+ {
+ vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
+ // vertContribution.Y -= PIOverFour;
+ }
+
+ // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
+ // Correction happens over a number of seconds.
+ Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
+
+ // The correction happens over the user's time period
+ vertContributionV /= m_verticalAttractionTimescale;
+
+ // Rotate the vehicle rotation to the world coordinates.
+ VehicleRotationalVelocity += (vertContributionV * VehicleFrameOrientation);
+
+ VDetailLog("{0}, MoveAngular,verticalAttraction,,upAxis={1},origRotVW={2},vertError={3},unscaledV={4},eff={5},ts={6},vertContribV={7}",
+ ControllingPrim.LocalID,
+ vehicleUpAxis,
+ origRotVelW,
+ verticalError,
+ unscaledContribVerticalErrorV,
+ m_verticalAttractionEfficiency,
+ m_verticalAttractionTimescale,
+ vertContributionV);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ // Angular correction to correct the direction the vehicle is pointing to be
+ // the direction is should want to be pointing.
+ // The vehicle is moving in some direction and correct its orientation to it is pointing
+ // in that direction.
+ // TODO: implement reference frame.
+ public void ComputeAngularDeflection()
+ {
+
+ if (BSParam.VehicleEnableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
+ {
+ Vector3 deflectContributionV = Vector3.Zero;
+
+ // The direction the vehicle is moving
+ Vector3 movingDirection = VehicleVelocity;
+ movingDirection.Normalize();
+
+ // If the vehicle is going backward, it is still pointing forward
+ movingDirection *= Math.Sign(VehicleForwardSpeed);
+
+ // The direction the vehicle is pointing
+ Vector3 pointingDirection = Vector3.UnitX * VehicleFrameOrientation;
+ //Predict where the Vehicle will be pointing after AngularVelocity change is applied. This will keep
+ // from overshooting and allow this correction to merge with the Vertical Attraction peacefully.
+ Vector3 predictedPointingDirection = pointingDirection * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
+ predictedPointingDirection.Normalize();
+
+ // The difference between what is and what should be.
+ // Vector3 deflectionError = movingDirection - predictedPointingDirection;
+ Vector3 deflectionError = Vector3.Cross(movingDirection, predictedPointingDirection);
+
+ // Don't try to correct very large errors (not our job)
+ // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
+ // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
+ // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
+ if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
+ if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
+ if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
+
+ // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
+
+ // Scale the correction by recovery timescale and efficiency
+ // Not modeling a spring so clamp the scale to no more then the arc
+ deflectContributionV = (-deflectionError) * ClampInRange(0, m_angularDeflectionEfficiency/m_angularDeflectionTimescale,1f);
+ //deflectContributionV /= m_angularDeflectionTimescale;
+
+ VehicleRotationalVelocity += deflectContributionV;
+ VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
+ ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
+ VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3},PredictedPointingDir={4}",
+ ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale, predictedPointingDirection);
+ }
+ }
+
+ // Angular change to rotate the vehicle around the Z axis when the vehicle
+ // is tipped around the X axis.
+ // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
+ // The vertical attractor feature must be enabled in order for the banking behavior to
+ // function. The way banking works is this: a rotation around the vehicle's roll-axis will
+ // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
+ // of the yaw effect will be proportional to the
+ // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
+ // velocity along its preferred axis of motion.
+ // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
+ // positive rotation (by the right-hand rule) about the roll-axis will effect a
+ // (negative) torque around the yaw-axis, making it turn to the right--that is the
+ // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
+ // Negating the banking coefficient will make it so that the vehicle leans to the
+ // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
+ // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
+ // banking vehicles do what you want rather than what the laws of physics allow.
+ // For example, consider a real motorcycle...it must be moving forward in order for
+ // it to turn while banking, however video-game motorcycles are often configured
+ // to turn in place when at a dead stop--because they are often easier to control
+ // that way using the limited interface of the keyboard or game controller. The
+ // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
+ // banking by functioning as a slider between a banking that is correspondingly
+ // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
+ // banking effect depends only on the vehicle's rotation about its roll-axis compared
+ // to "dynamic" where the banking is also proportional to its velocity along its
+ // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
+ // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
+ // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
+ // bank quickly then give it a banking timescale of about a second or less, otherwise you can
+ // make a sluggish vehicle by giving it a timescale of several seconds.
+ public void ComputeAngularBanking()
+ {
+ if (BSParam.VehicleEnableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
+ {
+ Vector3 bankingContributionV = Vector3.Zero;
+
+ // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
+ // As the vehicle rolls to the right or left, the Y value will increase from
+ // zero (straight up) to 1 or -1 (full tilt right or left)
+ Vector3 rollComponents = Vector3.UnitZ * VehicleFrameOrientation;
+
+ // Figure out the yaw value for this much roll.
+ float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
+ // actual error = static turn error + dynamic turn error
+ float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
+
+ // TODO: the banking effect should not go to infinity but what to limit it to?
+ // And what should happen when this is being added to a user defined yaw that is already PI*4?
+ mixedYawAngle = ClampInRange(-FourPI, mixedYawAngle, FourPI);
+
+ // Build the force vector to change rotation from what it is to what it should be
+ bankingContributionV.Z = -mixedYawAngle;
+
+ // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
+ bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
+
+ VehicleRotationalVelocity += bankingContributionV;
+
+
+ VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
+ ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
+ }
+ }
+
+ // This is from previous instantiations of XXXDynamics.cs.
+ // Applies roll reference frame.
+ // TODO: is this the right way to separate the code to do this operation?
+ // Should this be in MoveAngular()?
+ internal void LimitRotation(float timestep)
+ {
+ Quaternion rotq = VehicleOrientation;
+ Quaternion m_rot = rotq;
+ if (m_RollreferenceFrame != Quaternion.Identity)
+ {
+ if (rotq.X >= m_RollreferenceFrame.X)
+ {
+ m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
+ }
+ if (rotq.Y >= m_RollreferenceFrame.Y)
+ {
+ m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
+ }
+ if (rotq.X <= -m_RollreferenceFrame.X)
+ {
+ m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
+ }
+ if (rotq.Y <= -m_RollreferenceFrame.Y)
+ {
+ m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
+ }
+ }
+ if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
+ {
+ m_rot.X = 0;
+ m_rot.Y = 0;
+ }
+ if (rotq != m_rot)
+ {
+ VehicleOrientation = m_rot;
+ VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
+ }
+
+ }
+
+ // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
+ // some value by to apply this friction.
+ private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
+ {
+ Vector3 frictionFactor = Vector3.Zero;
+ if (friction != BSMotor.InfiniteVector)
+ {
+ // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
+ // Individual friction components can be 'infinite' so compute each separately.
+ frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
+ frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
+ frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
+ frictionFactor *= pTimestep;
+ }
+ return frictionFactor;
+ }
+
+ private float SortedClampInRange(float clampa, float val, float clampb)
+ {
+ if (clampa > clampb)
+ {
+ float temp = clampa;
+ clampa = clampb;
+ clampb = temp;
+ }
+ return ClampInRange(clampa, val, clampb);
+
+ }
+
+ //Given a Vector and a unit vector will return the amount of the vector is on the same axis as the unit.
+ private Vector3 ProjectVector(Vector3 vector, Vector3 onNormal)
+ {
+ float vectorDot = Vector3.Dot(vector, onNormal);
+ return onNormal * vectorDot;
+
+ }
+
+ private float ClampInRange(float low, float val, float high)
+ {
+ return Math.Max(low, Math.Min(val, high));
+ // return Utils.Clamp(val, low, high);
+ }
+
+ // Invoke the detailed logger and output something if it's enabled.
+ private void VDetailLog(string msg, params Object[] args)
+ {
+ if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
+ ControllingPrim.PhysScene.DetailLog(msg, args);
+ }
+ }
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
new file mode 100755
index 0000000..87eba33
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public abstract class BSLinkset
+{
+ // private static string LogHeader = "[BULLETSIM LINKSET]";
+
+ public enum LinksetImplementation
+ {
+ Constraint = 0, // linkset tied together with constraints
+ Compound = 1, // linkset tied together as a compound object
+ Manual = 2 // linkset tied together manually (code moves all the pieces)
+ }
+ // Create the correct type of linkset for this child
+ public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
+ {
+ BSLinkset ret = null;
+
+ switch (parent.LinksetType)
+ {
+ case LinksetImplementation.Constraint:
+ ret = new BSLinksetConstraints(physScene, parent);
+ break;
+ case LinksetImplementation.Compound:
+ ret = new BSLinksetCompound(physScene, parent);
+ break;
+ case LinksetImplementation.Manual:
+ // ret = new BSLinksetManual(physScene, parent);
+ break;
+ default:
+ ret = new BSLinksetCompound(physScene, parent);
+ break;
+ }
+ if (ret == null)
+ {
+ physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
+ }
+ return ret;
+ }
+
+ public class BSLinkInfo
+ {
+ public BSPrimLinkable member;
+ public BSLinkInfo(BSPrimLinkable pMember)
+ {
+ member = pMember;
+ }
+ public virtual void ResetLink() { }
+ public virtual void SetLinkParameters(BSConstraint constrain) { }
+ // Returns 'true' if physical property updates from the child should be reported to the simulator
+ public virtual bool ShouldUpdateChildProperties() { return false; }
+ }
+
+ public LinksetImplementation LinksetImpl { get; protected set; }
+
+ public BSPrimLinkable LinksetRoot { get; protected set; }
+
+ protected BSScene m_physicsScene { get; private set; }
+
+ static int m_nextLinksetID = 1;
+ public int LinksetID { get; private set; }
+
+ // The children under the root in this linkset.
+ // protected HashSet m_children;
+ protected Dictionary m_children;
+
+ // We lock the diddling of linkset classes to prevent any badness.
+ // This locks the modification of the instances of this class. Changes
+ // to the physical representation is done via the tainting mechenism.
+ protected object m_linksetActivityLock = new Object();
+
+ // We keep the prim's mass in the linkset structure since it could be dependent on other prims
+ public float LinksetMass { get; protected set; }
+
+ public virtual bool LinksetIsColliding { get { return false; } }
+
+ public OMV.Vector3 CenterOfMass
+ {
+ get { return ComputeLinksetCenterOfMass(); }
+ }
+
+ public OMV.Vector3 GeometricCenter
+ {
+ get { return ComputeLinksetGeometricCenter(); }
+ }
+
+ protected BSLinkset(BSScene scene, BSPrimLinkable parent)
+ {
+ // A simple linkset of one (no children)
+ LinksetID = m_nextLinksetID++;
+ // We create LOTS of linksets.
+ if (m_nextLinksetID <= 0)
+ m_nextLinksetID = 1;
+ m_physicsScene = scene;
+ LinksetRoot = parent;
+ m_children = new Dictionary();
+ LinksetMass = parent.RawMass;
+ Rebuilding = false;
+ RebuildScheduled = false;
+
+ parent.ClearDisplacement();
+ }
+
+ // Link to a linkset where the child knows the parent.
+ // Parent changing should not happen so do some sanity checking.
+ // We return the parent's linkset so the child can track its membership.
+ // Called at runtime.
+ public BSLinkset AddMeToLinkset(BSPrimLinkable child)
+ {
+ lock (m_linksetActivityLock)
+ {
+ // Don't add the root to its own linkset
+ if (!IsRoot(child))
+ AddChildToLinkset(child);
+ LinksetMass = ComputeLinksetMass();
+ }
+ return this;
+ }
+
+ // Remove a child from a linkset.
+ // Returns a new linkset for the child which is a linkset of one (just the
+ // orphened child).
+ // Called at runtime.
+ public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
+ {
+ lock (m_linksetActivityLock)
+ {
+ if (IsRoot(child))
+ {
+ // Cannot remove the root from a linkset.
+ return this;
+ }
+ RemoveChildFromLinkset(child, inTaintTime);
+ LinksetMass = ComputeLinksetMass();
+ }
+
+ // The child is down to a linkset of just itself
+ return BSLinkset.Factory(m_physicsScene, child);
+ }
+
+ // Return 'true' if the passed object is the root object of this linkset
+ public bool IsRoot(BSPrimLinkable requestor)
+ {
+ return (requestor.LocalID == LinksetRoot.LocalID);
+ }
+
+ public int NumberOfChildren { get { return m_children.Count; } }
+
+ // Return 'true' if this linkset has any children (more than the root member)
+ public bool HasAnyChildren { get { return (m_children.Count > 0); } }
+
+ // Return 'true' if this child is in this linkset
+ public bool HasChild(BSPrimLinkable child)
+ {
+ bool ret = false;
+ lock (m_linksetActivityLock)
+ {
+ ret = m_children.ContainsKey(child);
+ }
+ return ret;
+ }
+
+ // Perform an action on each member of the linkset including root prim.
+ // Depends on the action on whether this should be done at taint time.
+ public delegate bool ForEachMemberAction(BSPrimLinkable obj);
+ public virtual bool ForEachMember(ForEachMemberAction action)
+ {
+ bool ret = false;
+ lock (m_linksetActivityLock)
+ {
+ action(LinksetRoot);
+ foreach (BSPrimLinkable po in m_children.Keys)
+ {
+ if (action(po))
+ break;
+ }
+ }
+ return ret;
+ }
+
+ public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
+ {
+ bool ret = false;
+ BSLinkInfo found = null;
+ lock (m_linksetActivityLock)
+ {
+ ret = m_children.TryGetValue(child, out found);
+ }
+ foundInfo = found;
+ return ret;
+ }
+ // Perform an action on each member of the linkset including root prim.
+ // Depends on the action on whether this should be done at taint time.
+ public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
+ public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
+ {
+ bool ret = false;
+ lock (m_linksetActivityLock)
+ {
+ foreach (BSLinkInfo po in m_children.Values)
+ {
+ if (action(po))
+ break;
+ }
+ }
+ return ret;
+ }
+
+ // Check the type of the link and return 'true' if the link is flexible and the
+ // updates from the child should be sent to the simulator so things change.
+ public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
+ {
+ bool ret = false;
+
+ BSLinkInfo linkInfo;
+ if (m_children.TryGetValue(child, out linkInfo))
+ {
+ ret = linkInfo.ShouldUpdateChildProperties();
+ }
+
+ return ret;
+ }
+
+ // Called after a simulation step to post a collision with this object.
+ // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
+ // anything to add for the collision and it should be passed through normal processing.
+ // Default processing for a linkset.
+ public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
+ OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
+ {
+ bool ret = false;
+
+ // prims in the same linkset cannot collide with each other
+ BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
+ if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
+ {
+ // By returning 'true', we tell the caller the collision has been 'handled' so it won't
+ // do anything about this collision and thus, effectivily, ignoring the collision.
+ ret = true;
+ }
+ else
+ {
+ // Not a collision between members of the linkset. Must be a real collision.
+ // So the linkset root can know if there is a collision anywhere in the linkset.
+ LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
+ }
+
+ return ret;
+ }
+
+ // I am the root of a linkset and a new child is being added
+ // Called while LinkActivity is locked.
+ protected abstract void AddChildToLinkset(BSPrimLinkable child);
+
+ // I am the root of a linkset and one of my children is being removed.
+ // Safe to call even if the child is not really in my linkset.
+ protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
+
+ // When physical properties are changed the linkset needs to recalculate
+ // its internal properties.
+ // May be called at runtime or taint-time.
+ public virtual void Refresh(BSPrimLinkable requestor)
+ {
+ LinksetMass = ComputeLinksetMass();
+ }
+
+ // Flag denoting the linkset is in the process of being rebuilt.
+ // Used to know not the schedule a rebuild in the middle of a rebuild.
+ // Because of potential update calls that could want to schedule another rebuild.
+ protected bool Rebuilding { get; set; }
+
+ // Flag saying a linkset rebuild has been scheduled.
+ // This is turned on when the rebuild is requested and turned off when
+ // the rebuild is complete. Used to limit modifications to the
+ // linkset parameters while the linkset is in an intermediate state.
+ // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
+ public bool RebuildScheduled { get; protected set; }
+
+ // The object is going dynamic (physical). Do any setup necessary
+ // for a dynamic linkset.
+ // Only the state of the passed object can be modified. The rest of the linkset
+ // has not yet been fully constructed.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public abstract bool MakeDynamic(BSPrimLinkable child);
+
+ public virtual bool AllPartsComplete
+ {
+ get {
+ bool ret = true;
+ this.ForEachMember((member) =>
+ {
+ if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
+ {
+ ret = false;
+ return true; // exit loop
+ }
+ return false; // continue loop
+ });
+ return ret;
+ }
+ }
+
+ // The object is going static (non-physical). Do any setup necessary
+ // for a static linkset.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public abstract bool MakeStatic(BSPrimLinkable child);
+
+ // Called when a parameter update comes from the physics engine for any object
+ // of the linkset is received.
+ // Passed flag is update came from physics engine (true) or the user (false).
+ // Called at taint-time!!
+ public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
+
+ // Routine used when rebuilding the body of the root of the linkset
+ // Destroy all the constraints have have been made to root.
+ // This is called when the root body is changing.
+ // Returns 'true' of something was actually removed and would need restoring
+ // Called at taint-time!!
+ public abstract bool RemoveDependencies(BSPrimLinkable child);
+
+ // ================================================================
+ // Some physical setting happen to all members of the linkset
+ public virtual void SetPhysicalFriction(float friction)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetFriction(member.PhysBody, friction);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void SetPhysicalRestitution(float restitution)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ {
+ OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
+ member.Inertia = inertia * inertiaFactor;
+ m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
+ m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
+ DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
+
+ }
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ ForEachMember((member) =>
+ {
+ if (member.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
+ return false; // 'false' says to continue looping
+ }
+ );
+ }
+ // ================================================================
+ protected virtual float ComputeLinksetMass()
+ {
+ float mass = LinksetRoot.RawMass;
+ if (HasAnyChildren)
+ {
+ lock (m_linksetActivityLock)
+ {
+ foreach (BSPrimLinkable bp in m_children.Keys)
+ {
+ mass += bp.RawMass;
+ }
+ }
+ }
+ return mass;
+ }
+
+ // Computes linkset's center of mass in world coordinates.
+ protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
+ {
+ OMV.Vector3 com;
+ lock (m_linksetActivityLock)
+ {
+ com = LinksetRoot.Position * LinksetRoot.RawMass;
+ float totalMass = LinksetRoot.RawMass;
+
+ foreach (BSPrimLinkable bp in m_children.Keys)
+ {
+ com += bp.Position * bp.RawMass;
+ totalMass += bp.RawMass;
+ }
+ if (totalMass != 0f)
+ com /= totalMass;
+ }
+
+ return com;
+ }
+
+ protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
+ {
+ OMV.Vector3 com;
+ lock (m_linksetActivityLock)
+ {
+ com = LinksetRoot.Position;
+
+ foreach (BSPrimLinkable bp in m_children.Keys)
+ {
+ com += bp.Position;
+ }
+ com /= (m_children.Count + 1);
+ }
+
+ return com;
+ }
+
+ #region Extension
+ public virtual object Extension(string pFunct, params object[] pParams)
+ {
+ return null;
+ }
+ #endregion // Extension
+
+ // Invoke the detailed logger and output something if it's enabled.
+ protected void DetailLog(string msg, params Object[] args)
+ {
+ if (m_physicsScene.PhysicsLogging.Enabled)
+ m_physicsScene.DetailLog(msg, args);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
new file mode 100755
index 0000000..cae9efa
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OpenSim.Framework;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public sealed class BSLinksetCompound : BSLinkset
+{
+#pragma warning disable 414
+ private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
+#pragma warning restore 414
+
+ public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
+ : base(scene, parent)
+ {
+ LinksetImpl = LinksetImplementation.Compound;
+ }
+
+ // ================================================================
+ // Changing the physical property of the linkset only needs to change the root
+ public override void SetPhysicalFriction(float friction)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
+ }
+ public override void SetPhysicalRestitution(float restitution)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
+ }
+ public override void SetPhysicalGravity(OMV.Vector3 gravity)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
+ }
+ public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
+ {
+ OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
+ LinksetRoot.Inertia = inertia * inertiaFactor;
+ m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
+ m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
+ }
+ public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
+ }
+ public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
+ }
+ public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
+ {
+ if (LinksetRoot.PhysBody.HasPhysicalBody)
+ m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
+ }
+ // ================================================================
+
+ // When physical properties are changed the linkset needs to recalculate
+ // its internal properties.
+ public override void Refresh(BSPrimLinkable requestor)
+ {
+ // Something changed so do the rebuilding thing
+ ScheduleRebuild(requestor);
+ base.Refresh(requestor);
+ }
+
+ // Schedule a refresh to happen after all the other taint processing.
+ private void ScheduleRebuild(BSPrimLinkable requestor)
+ {
+ // When rebuilding, it is possible to set properties that would normally require a rebuild.
+ // If already rebuilding, don't request another rebuild.
+ // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
+ lock (m_linksetActivityLock)
+ {
+ if (!RebuildScheduled && !Rebuilding && HasAnyChildren)
+ {
+ InternalScheduleRebuild(requestor);
+ }
+ }
+ }
+
+ // Must be called with m_linksetActivityLock or race conditions will haunt you.
+ private void InternalScheduleRebuild(BSPrimLinkable requestor)
+ {
+ DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}",
+ requestor.LocalID, Rebuilding, HasAnyChildren);
+ RebuildScheduled = true;
+ m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
+ {
+ if (HasAnyChildren)
+ {
+ if (this.AllPartsComplete)
+ {
+ RecomputeLinksetCompound();
+ }
+ else
+ {
+ DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete",
+ requestor.LocalID);
+ InternalScheduleRebuild(requestor);
+ }
+ }
+ RebuildScheduled = false;
+ });
+ }
+
+ // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
+ // Only the state of the passed object can be modified. The rest of the linkset
+ // has not yet been fully constructed.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public override bool MakeDynamic(BSPrimLinkable child)
+ {
+ bool ret = false;
+ DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
+ if (IsRoot(child))
+ {
+ // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
+ Refresh(LinksetRoot);
+ }
+ return ret;
+ }
+
+ // The object is going static (non-physical). We do not do anything for static linksets.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public override bool MakeStatic(BSPrimLinkable child)
+ {
+ bool ret = false;
+
+ DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
+ child.ClearDisplacement();
+ if (IsRoot(child))
+ {
+ // Schedule a rebuild to verify that the root shape is set to the real shape.
+ Refresh(LinksetRoot);
+ }
+ return ret;
+ }
+
+ // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
+ // Called at taint-time.
+ public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
+ {
+ if (!LinksetRoot.IsPhysicallyActive)
+ {
+ // No reason to do this physical stuff for static linksets.
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
+ return;
+ }
+
+ // The user moving a child around requires the rebuilding of the linkset compound shape
+ // One problem is this happens when a border is crossed -- the simulator implementation
+ // stores the position into the group which causes the move of the object
+ // but it also means all the child positions get updated.
+ // What would cause an unnecessary rebuild so we make sure the linkset is in a
+ // region before bothering to do a rebuild.
+ if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
+ {
+ // If a child of the linkset is updating only the position or rotation, that can be done
+ // without rebuilding the linkset.
+ // If a handle for the child can be fetch, we update the child here. If a rebuild was
+ // scheduled by someone else, the rebuild will just replace this setting.
+
+ bool updatedChild = false;
+ // Anything other than updating position or orientation usually means a physical update
+ // and that is caused by us updating the object.
+ if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
+ {
+ // Find the physical instance of the child
+ if (!RebuildScheduled // if rebuilding, let the rebuild do it
+ && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change
+ && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned
+ && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
+ {
+ // It is possible that the linkset is still under construction and the child is not yet
+ // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
+ // build the whole thing with the new position or rotation.
+ // The index must be checked because Bullet references the child array but does no validity
+ // checking of the child index passed.
+ int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
+ if (updated.LinksetChildIndex < numLinksetChildren)
+ {
+ BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
+ if (linksetChildShape.HasPhysicalShape)
+ {
+ // Found the child shape within the compound shape
+ m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
+ updated.RawPosition - LinksetRoot.RawPosition,
+ updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
+ true /* shouldRecalculateLocalAabb */);
+ updatedChild = true;
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
+ updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
+ }
+ else // DEBUG DEBUG
+ { // DEBUG DEBUG
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
+ updated.LocalID, linksetChildShape);
+ } // DEBUG DEBUG
+ }
+ else // DEBUG DEBUG
+ { // DEBUG DEBUG
+ // the child is not yet in the compound shape. This is non-fatal.
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
+ updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
+ } // DEBUG DEBUG
+ }
+ else // DEBUG DEBUG
+ { // DEBUG DEBUG
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
+ } // DEBUG DEBUG
+
+ if (!updatedChild)
+ {
+ // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
+ // Note: there are several ways through this code that will not update the child if
+ // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
+ // there will already be a rebuild scheduled.
+ DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
+ updated.LocalID, whichUpdated);
+ Refresh(updated);
+ }
+ }
+ }
+ }
+
+ // Routine called when rebuilding the body of some member of the linkset.
+ // If one of the bodies is being changed, the linkset needs rebuilding.
+ // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
+ // Returns 'true' of something was actually removed and would need restoring
+ // Called at taint-time!!
+ public override bool RemoveDependencies(BSPrimLinkable child)
+ {
+ bool ret = false;
+
+ DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
+ child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
+
+ Refresh(child);
+
+ return ret;
+ }
+
+ // ================================================================
+
+ // Add a new child to the linkset.
+ // Called while LinkActivity is locked.
+ protected override void AddChildToLinkset(BSPrimLinkable child)
+ {
+ if (!HasChild(child))
+ {
+ m_children.Add(child, new BSLinkInfo(child));
+
+ DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
+
+ // Rebuild the compound shape with the new child shape included
+ Refresh(child);
+ }
+ return;
+ }
+
+ // Remove the specified child from the linkset.
+ // Safe to call even if the child is not really in the linkset.
+ protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
+ {
+ child.ClearDisplacement();
+
+ if (m_children.Remove(child))
+ {
+ DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
+ child.LocalID,
+ LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
+ child.LocalID, child.PhysBody.AddrString);
+
+ // Cause the child's body to be rebuilt and thus restored to normal operation
+ child.ForceBodyShapeRebuild(inTaintTime);
+
+ if (!HasAnyChildren)
+ {
+ // The linkset is now empty. The root needs rebuilding.
+ LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
+ }
+ else
+ {
+ // Rebuild the compound shape with the child removed
+ Refresh(LinksetRoot);
+ }
+ }
+ return;
+ }
+
+ // Called before the simulation step to make sure the compound based linkset
+ // is all initialized.
+ // Constraint linksets are rebuilt every time.
+ // Note that this works for rebuilding just the root after a linkset is taken apart.
+ // Called at taint time!!
+ private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
+ private void RecomputeLinksetCompound()
+ {
+ try
+ {
+ Rebuilding = true;
+
+ // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
+ // to what they should be as if the root was not in a linkset.
+ // Not that bad since we only get into this routine if there are children in the linkset and
+ // something has been updated/changed.
+ // Have to do the rebuild before checking for physical because this might be a linkset
+ // being destructed and going non-physical.
+ LinksetRoot.ForceBodyShapeRebuild(true);
+
+ // There is no reason to build all this physical stuff for a non-physical or empty linkset.
+ if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
+ {
+ DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
+ return; // Note the 'finally' clause at the botton which will get executed.
+ }
+
+ // Get a new compound shape to build the linkset shape in.
+ BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
+
+ // Compute a displacement for each component so it is relative to the center-of-mass.
+ // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
+ OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
+
+ OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
+ OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
+
+ // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
+ OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
+ if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
+ {
+ // Zero everything if center-of-mass displacement is not being done.
+ centerDisplacementV = OMV.Vector3.Zero;
+ LinksetRoot.ClearDisplacement();
+ }
+ else
+ {
+ // The actual center-of-mass could have been set by the user.
+ centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
+ }
+
+ DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
+ LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
+
+ // Add the shapes of all the components of the linkset
+ int memberIndex = 1;
+ ForEachMember((cPrim) =>
+ {
+ if (IsRoot(cPrim))
+ {
+ // Root shape is always index zero.
+ cPrim.LinksetChildIndex = 0;
+ }
+ else
+ {
+ cPrim.LinksetChildIndex = memberIndex;
+ memberIndex++;
+ }
+
+ // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
+ BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
+
+ // Offset the child shape from the center-of-mass and rotate it to root relative.
+ OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
+ OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
+
+ // Add the child shape to the compound shape being built
+ if (childShape.physShapeInfo.HasPhysicalShape)
+ {
+ m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
+ DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
+ LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
+
+ // Since we are borrowing the shape of the child, disable the origional child body
+ if (!IsRoot(cPrim))
+ {
+ m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
+ m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
+ // We don't want collisions from the old linkset children.
+ m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+ cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
+ }
+ }
+ else
+ {
+ // The linkset must be in an intermediate state where all the children have not yet
+ // been constructed. This sometimes happens on startup when everything is getting
+ // built and some shapes have to wait for assets to be read in.
+ // Just skip this linkset for the moment and cause the shape to be rebuilt next tick.
+ // One problem might be that the shape is broken somehow and it never becomes completely
+ // available. This might cause the rebuild to happen over and over.
+ InternalScheduleRebuild(LinksetRoot);
+ DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}",
+ LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
+ // Output an annoying warning. It should only happen once but if it keeps coming out,
+ // the user knows there is something wrong and will report it.
+ m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader);
+ m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}",
+ LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape);
+
+ // This causes the loop to bail on building the rest of this linkset.
+ // The rebuild operation will fix it up next tick or declare the object unbuildable.
+ return true;
+ }
+
+ return false; // 'false' says to move onto the next child in the list
+ });
+
+ // Replace the root shape with the built compound shape.
+ // Object removed and added to world to get collision cache rebuilt for new shape.
+ LinksetRoot.PhysShape.Dereference(m_physicsScene);
+ LinksetRoot.PhysShape = linksetShape;
+ m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
+ m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
+ m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
+ DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
+ LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
+
+ // With all of the linkset packed into the root prim, it has the mass of everyone.
+ LinksetMass = ComputeLinksetMass();
+ LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
+
+ if (UseBulletSimRootOffsetHack)
+ {
+ // Enable the physical position updator to return the position and rotation of the root shape.
+ // This enables a feature in the C++ code to return the world coordinates of the first shape in the
+ // compound shape. This aleviates the need to offset the returned physical position by the
+ // center-of-mass offset.
+ // TODO: either debug this feature or remove it.
+ m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
+ }
+ }
+ finally
+ {
+ Rebuilding = false;
+ }
+
+ // See that the Aabb surrounds the new shape
+ m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
+ }
+}
+}
\ 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..4384cdc
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OpenSim.Region.OptionalModules.Scripting;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSLinksetConstraints : BSLinkset
+{
+ // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
+
+ public class BSLinkInfoConstraint : BSLinkInfo
+ {
+ public ConstraintType constraintType;
+ public BSConstraint constraint;
+ public OMV.Vector3 linearLimitLow;
+ public OMV.Vector3 linearLimitHigh;
+ public OMV.Vector3 angularLimitLow;
+ public OMV.Vector3 angularLimitHigh;
+ public bool useFrameOffset;
+ public bool enableTransMotor;
+ public float transMotorMaxVel;
+ public float transMotorMaxForce;
+ public float cfm;
+ public float erp;
+ public float solverIterations;
+ //
+ public OMV.Vector3 frameInAloc;
+ public OMV.Quaternion frameInArot;
+ public OMV.Vector3 frameInBloc;
+ public OMV.Quaternion frameInBrot;
+ public bool useLinearReferenceFrameA;
+ // Spring
+ public bool[] springAxisEnable;
+ public float[] springDamping;
+ public float[] springStiffness;
+ public OMV.Vector3 springLinearEquilibriumPoint;
+ public OMV.Vector3 springAngularEquilibriumPoint;
+
+ public BSLinkInfoConstraint(BSPrimLinkable pMember)
+ : base(pMember)
+ {
+ constraint = null;
+ ResetLink();
+ member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID);
+ }
+
+ // Set all the parameters for this constraint to a fixed, non-movable constraint.
+ public override void ResetLink()
+ {
+ // constraintType = ConstraintType.D6_CONSTRAINT_TYPE;
+ constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE;
+ linearLimitLow = OMV.Vector3.Zero;
+ linearLimitHigh = OMV.Vector3.Zero;
+ angularLimitLow = OMV.Vector3.Zero;
+ angularLimitHigh = OMV.Vector3.Zero;
+ useFrameOffset = BSParam.LinkConstraintUseFrameOffset;
+ enableTransMotor = BSParam.LinkConstraintEnableTransMotor;
+ transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel;
+ transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce;
+ cfm = BSParam.LinkConstraintCFM;
+ erp = BSParam.LinkConstraintERP;
+ solverIterations = BSParam.LinkConstraintSolverIterations;
+ frameInAloc = OMV.Vector3.Zero;
+ frameInArot = OMV.Quaternion.Identity;
+ frameInBloc = OMV.Vector3.Zero;
+ frameInBrot = OMV.Quaternion.Identity;
+ useLinearReferenceFrameA = true;
+ springAxisEnable = new bool[6];
+ springDamping = new float[6];
+ springStiffness = new float[6];
+ for (int ii = 0; ii < springAxisEnable.Length; ii++)
+ {
+ springAxisEnable[ii] = false;
+ springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
+ springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED;
+ }
+ springLinearEquilibriumPoint = OMV.Vector3.Zero;
+ springAngularEquilibriumPoint = OMV.Vector3.Zero;
+ member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID);
+ }
+
+ // Given a constraint, apply the current constraint parameters to same.
+ public override void SetLinkParameters(BSConstraint constrain)
+ {
+ member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType);
+ switch (constraintType)
+ {
+ case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
+ case ConstraintType.D6_CONSTRAINT_TYPE:
+ BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof;
+ if (constrain6dof != null)
+ {
+ // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code.
+ // zero linear and angular limits makes the objects unable to move in relation to each other
+ constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh);
+ constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh);
+
+ // tweek the constraint to increase stability
+ constrain6dof.UseFrameOffset(useFrameOffset);
+ constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
+ constrain6dof.SetCFMAndERP(cfm, erp);
+ if (solverIterations != 0f)
+ {
+ constrain6dof.SetSolverIterations(solverIterations);
+ }
+ }
+ break;
+ case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
+ BSConstraintSpring constrainSpring = constrain as BSConstraintSpring;
+ if (constrainSpring != null)
+ {
+ // zero linear and angular limits makes the objects unable to move in relation to each other
+ constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh);
+ constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh);
+
+ // tweek the constraint to increase stability
+ constrainSpring.UseFrameOffset(useFrameOffset);
+ constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce);
+ constrainSpring.SetCFMAndERP(cfm, erp);
+ if (solverIterations != 0f)
+ {
+ constrainSpring.SetSolverIterations(solverIterations);
+ }
+ for (int ii = 0; ii < springAxisEnable.Length; ii++)
+ {
+ constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]);
+ if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
+ constrainSpring.SetDamping(ii, springDamping[ii]);
+ if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED)
+ constrainSpring.SetStiffness(ii, springStiffness[ii]);
+ }
+ constrainSpring.CalculateTransforms();
+
+ if (springLinearEquilibriumPoint != OMV.Vector3.Zero)
+ constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint);
+ else
+ constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Return 'true' if the property updates from the physics engine should be reported
+ // to the simulator.
+ // If the constraint is fixed, we don't need to report as the simulator and viewer will
+ // report the right things.
+ public override bool ShouldUpdateChildProperties()
+ {
+ bool ret = true;
+ if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE)
+ ret = false;
+
+ return ret;
+ }
+ }
+
+ public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent)
+ {
+ LinksetImpl = LinksetImplementation.Constraint;
+ }
+
+ private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]";
+
+ // When physical properties are changed the linkset needs to recalculate
+ // its internal properties.
+ // This is queued in the 'post taint' queue so the
+ // refresh will happen once after all the other taints are applied.
+ public override void Refresh(BSPrimLinkable requestor)
+ {
+ ScheduleRebuild(requestor);
+ base.Refresh(requestor);
+
+ }
+
+ private void ScheduleRebuild(BSPrimLinkable requestor)
+ {
+ DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
+ requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
+
+ // When rebuilding, it is possible to set properties that would normally require a rebuild.
+ // If already rebuilding, don't request another rebuild.
+ // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
+ lock (this)
+ {
+ if (!RebuildScheduled)
+ {
+ if (!Rebuilding && HasAnyChildren)
+ {
+ RebuildScheduled = true;
+ // Queue to happen after all the other taint processing
+ m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
+ {
+ if (HasAnyChildren)
+ {
+ // Constraints that have not been changed are not rebuild but make sure
+ // the constraint of the requestor is rebuilt.
+ PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor);
+ // Rebuild the linkset and all its constraints.
+ RecomputeLinksetConstraints();
+ }
+ RebuildScheduled = false;
+ });
+ }
+ }
+ }
+ }
+
+ // The object is going dynamic (physical). Do any setup necessary
+ // for a dynamic linkset.
+ // Only the state of the passed object can be modified. The rest of the linkset
+ // has not yet been fully constructed.
+ // Return 'true' if any properties updated on the passed object.
+ // Called at taint-time!
+ public override bool MakeDynamic(BSPrimLinkable child)
+ {
+ bool ret = false;
+ DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
+ if (IsRoot(child))
+ {
+ // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
+ Refresh(LinksetRoot);
+ }
+ return ret;
+ }
+
+ // The object is going static (non-physical). Do any setup necessary for a static linkset.
+ // Return 'true' if any properties updated on the passed object.
+ // This doesn't normally happen -- OpenSim removes the objects from the physical
+ // world if it is a static linkset.
+ // Called at taint-time!
+ public override bool MakeStatic(BSPrimLinkable child)
+ {
+ bool ret = false;
+
+ DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
+ child.ClearDisplacement();
+ if (IsRoot(child))
+ {
+ // Schedule a rebuild to verify that the root shape is set to the real shape.
+ Refresh(LinksetRoot);
+ }
+ return ret;
+ }
+
+ // Called at taint-time!!
+ public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj)
+ {
+ // Nothing to do for constraints on property updates
+ }
+
+ // Routine called when rebuilding the body of some member of the linkset.
+ // Destroy all the constraints have have been made to root and set
+ // up to rebuild the constraints before the next simulation step.
+ // Returns 'true' of something was actually removed and would need restoring
+ // Called at taint-time!!
+ public override bool RemoveDependencies(BSPrimLinkable child)
+ {
+ bool ret = false;
+
+ DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}",
+ child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
+
+ lock (m_linksetActivityLock)
+ {
+ // Just undo all the constraints for this linkset. Rebuild at the end of the step.
+ ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
+ // Cause the constraints, et al to be rebuilt before the next simulation step.
+ Refresh(LinksetRoot);
+ }
+ return ret;
+ }
+
+ // ================================================================
+
+ // Add a new child to the linkset.
+ // Called while LinkActivity is locked.
+ protected override void AddChildToLinkset(BSPrimLinkable child)
+ {
+ if (!HasChild(child))
+ {
+ m_children.Add(child, new BSLinkInfoConstraint(child));
+
+ DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
+
+ // Cause constraints and assorted properties to be recomputed before the next simulation step.
+ Refresh(LinksetRoot);
+ }
+ return;
+ }
+
+ // Remove the specified child from the linkset.
+ // Safe to call even if the child is not really in my linkset.
+ protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
+ {
+ if (m_children.Remove(child))
+ {
+ BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now
+ BSPrimLinkable childx = child;
+
+ DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
+ childx.LocalID,
+ rootx.LocalID, rootx.PhysBody.AddrString,
+ childx.LocalID, childx.PhysBody.AddrString);
+
+ m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate()
+ {
+ PhysicallyUnlinkAChildFromRoot(rootx, childx);
+ });
+ // See that the linkset parameters are recomputed at the end of the taint time.
+ Refresh(LinksetRoot);
+ }
+ else
+ {
+ // Non-fatal occurance.
+ // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
+ }
+ return;
+ }
+
+ // Create a constraint between me (root of linkset) and the passed prim (the child).
+ // Called at taint time!
+ private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
+ {
+ // Don't build the constraint when asked. Put it off until just before the simulation step.
+ Refresh(rootPrim);
+ }
+
+ // Create a static constraint between the two passed objects
+ private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li)
+ {
+ BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint;
+ if (linkInfo == null)
+ return null;
+
+ // Zero motion for children so they don't interpolate
+ li.member.ZeroMotion(true);
+
+ BSConstraint constrain = null;
+
+ switch (linkInfo.constraintType)
+ {
+ case ConstraintType.BS_FIXED_CONSTRAINT_TYPE:
+ case ConstraintType.D6_CONSTRAINT_TYPE:
+ // Relative position normalized to the root prim
+ // Essentually a vector pointing from center of rootPrim to center of li.member
+ OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position;
+
+ // real world coordinate of midpoint between the two objects
+ OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
+
+ DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}",
+ rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody,
+ rootPrim.Position, linkInfo.member.Position, midPoint);
+
+ // create a constraint that allows no freedom of movement between the two objects
+ // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
+
+ constrain = new BSConstraint6Dof(
+ m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true );
+
+ /* NOTE: below is an attempt to build constraint with full frame computation, etc.
+ * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
+ * of the objects.
+ * Code left for future programmers.
+ // ==================================================================================
+ // relative position normalized to the root prim
+ OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
+ OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation;
+
+ // relative rotation of the child to the parent
+ OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation;
+ OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
+
+ DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID);
+ constrain = new BS6DofConstraint(
+ PhysicsScene.World, rootPrim.Body, liConstraint.member.Body,
+ OMV.Vector3.Zero,
+ OMV.Quaternion.Inverse(rootPrim.Orientation),
+ OMV.Vector3.Zero,
+ OMV.Quaternion.Inverse(liConstraint.member.Orientation),
+ true,
+ true
+ );
+ // ==================================================================================
+ */
+
+ break;
+ case ConstraintType.D6_SPRING_CONSTRAINT_TYPE:
+ constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody,
+ linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot,
+ linkInfo.useLinearReferenceFrameA,
+ true /*disableCollisionsBetweenLinkedBodies*/);
+ DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}",
+ rootPrim.LocalID,
+ rootPrim.LocalID, rootPrim.PhysBody.AddrString,
+ linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString,
+ rootPrim.Position, linkInfo.member.Position);
+
+ break;
+ default:
+ break;
+ }
+
+ linkInfo.SetLinkParameters(constrain);
+
+ m_physicsScene.Constraints.AddConstraint(constrain);
+
+ return constrain;
+ }
+
+ // Remove linkage between the linkset root and a particular child
+ // The root and child bodies are passed in because we need to remove the constraint between
+ // the bodies that were present at unlink time.
+ // Called at taint time!
+ private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim)
+ {
+ bool ret = false;
+ DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
+ rootPrim.LocalID,
+ rootPrim.LocalID, rootPrim.PhysBody.AddrString,
+ childPrim.LocalID, childPrim.PhysBody.AddrString);
+
+ // If asked to unlink root from root, just remove all the constraints
+ if (rootPrim == childPrim || childPrim == LinksetRoot)
+ {
+ PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
+ ret = true;
+ }
+ else
+ {
+ // Find the constraint for this link and get rid of it from the overall collection and from my list
+ if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
+ {
+ // Make the child refresh its location
+ m_physicsScene.PE.PushUpdate(childPrim.PhysBody);
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ // Remove linkage between myself and any possible children I might have.
+ // Returns 'true' of any constraints were destroyed.
+ // Called at taint time!
+ private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim)
+ {
+ DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
+
+ return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
+ }
+
+ // Call each of the constraints that make up this linkset and recompute the
+ // various transforms and variables. Create constraints of not created yet.
+ // Called before the simulation step to make sure the constraint based linkset
+ // is all initialized.
+ // Called at taint time!!
+ private void RecomputeLinksetConstraints()
+ {
+ float linksetMass = LinksetMass;
+ LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
+
+ DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
+ LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
+
+ try
+ {
+ Rebuilding = true;
+
+ // There is no reason to build all this physical stuff for a non-physical linkset.
+ if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
+ {
+ DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
+ return; // Note the 'finally' clause at the botton which will get executed.
+ }
+
+ ForEachLinkInfo((li) =>
+ {
+ // A child in the linkset physically shows the mass of the whole linkset.
+ // This allows Bullet to apply enough force on the child to move the whole linkset.
+ // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
+ li.member.UpdatePhysicalMassProperties(linksetMass, true);
+
+ BSConstraint constrain;
+ if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain))
+ {
+ // If constraint doesn't exist yet, create it.
+ constrain = BuildConstraint(LinksetRoot, li);
+ }
+ li.SetLinkParameters(constrain);
+ constrain.RecomputeConstraintVariables(linksetMass);
+
+ // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
+ return false; // 'false' says to keep processing other members
+ });
+ }
+ finally
+ {
+ Rebuilding = false;
+ }
+ }
+
+ #region Extension
+ public override object Extension(string pFunct, params object[] pParams)
+ {
+ object ret = null;
+ switch (pFunct)
+ {
+ // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
+ case ExtendedPhysics.PhysFunctChangeLinkType:
+ if (pParams.Length > 2)
+ {
+ int requestedType = (int)pParams[2];
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType);
+ if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE
+ || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE
+ || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE
+ || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE
+ || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE
+ || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE)
+ {
+ BSPrimLinkable child = pParams[1] as BSPrimLinkable;
+ if (child != null)
+ {
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}",
+ LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType);
+ m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate()
+ {
+ // Pick up all the constraints currently created.
+ RemoveDependencies(child);
+
+ BSLinkInfo linkInfo = null;
+ if (TryGetLinkInfo(child, out linkInfo))
+ {
+ BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
+ if (linkInfoC != null)
+ {
+ linkInfoC.constraintType = (ConstraintType)requestedType;
+ ret = (object)true;
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}",
+ linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
+ }
+ else
+ {
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID);
+ }
+ }
+ else
+ {
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID);
+ }
+ // Cause the whole linkset to be rebuilt in post-taint time.
+ Refresh(child);
+ });
+ }
+ else
+ {
+ DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID);
+ }
+ }
+ else
+ {
+ DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}",
+ LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE));
+ }
+ }
+ break;
+ // pParams = [ BSPhysObject root, BSPhysObject child ]
+ case ExtendedPhysics.PhysFunctGetLinkType:
+ if (pParams.Length > 0)
+ {
+ BSPrimLinkable child = pParams[1] as BSPrimLinkable;
+ if (child != null)
+ {
+ BSLinkInfo linkInfo = null;
+ if (TryGetLinkInfo(child, out linkInfo))
+ {
+ BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint;
+ if (linkInfoC != null)
+ {
+ ret = (object)(int)linkInfoC.constraintType;
+ DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}",
+ linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType);
+
+ }
+ }
+ }
+ }
+ break;
+ // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ]
+ case ExtendedPhysics.PhysFunctChangeLinkParams:
+ // There should be two parameters: the childActor and a list of parameters to set
+ if (pParams.Length > 2)
+ {
+ BSPrimLinkable child = pParams[1] as BSPrimLinkable;
+ BSLinkInfo baseLinkInfo = null;
+ if (TryGetLinkInfo(child, out baseLinkInfo))
+ {
+ BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint;
+ if (linkInfo != null)
+ {
+ int valueInt;
+ float valueFloat;
+ bool valueBool;
+ OMV.Vector3 valueVector;
+ OMV.Vector3 valueVector2;
+ OMV.Quaternion valueQuaternion;
+ int axisLow, axisHigh;
+
+ int opIndex = 2;
+ while (opIndex < pParams.Length)
+ {
+ int thisOp = 0;
+ string errMsg = "";
+ try
+ {
+ thisOp = (int)pParams[opIndex];
+ DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}",
+ linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]);
+ switch (thisOp)
+ {
+ case ExtendedPhysics.PHYS_PARAM_LINK_TYPE:
+ valueInt = (int)pParams[opIndex + 1];
+ ConstraintType valueType = (ConstraintType)valueInt;
+ if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE
+ || valueType == ConstraintType.D6_CONSTRAINT_TYPE
+ || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE
+ || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE
+ || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE
+ || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE)
+ {
+ linkInfo.constraintType = valueType;
+ }
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC:
+ errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.frameInAloc = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT:
+ errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation";
+ valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
+ linkInfo.frameInArot = valueQuaternion;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC:
+ errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.frameInBloc = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT:
+ errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation";
+ valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1];
+ linkInfo.frameInBrot = valueQuaternion;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW:
+ errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.linearLimitLow = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH:
+ errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.linearLimitHigh = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW:
+ errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.angularLimitLow = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH:
+ errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ linkInfo.angularLimitHigh = valueVector;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET:
+ errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)";
+ valueBool = ((int)pParams[opIndex + 1]) != 0;
+ linkInfo.useFrameOffset = valueBool;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR:
+ errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)";
+ valueBool = ((int)pParams[opIndex + 1]) != 0;
+ linkInfo.enableTransMotor = valueBool;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL:
+ errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float";
+ valueFloat = (float)pParams[opIndex + 1];
+ linkInfo.transMotorMaxVel = valueFloat;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE:
+ errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float";
+ valueFloat = (float)pParams[opIndex + 1];
+ linkInfo.transMotorMaxForce = valueFloat;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_CFM:
+ errMsg = "PHYS_PARAM_CFM takes one parameter of type float";
+ valueFloat = (float)pParams[opIndex + 1];
+ linkInfo.cfm = valueFloat;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_ERP:
+ errMsg = "PHYS_PARAM_ERP takes one parameter of type float";
+ valueFloat = (float)pParams[opIndex + 1];
+ linkInfo.erp = valueFloat;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS:
+ errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float";
+ valueFloat = (float)pParams[opIndex + 1];
+ linkInfo.solverIterations = valueFloat;
+ opIndex += 2;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE:
+ errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)";
+ valueInt = (int)pParams[opIndex + 1];
+ valueBool = ((int)pParams[opIndex + 2]) != 0;
+ GetAxisRange(valueInt, out axisLow, out axisHigh);
+ for (int ii = axisLow; ii <= axisHigh; ii++)
+ linkInfo.springAxisEnable[ii] = valueBool;
+ opIndex += 3;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING:
+ errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float";
+ valueInt = (int)pParams[opIndex + 1];
+ valueFloat = (float)pParams[opIndex + 2];
+ GetAxisRange(valueInt, out axisLow, out axisHigh);
+ for (int ii = axisLow; ii <= axisHigh; ii++)
+ linkInfo.springDamping[ii] = valueFloat;
+ opIndex += 3;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS:
+ errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float";
+ valueInt = (int)pParams[opIndex + 1];
+ valueFloat = (float)pParams[opIndex + 2];
+ GetAxisRange(valueInt, out axisLow, out axisHigh);
+ for (int ii = axisLow; ii <= axisHigh; ii++)
+ linkInfo.springStiffness[ii] = valueFloat;
+ opIndex += 3;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT:
+ errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector";
+ valueVector = (OMV.Vector3)pParams[opIndex + 1];
+ valueVector2 = (OMV.Vector3)pParams[opIndex + 2];
+ linkInfo.springLinearEquilibriumPoint = valueVector;
+ linkInfo.springAngularEquilibriumPoint = valueVector2;
+ opIndex += 3;
+ break;
+ case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA:
+ errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)";
+ valueBool = ((int)pParams[opIndex + 1]) != 0;
+ linkInfo.useLinearReferenceFrameA = valueBool;
+ opIndex += 2;
+ break;
+ default:
+ break;
+ }
+ }
+ catch (InvalidCastException e)
+ {
+ m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}",
+ LogHeader, errMsg, e);
+ }
+ catch (Exception e)
+ {
+ m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e);
+ }
+ }
+ }
+ // Something changed so a rebuild is in order
+ Refresh(child);
+ }
+ }
+ break;
+ default:
+ ret = base.Extension(pFunct, pParams);
+ break;
+ }
+ return ret;
+ }
+
+ // Bullet constraints keep some limit parameters for each linear and angular axis.
+ // Setting same is easier if there is an easy way to see all or types.
+ // This routine returns the array limits for the set of axis.
+ private void GetAxisRange(int rangeSpec, out int low, out int high)
+ {
+ switch (rangeSpec)
+ {
+ case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL:
+ low = 0;
+ high = 2;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL:
+ low = 3;
+ high = 5;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_ALL:
+ low = 0;
+ high = 5;
+ break;
+ default:
+ low = high = rangeSpec;
+ break;
+ }
+ return;
+ }
+ #endregion // Extension
+
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
new file mode 100755
index 0000000..ee77d6e
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using Nini.Config;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public struct MaterialAttributes
+{
+ // Material type values that correspond with definitions for LSL
+ public enum Material : int
+ {
+ Stone = 0,
+ Metal,
+ Glass,
+ Wood,
+ Flesh,
+ Plastic,
+ Rubber,
+ Light,
+ // Hereafter are BulletSim additions
+ Avatar,
+ NumberOfTypes // the count of types in the enum.
+ }
+
+ // Names must be in the order of the above enum.
+ // These names must coorespond to the lower case field names in the MaterialAttributes
+ // structure as reflection is used to select the field to put the value in.
+ public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
+
+ public MaterialAttributes(string t, float d, float f, float r)
+ {
+ type = t;
+ density = d;
+ friction = f;
+ restitution = r;
+ }
+ public string type;
+ public float density;
+ public float friction;
+ public float restitution;
+}
+
+public static class BSMaterials
+{
+ // Attributes for each material type
+ private static readonly MaterialAttributes[] Attributes;
+
+ // Map of material name to material type code
+ public static readonly Dictionary MaterialMap;
+
+ static BSMaterials()
+ {
+ // Attribute sets for both the non-physical and physical instances of materials.
+ Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
+
+ // Map of name to type code.
+ MaterialMap = new Dictionary();
+ MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
+ MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
+ MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
+ MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
+ MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
+ MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
+ MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
+ MaterialMap.Add("Light", MaterialAttributes.Material.Light);
+ MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
+ }
+
+ // This is where all the default material attributes are defined.
+ public static void InitializeFromDefaults(ConfigurationParameters parms)
+ {
+ // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
+ float dDensity = parms.defaultDensity;
+ float dFriction = parms.defaultFriction;
+ float dRestitution = parms.defaultRestitution;
+ Attributes[(int)MaterialAttributes.Material.Stone] =
+ new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
+ Attributes[(int)MaterialAttributes.Material.Metal] =
+ new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
+ Attributes[(int)MaterialAttributes.Material.Glass] =
+ new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
+ Attributes[(int)MaterialAttributes.Material.Wood] =
+ new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
+ Attributes[(int)MaterialAttributes.Material.Flesh] =
+ new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
+ Attributes[(int)MaterialAttributes.Material.Plastic] =
+ new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
+ Attributes[(int)MaterialAttributes.Material.Rubber] =
+ new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
+ Attributes[(int)MaterialAttributes.Material.Light] =
+ new MaterialAttributes("light",dDensity, dFriction, dRestitution);
+ Attributes[(int)MaterialAttributes.Material.Avatar] =
+ new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
+
+ Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
+ Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
+ Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
+ Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
+ Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
+ Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
+ Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
+ Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
+ Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
+ }
+
+ // Under the [BulletSim] section, one can change the individual material
+ // attribute values. The format of the configuration parameter is:
+ // ["Physical"] = floatValue
+ // For instance:
+ // [BulletSim]
+ // StoneFriction = 0.2
+ // FleshRestitutionPhysical = 0.8
+ // Materials can have different parameters for their static and
+ // physical instantiations. When setting the non-physical value,
+ // both values are changed. Setting the physical value only changes
+ // the physical value.
+ public static void InitializefromParameters(IConfig pConfig)
+ {
+ foreach (KeyValuePair kvp in MaterialMap)
+ {
+ string matName = kvp.Key;
+ foreach (string attribName in MaterialAttributes.MaterialAttribs)
+ {
+ string paramName = matName + attribName;
+ if (pConfig.Contains(paramName))
+ {
+ float paramValue = pConfig.GetFloat(paramName);
+ SetAttributeValue((int)kvp.Value, attribName, paramValue);
+ // set the physical value also
+ SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
+ }
+ paramName += "Physical";
+ if (pConfig.Contains(paramName))
+ {
+ float paramValue = pConfig.GetFloat(paramName);
+ SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
+ }
+ }
+ }
+ }
+
+ // Use reflection to set the value in the attribute structure.
+ private static void SetAttributeValue(int matType, string attribName, float val)
+ {
+ // Get the current attribute values for this material
+ MaterialAttributes thisAttrib = Attributes[matType];
+ // Find the field for the passed attribute name (eg, find field named 'friction')
+ FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
+ if (fieldInfo != null)
+ {
+ fieldInfo.SetValue(thisAttrib, val);
+ // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference.
+ Attributes[matType] = thisAttrib;
+ }
+ }
+
+ // Given a material type, return a structure of attributes.
+ public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
+ {
+ int ind = (int)type;
+ if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
+ return Attributes[ind];
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
new file mode 100755
index 0000000..7693195
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+using OpenSim.Framework;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public abstract class BSMotor
+{
+ // Timescales and other things can be turned off by setting them to 'infinite'.
+ public const float Infinite = 12345.6f;
+ public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
+
+ public BSMotor(string useName)
+ {
+ UseName = useName;
+ PhysicsScene = null;
+ Enabled = true;
+ }
+ public virtual bool Enabled { get; set; }
+ public virtual void Reset() { }
+ public virtual void Zero() { }
+ public virtual void GenerateTestOutput(float timeStep) { }
+
+ // A name passed at motor creation for easily identifyable debugging messages.
+ public string UseName { get; private set; }
+
+ // Used only for outputting debug information. Might not be set so check for null.
+ public BSScene PhysicsScene { get; set; }
+ protected void MDetailLog(string msg, params Object[] parms)
+ {
+ if (PhysicsScene != null)
+ {
+ PhysicsScene.DetailLog(msg, parms);
+ }
+ }
+}
+
+// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
+// The TargetValue decays in TargetValueDecayTimeScale.
+// This motor will "zero itself" over time in that the targetValue will
+// decay to zero and the currentValue will follow it to that zero.
+// The overall effect is for the returned correction value to go from large
+// values to small and eventually zero values.
+// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
+
+// For instance, if something is moving at speed X and the desired speed is Y,
+// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
+// values of CurrentValue are returned that approach the TargetValue.
+// The feature of decaying TargetValue is so vehicles will eventually
+// come to a stop rather than run forever. This can be disabled by
+// setting TargetValueDecayTimescale to 'infinite'.
+// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
+public class BSVMotor : BSMotor
+{
+ // public Vector3 FrameOfReference { get; set; }
+ // public Vector3 Offset { get; set; }
+
+ public virtual float TimeScale { get; set; }
+ public virtual float TargetValueDecayTimeScale { get; set; }
+ public virtual float Efficiency { get; set; }
+
+ public virtual float ErrorZeroThreshold { get; set; }
+
+ public virtual Vector3 TargetValue { get; protected set; }
+ public virtual Vector3 CurrentValue { get; protected set; }
+ public virtual Vector3 LastError { get; protected set; }
+
+ public virtual bool ErrorIsZero()
+ {
+ return ErrorIsZero(LastError);
+ }
+ public virtual bool ErrorIsZero(Vector3 err)
+ {
+ return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
+ }
+
+ public BSVMotor(string useName)
+ : base(useName)
+ {
+ TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
+ Efficiency = 1f;
+ CurrentValue = TargetValue = Vector3.Zero;
+ ErrorZeroThreshold = 0.001f;
+ }
+ public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency)
+ : this(useName)
+ {
+ TimeScale = timeScale;
+ TargetValueDecayTimeScale = decayTimeScale;
+ Efficiency = efficiency;
+ CurrentValue = TargetValue = Vector3.Zero;
+ }
+ public void SetCurrent(Vector3 current)
+ {
+ CurrentValue = current;
+ }
+ public void SetTarget(Vector3 target)
+ {
+ TargetValue = target;
+ }
+ public override void Zero()
+ {
+ base.Zero();
+ CurrentValue = TargetValue = Vector3.Zero;
+ }
+
+ // Compute the next step and return the new current value.
+ // Returns the correction needed to move 'current' to 'target'.
+ public virtual Vector3 Step(float timeStep)
+ {
+ if (!Enabled) return TargetValue;
+
+ Vector3 origTarget = TargetValue; // DEBUG
+ Vector3 origCurrVal = CurrentValue; // DEBUG
+
+ Vector3 correction = Vector3.Zero;
+ Vector3 error = TargetValue - CurrentValue;
+ if (!ErrorIsZero(error))
+ {
+ correction = StepError(timeStep, error);
+
+ CurrentValue += correction;
+
+ // The desired value reduces to zero which also reduces the difference with current.
+ // If the decay time is infinite, don't decay at all.
+ float decayFactor = 0f;
+ if (TargetValueDecayTimeScale != BSMotor.Infinite)
+ {
+ decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
+ TargetValue *= (1f - decayFactor);
+ }
+
+ MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
+ BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
+ timeStep, error, correction);
+ MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
+ BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
+ }
+ else
+ {
+ // Difference between what we have and target is small. Motor is done.
+ if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
+ {
+ // The target can step down to nearly zero but not get there. If close to zero
+ // it is really zero.
+ TargetValue = Vector3.Zero;
+ }
+ CurrentValue = TargetValue;
+ MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}",
+ BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue);
+ }
+ LastError = error;
+
+ return correction;
+ }
+ // version of step that sets the current value before doing the step
+ public virtual Vector3 Step(float timeStep, Vector3 current)
+ {
+ CurrentValue = current;
+ return Step(timeStep);
+ }
+ // Given and error, computer a correction for this step.
+ // Simple scaling of the error by the timestep.
+ public virtual Vector3 StepError(float timeStep, Vector3 error)
+ {
+ if (!Enabled) return Vector3.Zero;
+
+ Vector3 returnCorrection = Vector3.Zero;
+ if (!ErrorIsZero(error))
+ {
+ // correction = error / secondsItShouldTakeToCorrect
+ Vector3 correctionAmount;
+ if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
+ correctionAmount = error * timeStep;
+ else
+ correctionAmount = error / TimeScale * timeStep;
+
+ returnCorrection = correctionAmount;
+ MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
+ BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
+ }
+ return returnCorrection;
+ }
+
+ // The user sets all the parameters and calls this which outputs values until error is zero.
+ public override void GenerateTestOutput(float timeStep)
+ {
+ // maximum number of outputs to generate.
+ int maxOutput = 50;
+ MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
+ MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}",
+ BSScene.DetailLogZero, UseName,
+ TimeScale, TargetValueDecayTimeScale, Efficiency,
+ CurrentValue, TargetValue);
+
+ LastError = BSMotor.InfiniteVector;
+ while (maxOutput-- > 0 && !ErrorIsZero())
+ {
+ Vector3 lastStep = Step(timeStep);
+ MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
+ BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
+ }
+ MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
+
+
+ }
+
+ public override string ToString()
+ {
+ return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
+ UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
+ }
+}
+
+// ============================================================================
+// ============================================================================
+public class BSFMotor : BSMotor
+{
+ public virtual float TimeScale { get; set; }
+ public virtual float TargetValueDecayTimeScale { get; set; }
+ public virtual float Efficiency { get; set; }
+
+ public virtual float ErrorZeroThreshold { get; set; }
+
+ public virtual float TargetValue { get; protected set; }
+ public virtual float CurrentValue { get; protected set; }
+ public virtual float LastError { get; protected set; }
+
+ public virtual bool ErrorIsZero()
+ {
+ return ErrorIsZero(LastError);
+ }
+ public virtual bool ErrorIsZero(float err)
+ {
+ return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
+ }
+
+ public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency)
+ : base(useName)
+ {
+ TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
+ Efficiency = 1f;
+ CurrentValue = TargetValue = 0f;
+ ErrorZeroThreshold = 0.01f;
+ }
+ public void SetCurrent(float current)
+ {
+ CurrentValue = current;
+ }
+ public void SetTarget(float target)
+ {
+ TargetValue = target;
+ }
+ public override void Zero()
+ {
+ base.Zero();
+ CurrentValue = TargetValue = 0f;
+ }
+
+ public virtual float Step(float timeStep)
+ {
+ if (!Enabled) return TargetValue;
+
+ float origTarget = TargetValue; // DEBUG
+ float origCurrVal = CurrentValue; // DEBUG
+
+ float correction = 0f;
+ float error = TargetValue - CurrentValue;
+ if (!ErrorIsZero(error))
+ {
+ correction = StepError(timeStep, error);
+
+ CurrentValue += correction;
+
+ // The desired value reduces to zero which also reduces the difference with current.
+ // If the decay time is infinite, don't decay at all.
+ float decayFactor = 0f;
+ if (TargetValueDecayTimeScale != BSMotor.Infinite)
+ {
+ decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
+ TargetValue *= (1f - decayFactor);
+ }
+
+ MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
+ BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
+ timeStep, error, correction);
+ MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}",
+ BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue);
+ }
+ else
+ {
+ // Difference between what we have and target is small. Motor is done.
+ if (Util.InRange(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold))
+ {
+ // The target can step down to nearly zero but not get there. If close to zero
+ // it is really zero.
+ TargetValue = 0f;
+ }
+ CurrentValue = TargetValue;
+ MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
+ BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
+ }
+ LastError = error;
+
+ return CurrentValue;
+ }
+
+ public virtual float StepError(float timeStep, float error)
+ {
+ if (!Enabled) return 0f;
+
+ float returnCorrection = 0f;
+ if (!ErrorIsZero(error))
+ {
+ // correction = error / secondsItShouldTakeToCorrect
+ float correctionAmount;
+ if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
+ correctionAmount = error * timeStep;
+ else
+ correctionAmount = error / TimeScale * timeStep;
+
+ returnCorrection = correctionAmount;
+ MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
+ BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
+ }
+ return returnCorrection;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>",
+ UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale);
+ }
+
+}
+
+// ============================================================================
+// ============================================================================
+// Proportional, Integral, Derivitive ("PID") Motor
+// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
+public class BSPIDVMotor : BSVMotor
+{
+ // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
+ public Vector3 proportionFactor { get; set; }
+ public Vector3 integralFactor { get; set; }
+ public Vector3 derivFactor { get; set; }
+
+ // The factors are vectors for the three dimensions. This is the proportional of each
+ // that is applied. This could be multiplied through the actual factors but it
+ // is sometimes easier to manipulate the factors and their mix separately.
+ public Vector3 FactorMix;
+
+ // Arbritrary factor range.
+ // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
+ public float EfficiencyHigh = 0.4f;
+ public float EfficiencyLow = 4.0f;
+
+ // Running integration of the error
+ Vector3 RunningIntegration { get; set; }
+
+ public BSPIDVMotor(string useName)
+ : base(useName)
+ {
+ proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
+ integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
+ derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
+ FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
+ RunningIntegration = Vector3.Zero;
+ LastError = Vector3.Zero;
+ }
+
+ public override void Zero()
+ {
+ base.Zero();
+ }
+
+ public override float Efficiency
+ {
+ get { return base.Efficiency; }
+ set
+ {
+ base.Efficiency = Util.Clamp(value, 0f, 1f);
+
+ // Compute factors based on efficiency.
+ // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
+ // If efficiency is low (0f), use a factor value that overcorrects.
+ // TODO: might want to vary contribution of different factor depending on efficiency.
+ // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
+ float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
+
+ proportionFactor = new Vector3(factor, factor, factor);
+ integralFactor = new Vector3(factor, factor, factor);
+ derivFactor = new Vector3(factor, factor, factor);
+
+ MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
+ }
+ }
+
+ // Advance the PID computation on this error.
+ public override Vector3 StepError(float timeStep, Vector3 error)
+ {
+ if (!Enabled) return Vector3.Zero;
+
+ // Add up the error so we can integrate over the accumulated errors
+ RunningIntegration += error * timeStep;
+
+ // A simple derivitive is the rate of change from the last error.
+ Vector3 derivitive = (error - LastError) * timeStep;
+
+ // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
+ Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X
+ + RunningIntegration / TimeScale * integralFactor * FactorMix.Y
+ + derivitive / TimeScale * derivFactor * FactorMix.Z
+ ;
+
+ MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}",
+ BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret);
+
+ return ret;
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
new file mode 100755
index 0000000..6d46fe6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs
@@ -0,0 +1,927 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+using OpenSim.Region.Physics.Manager;
+
+using OpenMetaverse;
+using Nini.Config;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public static class BSParam
+{
+ private static string LogHeader = "[BULLETSIM PARAMETERS]";
+
+ // Tuning notes:
+ // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575
+ // Contact points can be added even if the distance is positive. The constraint solver can deal with
+ // contacts with positive distances as well as negative (penetration). Contact points are discarded
+ // if the distance exceeds a certain threshold.
+ // Bullet has a contact processing threshold and a contact breaking threshold.
+ // If the distance is larger than the contact breaking threshold, it will be removed after one frame.
+ // If the distance is larger than the contact processing threshold, the constraint solver will ignore it.
+
+ // This is separate/independent from the collision margin. The collision margin increases the object a bit
+ // to improve collision detection performance and accuracy.
+ // ===================
+ // From:
+
+ ///
+ /// Set whether physics is active or not.
+ ///
+ ///
+ /// Can be enabled and disabled to start and stop physics.
+ ///
+ public static bool Active { get; private set; }
+
+ public static bool UseSeparatePhysicsThread { get; private set; }
+ public static float PhysicsTimeStep { get; private set; }
+
+ // Level of Detail values kept as float because that's what the Meshmerizer wants
+ public static float MeshLOD { get; private set; }
+ public static float MeshCircularLOD { get; private set; }
+ public static float MeshMegaPrimLOD { get; private set; }
+ public static float MeshMegaPrimThreshold { get; private set; }
+ public static float SculptLOD { get; private set; }
+
+ public static int CrossingFailuresBeforeOutOfBounds { get; private set; }
+ public static float UpdateVelocityChangeThreshold { get; private set; }
+
+ public static float MinimumObjectMass { get; private set; }
+ public static float MaximumObjectMass { get; private set; }
+ public static float MaxLinearVelocity { get; private set; }
+ public static float MaxLinearVelocitySquared { get; private set; }
+ public static float MaxAngularVelocity { get; private set; }
+ public static float MaxAngularVelocitySquared { get; private set; }
+ public static float MaxAddForceMagnitude { get; private set; }
+ public static float MaxAddForceMagnitudeSquared { get; private set; }
+ public static float DensityScaleFactor { get; private set; }
+
+ public static float LinearDamping { get; private set; }
+ public static float AngularDamping { get; private set; }
+ public static float DeactivationTime { get; private set; }
+ public static float LinearSleepingThreshold { get; private set; }
+ public static float AngularSleepingThreshold { get; private set; }
+ public static float CcdMotionThreshold { get; private set; }
+ public static float CcdSweptSphereRadius { get; private set; }
+ public static float ContactProcessingThreshold { get; private set; }
+
+ public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
+ public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
+ public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
+ public static bool ShouldRemoveZeroWidthTriangles { get; private set; }
+ public static bool ShouldUseBulletHACD { get; set; }
+ public static bool ShouldUseSingleConvexHullForPrims { get; set; }
+ public static bool ShouldUseGImpactShapeForPrims { get; set; }
+ public static bool ShouldUseAssetHulls { get; set; }
+
+ public static float TerrainImplementation { get; set; }
+ public static int TerrainMeshMagnification { get; private set; }
+ public static float TerrainGroundPlane { get; private set; }
+ public static float TerrainFriction { get; private set; }
+ public static float TerrainHitFraction { get; private set; }
+ public static float TerrainRestitution { get; private set; }
+ public static float TerrainContactProcessingThreshold { get; private set; }
+ public static float TerrainCollisionMargin { get; private set; }
+
+ public static float DefaultFriction { get; private set; }
+ public static float DefaultDensity { get; private set; }
+ public static float DefaultRestitution { get; private set; }
+ public static float CollisionMargin { get; private set; }
+ public static float Gravity { get; private set; }
+
+ // Physics Engine operation
+ public static float MaxPersistantManifoldPoolSize { get; private set; }
+ public static float MaxCollisionAlgorithmPoolSize { get; private set; }
+ public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; }
+ public static bool ShouldForceUpdateAllAabbs { get; private set; }
+ public static bool ShouldRandomizeSolverOrder { get; private set; }
+ public static bool ShouldSplitSimulationIslands { get; private set; }
+ public static bool ShouldEnableFrictionCaching { get; private set; }
+ public static float NumberOfSolverIterations { get; private set; }
+ public static bool UseSingleSidedMeshes { get; private set; }
+ public static float GlobalContactBreakingThreshold { get; private set; }
+ public static float PhysicsUnmanLoggingFrames { get; private set; }
+
+ // Avatar parameters
+ public static bool AvatarToAvatarCollisionsByDefault { get; private set; }
+ public static float AvatarFriction { get; private set; }
+ public static float AvatarStandingFriction { get; private set; }
+ public static float AvatarAlwaysRunFactor { get; private set; }
+ public static float AvatarDensity { get; private set; }
+ public static float AvatarRestitution { get; private set; }
+ public static int AvatarShape { get; private set; }
+ public static float AvatarCapsuleWidth { get; private set; }
+ public static float AvatarCapsuleDepth { get; private set; }
+ public static float AvatarCapsuleHeight { get; private set; }
+ public static float AvatarHeightLowFudge { get; private set; }
+ public static float AvatarHeightMidFudge { get; private set; }
+ public static float AvatarHeightHighFudge { get; private set; }
+ public static float AvatarFlyingGroundMargin { get; private set; }
+ public static float AvatarFlyingGroundUpForce { get; private set; }
+ public static float AvatarTerminalVelocity { get; private set; }
+ public static float AvatarContactProcessingThreshold { get; private set; }
+ public static float AvatarStopZeroThreshold { get; private set; }
+ public static int AvatarJumpFrames { get; private set; }
+ public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
+ public static float AvatarStepHeight { get; private set; }
+ public static float AvatarStepAngle { get; private set; }
+ public static float AvatarStepGroundFudge { get; private set; }
+ public static float AvatarStepApproachFactor { get; private set; }
+ public static float AvatarStepForceFactor { get; private set; }
+ public static float AvatarStepUpCorrectionFactor { get; private set; }
+ public static int AvatarStepSmoothingSteps { get; private set; }
+
+ // Vehicle parameters
+ public static float VehicleMaxLinearVelocity { get; private set; }
+ public static float VehicleMaxLinearVelocitySquared { get; private set; }
+ public static float VehicleMinLinearVelocity { get; private set; }
+ public static float VehicleMinLinearVelocitySquared { get; private set; }
+ public static float VehicleMaxAngularVelocity { get; private set; }
+ public static float VehicleMaxAngularVelocitySq { get; private set; }
+ public static float VehicleAngularDamping { get; private set; }
+ public static float VehicleFriction { get; private set; }
+ public static float VehicleRestitution { get; private set; }
+ public static Vector3 VehicleLinearFactor { get; private set; }
+ public static Vector3 VehicleAngularFactor { get; private set; }
+ public static Vector3 VehicleInertiaFactor { get; private set; }
+ public static float VehicleGroundGravityFudge { get; private set; }
+ public static float VehicleAngularBankingTimescaleFudge { get; private set; }
+ public static bool VehicleEnableLinearDeflection { get; private set; }
+ public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; }
+ public static bool VehicleEnableAngularVerticalAttraction { get; private set; }
+ public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; }
+ public static bool VehicleEnableAngularDeflection { get; private set; }
+ public static bool VehicleEnableAngularBanking { get; private set; }
+
+ // Convex Hulls
+ // Parameters for convex hull routine that ships with Bullet
+ public static int CSHullMaxDepthSplit { get; private set; }
+ public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; }
+ public static float CSHullConcavityThresholdPercent { get; private set; }
+ public static float CSHullVolumeConservationThresholdPercent { get; private set; }
+ public static int CSHullMaxVertices { get; private set; }
+ public static float CSHullMaxSkinWidth { get; private set; }
+ public static float BHullMaxVerticesPerHull { get; private set; } // 100
+ public static float BHullMinClusters { get; private set; } // 2
+ public static float BHullCompacityWeight { get; private set; } // 0.1
+ public static float BHullVolumeWeight { get; private set; } // 0.0
+ public static float BHullConcavity { get; private set; } // 100
+ public static bool BHullAddExtraDistPoints { get; private set; } // false
+ public static bool BHullAddNeighboursDistPoints { get; private set; } // false
+ public static bool BHullAddFacesPoints { get; private set; } // false
+ public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false
+ public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD
+ // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd
+ // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1
+ // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html
+ public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage
+ public static float VHACDdepth { get; private set; } // 20 max number of clipping stages
+ public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity
+ public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane
+ public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process
+ public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes
+ public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis
+ public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging
+ public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp
+ public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based
+ public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull
+ public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls
+
+ // Linkset implementation parameters
+ public static float LinksetImplementation { get; private set; }
+ public static bool LinksetOffsetCenterOfMass { get; private set; }
+ public static bool LinkConstraintUseFrameOffset { get; private set; }
+ public static bool LinkConstraintEnableTransMotor { get; private set; }
+ public static float LinkConstraintTransMotorMaxVel { get; private set; }
+ public static float LinkConstraintTransMotorMaxForce { get; private set; }
+ public static float LinkConstraintERP { get; private set; }
+ public static float LinkConstraintCFM { get; private set; }
+ public static float LinkConstraintSolverIterations { get; private set; }
+
+ public static float PID_D { get; private set; } // derivative
+ public static float PID_P { get; private set; } // proportional
+
+ // Various constants that come from that other virtual world that shall not be named.
+ public const float MinGravityZ = -1f;
+ public const float MaxGravityZ = 28f;
+ public const float MinFriction = 0f;
+ public const float MaxFriction = 255f;
+ public const float MinDensity = 0.01f;
+ public const float MaxDensity = 22587f;
+ public const float MinRestitution = 0f;
+ public const float MaxRestitution = 1f;
+
+ // =====================================================================================
+ // =====================================================================================
+
+ // Base parameter definition that gets and sets parameter values via a string
+ public abstract class ParameterDefnBase
+ {
+ public string name; // string name of the parameter
+ public string desc; // a short description of what the parameter means
+ public ParameterDefnBase(string pName, string pDesc)
+ {
+ name = pName;
+ desc = pDesc;
+ }
+ // Set the parameter value to the default
+ public abstract void AssignDefault(BSScene s);
+ // Get the value as a string
+ public abstract string GetValue(BSScene s);
+ // Set the value to this string value
+ public abstract void SetValue(BSScene s, string valAsString);
+ // set the value on a particular object (usually sets in physics engine)
+ public abstract void SetOnObject(BSScene s, BSPhysObject obj);
+ public abstract bool HasSetOnObject { get; }
+ }
+
+ // Specific parameter definition for a parameter of a specific type.
+ public delegate T PGetValue(BSScene s);
+ public delegate void PSetValue(BSScene s, T val);
+ public delegate void PSetOnObject(BSScene scene, BSPhysObject obj);
+ public sealed class ParameterDefn : ParameterDefnBase
+ {
+ private T defaultValue;
+ private PSetValue setter;
+ private PGetValue getter;
+ private PSetOnObject objectSet;
+ public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter)
+ : base(pName, pDesc)
+ {
+ defaultValue = pDefault;
+ setter = pSetter;
+ getter = pGetter;
+ objectSet = null;
+ }
+ public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter, PSetOnObject pObjSetter)
+ : base(pName, pDesc)
+ {
+ defaultValue = pDefault;
+ setter = pSetter;
+ getter = pGetter;
+ objectSet = pObjSetter;
+ }
+ // Simple parameter variable where property name is the same as the INI file name
+ // and the value is only a simple get and set.
+ public ParameterDefn(string pName, string pDesc, T pDefault)
+ : base(pName, pDesc)
+ {
+ defaultValue = pDefault;
+ setter = (s, v) => { SetValueByName(s, name, v); };
+ getter = (s) => { return GetValueByName(s, name); };
+ objectSet = null;
+ }
+ // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same.
+ private void SetValueByName(BSScene s, string pName, T val)
+ {
+ PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
+ if (prop == null)
+ {
+ // This should only be output when someone adds a new INI parameter and misspells the name.
+ s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName);
+ }
+ else
+ {
+ prop.SetValue(null, val, null);
+ }
+ }
+ // Use reflection to find the property named 'pName' in BSParam and return the value in same.
+ private T GetValueByName(BSScene s, string pName)
+ {
+ PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
+ if (prop == null)
+ {
+ // This should only be output when someone adds a new INI parameter and misspells the name.
+ s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName);
+ }
+ return (T)prop.GetValue(null, null);
+ }
+ public override void AssignDefault(BSScene s)
+ {
+ setter(s, defaultValue);
+ }
+ public override string GetValue(BSScene s)
+ {
+ return getter(s).ToString();
+ }
+ public override void SetValue(BSScene s, string valAsString)
+ {
+ // Get the generic type of the setter
+ Type genericType = setter.GetType().GetGenericArguments()[0];
+ // Find the 'Parse' method on that type
+ System.Reflection.MethodInfo parser = null;
+ try
+ {
+ parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } );
+ }
+ catch (Exception e)
+ {
+ s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e);
+ parser = null;
+ }
+ if (parser != null)
+ {
+ // Parse the input string
+ try
+ {
+ T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString });
+ // Store the parsed value
+ setter(s, setValue);
+ // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue);
+ }
+ catch
+ {
+ s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType);
+ }
+ }
+ else
+ {
+ s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType);
+ }
+ }
+ public override bool HasSetOnObject
+ {
+ get { return objectSet != null; }
+ }
+ public override void SetOnObject(BSScene s, BSPhysObject obj)
+ {
+ if (objectSet != null)
+ objectSet(s, obj);
+ }
+ }
+
+ // List of all of the externally visible parameters.
+ // For each parameter, this table maps a text name to getter and setters.
+ // To add a new externally referencable/settable parameter, add the paramter storage
+ // location somewhere in the program and make an entry in this table with the
+ // getters and setters.
+ // It is easiest to find an existing definition and copy it.
+ //
+ // A ParameterDefn() takes the following parameters:
+ // -- the text name of the parameter. This is used for console input and ini file.
+ // -- a short text description of the parameter. This shows up in the console listing.
+ // -- a default value
+ // -- a delegate for getting the value
+ // -- a delegate for setting the value
+ // -- an optional delegate to update the value in the world. Most often used to
+ // push the new value to an in-world object.
+ //
+ // The single letter parameters for the delegates are:
+ // s = BSScene
+ // o = BSPhysObject
+ // v = value (appropriate type)
+ private static ParameterDefnBase[] ParameterDefinitions =
+ {
+ new ParameterDefn("Active", "If 'true', false then physics is not active",
+ false ),
+ new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat",
+ false ),
+ new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval",
+ 0.089f ),
+
+ new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
+ true,
+ (s) => { return ShouldMeshSculptedPrim; },
+ (s,v) => { ShouldMeshSculptedPrim = v; } ),
+ new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
+ false,
+ (s) => { return ShouldForceSimplePrimMeshing; },
+ (s,v) => { ShouldForceSimplePrimMeshing = v; } ),
+ new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
+ true,
+ (s) => { return ShouldUseHullsForPhysicalObjects; },
+ (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ),
+ new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes",
+ true ),
+ new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD",
+ false ),
+ new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims",
+ true ),
+ new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists",
+ false ),
+ new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info",
+ true ),
+
+ new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions",
+ 5 ),
+ new ParameterDefn("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator",
+ 0.1f ),
+
+ new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
+ 32f,
+ (s) => { return MeshLOD; },
+ (s,v) => { MeshLOD = v; } ),
+ new ParameterDefn("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes",
+ 32f,
+ (s) => { return MeshCircularLOD; },
+ (s,v) => { MeshCircularLOD = v; } ),
+ new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
+ 10f,
+ (s) => { return MeshMegaPrimThreshold; },
+ (s,v) => { MeshMegaPrimThreshold = v; } ),
+ new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
+ 32f,
+ (s) => { return MeshMegaPrimLOD; },
+ (s,v) => { MeshMegaPrimLOD = v; } ),
+ new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
+ 32f,
+ (s) => { return SculptLOD; },
+ (s,v) => { SculptLOD = v; } ),
+
+ new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
+ 10,
+ (s) => { return s.m_maxSubSteps; },
+ (s,v) => { s.m_maxSubSteps = (int)v; } ),
+ new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
+ 1f / 60f,
+ (s) => { return s.m_fixedTimeStep; },
+ (s,v) => { s.m_fixedTimeStep = v; } ),
+ new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
+ 55f,
+ (s) => { return s.NominalFrameRate; },
+ (s,v) => { s.NominalFrameRate = (int)v; } ),
+ new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
+ 2048,
+ (s) => { return s.m_maxCollisionsPerFrame; },
+ (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
+ new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
+ 8000,
+ (s) => { return s.m_maxUpdatesPerFrame; },
+ (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
+
+ new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
+ 0.0001f,
+ (s) => { return MinimumObjectMass; },
+ (s,v) => { MinimumObjectMass = v; } ),
+ new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
+ 10000.01f,
+ (s) => { return MaximumObjectMass; },
+ (s,v) => { MaximumObjectMass = v; } ),
+ new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object",
+ 1000.0f,
+ (s) => { return MaxLinearVelocity; },
+ (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ),
+ new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object",
+ 1000.0f,
+ (s) => { return MaxAngularVelocity; },
+ (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ),
+ // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject
+ new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)",
+ 20000.0f,
+ (s) => { return MaxAddForceMagnitude; },
+ (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ),
+ // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
+ // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
+ new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
+ 0.01f ),
+
+ new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
+ 2200f ),
+ new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
+ 900f ),
+
+ new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
+ 0.2f,
+ (s) => { return DefaultFriction; },
+ (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
+ // For historical reasons, the viewer and simulator multiply the density by 100
+ new ParameterDefn("DefaultDensity", "Density for new objects" ,
+ 1000.0006836f, // Aluminum g/cm3 * 100
+ (s) => { return DefaultDensity; },
+ (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
+ new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
+ 0f,
+ (s) => { return DefaultRestitution; },
+ (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ),
+ new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
+ 0.04f,
+ (s) => { return CollisionMargin; },
+ (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ),
+ new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
+ -9.80665f,
+ (s) => { return Gravity; },
+ (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; },
+ (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ),
+
+
+ new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
+ 0f,
+ (s) => { return LinearDamping; },
+ (s,v) => { LinearDamping = v; },
+ (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
+ new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
+ 0f,
+ (s) => { return AngularDamping; },
+ (s,v) => { AngularDamping = v; },
+ (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ),
+ new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
+ 0.2f,
+ (s) => { return DeactivationTime; },
+ (s,v) => { DeactivationTime = v; },
+ (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ),
+ new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
+ 0.8f,
+ (s) => { return LinearSleepingThreshold; },
+ (s,v) => { LinearSleepingThreshold = v;},
+ (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
+ new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
+ 1.0f,
+ (s) => { return AngularSleepingThreshold; },
+ (s,v) => { AngularSleepingThreshold = v;},
+ (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ),
+ new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
+ 0.0f, // set to zero to disable
+ (s) => { return CcdMotionThreshold; },
+ (s,v) => { CcdMotionThreshold = v;},
+ (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ),
+ new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
+ 0.2f,
+ (s) => { return CcdSweptSphereRadius; },
+ (s,v) => { CcdSweptSphereRadius = v;},
+ (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ),
+ new ParameterDefn("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" ,
+ 0.0f,
+ (s) => { return ContactProcessingThreshold; },
+ (s,v) => { ContactProcessingThreshold = v;},
+ (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
+
+ new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
+ (float)BSTerrainPhys.TerrainImplementation.Heightmap ),
+ new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
+ 2 ),
+ new ParameterDefn("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" ,
+ -500.0f ),
+ new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
+ 0.3f ),
+ new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
+ 0.8f ),
+ new ParameterDefn("TerrainRestitution", "Bouncyness" ,
+ 0f ),
+ new ParameterDefn("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" ,
+ 0.0f ),
+ new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
+ 0.04f ),
+
+ new ParameterDefn("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?",
+ true),
+ new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
+ 0.2f ),
+ new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
+ 0.95f ),
+ new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
+ 1.3f ),
+ // For historical reasons, density is reported * 100
+ new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
+ 3500f) , // 3.5 * 100
+ new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
+ 0f ),
+ new ParameterDefn("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh",
+ BSShapeCollection.AvatarShapeCube ) ,
+ new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
+ 0.6f ) ,
+ new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
+ 0.45f ),
+ new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
+ 1.5f ),
+ new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground",
+ 0f ),
+ new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground",
+ 0f ),
+ new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground",
+ 0f ),
+ new ParameterDefn("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying",
+ 5f ),
+ new ParameterDefn("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin",
+ 2.0f ),
+ new ParameterDefn("AvatarTerminalVelocity", "Terminal Velocity of falling avatar",
+ -54.0f ),
+ new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
+ 0.1f ),
+ new ParameterDefn("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped",
+ 0.1f ),
+ new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
+ 1.0f ),
+ new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.",
+ 4 ),
+ new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction",
+ 0.999f ) ,
+ new ParameterDefn("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step",
+ 0.3f ) ,
+ new ParameterDefn("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height",
+ 0.1f ) ,
+ new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)",
+ 2f ),
+ new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step",
+ 0f ),
+ new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step",
+ 0.8f ),
+ new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs",
+ 1 ),
+
+ new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
+ 1000.0f,
+ (s) => { return (float)VehicleMaxLinearVelocity; },
+ (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
+ new ParameterDefn("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
+ 0.001f,
+ (s) => { return (float)VehicleMinLinearVelocity; },
+ (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ),
+ new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
+ 12.0f,
+ (s) => { return (float)VehicleMaxAngularVelocity; },
+ (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ),
+ new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
+ 0.0f ),
+ new ParameterDefn("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)",
+ new Vector3(1f, 1f, 1f) ),
+ new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)",
+ new Vector3(1f, 1f, 1f) ),
+ new ParameterDefn("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)",
+ new Vector3(1f, 1f, 1f) ),
+ new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)",
+ 0.0f ),
+ new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
+ 0.0f ),
+ new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
+ 0.2f ),
+ new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
+ 60.0f ),
+ new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",
+ true ),
+ new ParameterDefn("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles",
+ true ),
+ new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect",
+ true ),
+ new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.",
+ 0 ),
+ new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect",
+ true ),
+ new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect",
+ true ),
+
+ new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
+ 0f,
+ (s) => { return MaxPersistantManifoldPoolSize; },
+ (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
+ new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
+ 0f,
+ (s) => { return MaxCollisionAlgorithmPoolSize; },
+ (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
+ new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
+ false,
+ (s) => { return ShouldDisableContactPoolDynamicAllocation; },
+ (s,v) => { ShouldDisableContactPoolDynamicAllocation = v;
+ s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ),
+ new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
+ false,
+ (s) => { return ShouldForceUpdateAllAabbs; },
+ (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ),
+ new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
+ true,
+ (s) => { return ShouldRandomizeSolverOrder; },
+ (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ),
+ new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
+ true,
+ (s) => { return ShouldSplitSimulationIslands; },
+ (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ),
+ new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
+ true,
+ (s) => { return ShouldEnableFrictionCaching; },
+ (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ),
+ new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
+ 0f, // zero says use Bullet default
+ (s) => { return NumberOfSolverIterations; },
+ (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
+ new ParameterDefn("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.",
+ true,
+ (s) => { return UseSingleSidedMeshes; },
+ (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ),
+ new ParameterDefn("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))",
+ 0f,
+ (s) => { return GlobalContactBreakingThreshold; },
+ (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ),
+ new ParameterDefn("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics",
+ 0f,
+ (s) => { return PhysicsUnmanLoggingFrames; },
+ (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ),
+
+ new ParameterDefn("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy",
+ 7 ),
+ new ParameterDefn("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes",
+ 2 ),
+ new ParameterDefn("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)",
+ 5f ),
+ new ParameterDefn("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)",
+ 5f ),
+ new ParameterDefn("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.",
+ 32 ),
+ new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.",
+ 0f ),
+
+ new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull",
+ 200f ),
+ new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh",
+ 10f ),
+ new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls",
+ 20f ),
+ new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull",
+ 0.1f ),
+ new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be",
+ 10f ),
+ new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors",
+ true ),
+ new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls",
+ true ),
+ new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces",
+ true ),
+ new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin",
+ false ),
+
+ new ParameterDefn("WhichHACD", "zero if Bullet HACD, non-zero says VHACD",
+ 0f ),
+ new ParameterDefn("VHACDresolution", "max number of voxels generated during voxelization stage",
+ 100000f ),
+ new ParameterDefn("VHACDdepth", "max number of clipping stages",
+ 20f ),
+ new ParameterDefn("VHACDconcavity", "maximum concavity",
+ 0.0025f ),
+ new ParameterDefn("VHACDplaneDownsampling", "granularity of search for best clipping plane",
+ 4f ),
+ new ParameterDefn("VHACDconvexHullDownsampling", "precision of hull gen process",
+ 4f ),
+ new ParameterDefn("VHACDalpha", "bias toward clipping along symmetry planes",
+ 0.05f ),
+ new ParameterDefn("VHACDbeta", "bias toward clipping along revolution axis",
+ 0.05f ),
+ new ParameterDefn("VHACDgamma", "max concavity when merging",
+ 0.00125f ),
+ new ParameterDefn("VHACDpca", "on/off normalizing mesh before decomp",
+ 0f ),
+ new ParameterDefn("VHACDmode", "0:voxel based, 1: tetrahedron based",
+ 0f ),
+ new ParameterDefn("VHACDmaxNumVerticesPerCH", "max triangles per convex hull",
+ 64f ),
+ new ParameterDefn("VHACDminVolumePerCH", "sampling of generated convex hulls",
+ 0.0001f ),
+
+ new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
+ (float)BSLinkset.LinksetImplementation.Compound ),
+ new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same",
+ true ),
+ new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
+ false ),
+ new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
+ true ),
+ new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
+ 5.0f ),
+ new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
+ 0.1f ),
+ new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
+ 0.1f ),
+ new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
+ 0.1f ),
+ new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
+ 40 ),
+
+ new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
+ 0,
+ (s) => { return s.PhysicsMetricDumpFrames; },
+ (s,v) => { s.PhysicsMetricDumpFrames = v; } ),
+ new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
+ 0f,
+ (s) => { return 0f; },
+ (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v, false /* inTaintTime */); } ),
+ new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
+ 0f,
+ (s) => { return 0f; },
+ (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
+ };
+
+ // Convert a boolean to our numeric true and false values
+ public static float NumericBool(bool b)
+ {
+ return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
+ }
+
+ // Convert numeric true and false values to a boolean
+ public static bool BoolNumeric(float b)
+ {
+ return (b == ConfigurationParameters.numericTrue ? true : false);
+ }
+
+ // Search through the parameter definitions and return the matching
+ // ParameterDefn structure.
+ // Case does not matter as names are compared after converting to lower case.
+ // Returns 'false' if the parameter is not found.
+ internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn)
+ {
+ bool ret = false;
+ ParameterDefnBase foundDefn = null;
+ string pName = paramName.ToLower();
+
+ foreach (ParameterDefnBase parm in ParameterDefinitions)
+ {
+ if (pName == parm.name.ToLower())
+ {
+ foundDefn = parm;
+ ret = true;
+ break;
+ }
+ }
+ defn = foundDefn;
+ return ret;
+ }
+
+ // Pass through the settable parameters and set the default values
+ internal static void SetParameterDefaultValues(BSScene physicsScene)
+ {
+ foreach (ParameterDefnBase parm in ParameterDefinitions)
+ {
+ parm.AssignDefault(physicsScene);
+ }
+ }
+
+ // Get user set values out of the ini file.
+ internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
+ {
+ foreach (ParameterDefnBase parm in ParameterDefinitions)
+ {
+ parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene)));
+ }
+ }
+
+ internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
+
+ // This creates an array in the correct format for returning the list of
+ // parameters. This is used by the 'list' option of the 'physics' command.
+ internal static void BuildParameterTable()
+ {
+ if (SettableParameters.Length < ParameterDefinitions.Length)
+ {
+ List entries = new List();
+ for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
+ {
+ ParameterDefnBase pd = ParameterDefinitions[ii];
+ entries.Add(new PhysParameterEntry(pd.name, pd.desc));
+ }
+
+ // make the list alphabetical for ease of finding anything
+ entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); });
+
+ SettableParameters = entries.ToArray();
+ }
+ }
+
+ // =====================================================================
+ // =====================================================================
+ // There are parameters that, when set, cause things to happen in the physics engine.
+ // This causes the broadphase collision cache to be cleared.
+ private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v, bool inTaintTime)
+ {
+ BSScene physScene = pPhysScene;
+ physScene.TaintedObject(inTaintTime, "BSParam.ResetBroadphasePoolTainted", delegate()
+ {
+ physScene.PE.ResetBroadphasePool(physScene.World);
+ });
+ }
+
+ // This causes the constraint solver cache to be cleared and reset.
+ private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
+ {
+ BSScene physScene = pPhysScene;
+ physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate()
+ {
+ physScene.PE.ResetConstraintSolver(physScene.World);
+ });
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
new file mode 100755
index 0000000..90da7a6
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
@@ -0,0 +1,620 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OMV = OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+/*
+ * Class to wrap all objects.
+ * The rest of BulletSim doesn't need to keep checking for avatars or prims
+ * unless the difference is significant.
+ *
+ * Variables in the physicsl objects are in three forms:
+ * VariableName: used by the simulator and performs taint operations, etc
+ * RawVariableName: direct reference to the BulletSim storage for the variable value
+ * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
+ * The last one should only be referenced in taint-time.
+ */
+
+/*
+ * As of 20121221, the following are the call sequences (going down) for different script physical functions:
+ * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
+ * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
+ * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
+ * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
+ * BS.ApplyCentralForce BS.ApplyTorque
+ */
+
+// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
+public enum UpdatedProperties : uint
+{
+ Position = 1 << 0,
+ Orientation = 1 << 1,
+ Velocity = 1 << 2,
+ Acceleration = 1 << 3,
+ RotationalVelocity = 1 << 4,
+ EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
+}
+public abstract class BSPhysObject : PhysicsActor
+{
+ protected BSPhysObject()
+ {
+ }
+ protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
+ {
+ IsInitialized = false;
+
+ PhysScene = parentScene;
+ LocalID = localID;
+ PhysObjectName = name;
+ Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
+ TypeName = typeName;
+
+ // Oddity if object is destroyed and recreated very quickly it could still have the old body.
+ if (!PhysBody.HasPhysicalBody)
+ PhysBody = new BulletBody(localID);
+
+ // Clean out anything that might be in the physical actor list.
+ // Again, a workaround for destroying and recreating an object very quickly.
+ PhysicalActors.Dispose();
+
+ UserSetCenterOfMassDisplacement = null;
+
+ PrimAssetState = PrimAssetCondition.Unknown;
+
+ // Initialize variables kept in base.
+ // Beware that these cause taints to be queued whch can cause race conditions on startup.
+ GravModifier = 1.0f;
+ Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
+ HoverActive = false;
+
+ // Default material type. Also sets Friction, Restitution and Density.
+ SetMaterial((int)MaterialAttributes.Material.Wood);
+
+ CollisionsLastTickStep = -1;
+
+ SubscribedEventsMs = 0;
+ // Crazy values that will never be true
+ CollidingStep = BSScene.NotASimulationStep;
+ CollidingGroundStep = BSScene.NotASimulationStep;
+ CollisionAccumulation = BSScene.NotASimulationStep;
+ ColliderIsMoving = false;
+ CollisionScore = 0;
+
+ // All axis free.
+ LockedLinearAxis = LockedAxisFree;
+ LockedAngularAxis = LockedAxisFree;
+ }
+
+ // Tell the object to clean up.
+ public virtual void Destroy()
+ {
+ PhysicalActors.Enable(false);
+ PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
+ {
+ PhysicalActors.Dispose();
+ });
+ }
+
+ public BSScene PhysScene { get; protected set; }
+ // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
+ public string PhysObjectName { get; protected set; }
+ public string TypeName { get; protected set; }
+
+ // Set to 'true' when the object is completely initialized.
+ // This mostly prevents property updates and collisions until the object is completely here.
+ public bool IsInitialized { get; protected set; }
+
+ // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed.
+ // This test is used to prevent some updates to the object when it only partially exists.
+ // There are several reasons and object might be incomplete:
+ // Its underlying mesh/sculpty is an asset which must be fetched from the asset store
+ // It is a linkset who is being added to or removed from
+ // It is changing state (static to physical, for instance) which requires rebuilding
+ // This is a computed value based on the underlying physical object construction
+ abstract public bool IsIncomplete { get; }
+
+ // Return the object mass without calculating it or having side effects
+ public abstract float RawMass { get; }
+ // Set the raw mass but also update physical mass properties (inertia, ...)
+ // 'inWorld' true if the object has already been added to the dynamic world.
+ public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
+
+ // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
+ public virtual OMV.Vector3 Gravity { get; set; }
+ // The last value calculated for the prim's inertia
+ public OMV.Vector3 Inertia { get; set; }
+
+ // Reference to the physical body (btCollisionObject) of this object
+ public BulletBody PhysBody = new BulletBody(0);
+ // Reference to the physical shape (btCollisionShape) of this object
+ public BSShape PhysShape = new BSShapeNull();
+
+ // The physical representation of the prim might require an asset fetch.
+ // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
+ public enum PrimAssetCondition
+ {
+ Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
+ }
+ public PrimAssetCondition PrimAssetState { get; set; }
+ public virtual bool AssetFailed()
+ {
+ return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch)
+ || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) );
+ }
+
+ // The objects base shape information. Null if not a prim type shape.
+ public PrimitiveBaseShape BaseShape { get; protected set; }
+
+ // When the physical properties are updated, an EntityProperty holds the update values.
+ // Keep the current and last EntityProperties to enable computation of differences
+ // between the current update and the previous values.
+ public EntityProperties CurrentEntityProperties { get; set; }
+ public EntityProperties LastEntityProperties { get; set; }
+
+ public virtual OMV.Vector3 Scale { get; set; }
+
+ // It can be confusing for an actor to know if it should move or update an object
+ // depeneding on the setting of 'selected', 'physical, ...
+ // This flag is the true test -- if true, the object is being acted on in the physical world
+ public abstract bool IsPhysicallyActive { get; }
+
+ // Detailed state of the object.
+ public abstract bool IsSolid { get; }
+ public abstract bool IsStatic { get; }
+ public abstract bool IsSelected { get; }
+ public abstract bool IsVolumeDetect { get; }
+
+ // Materialness
+ public MaterialAttributes.Material Material { get; private set; }
+ public override void SetMaterial(int material)
+ {
+ Material = (MaterialAttributes.Material)material;
+
+ // Setting the material sets the material attributes also.
+ // TODO: decide if this is necessary -- the simulator does this.
+ MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
+ Friction = matAttrib.friction;
+ Restitution = matAttrib.restitution;
+ Density = matAttrib.density;
+ // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
+ }
+
+ public override float Density
+ {
+ get
+ {
+ return base.Density;
+ }
+ set
+ {
+ DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
+ base.Density = value;
+ }
+ }
+
+ // Stop all physical motion.
+ public abstract void ZeroMotion(bool inTaintTime);
+ public abstract void ZeroAngularMotion(bool inTaintTime);
+
+ // Update the physical location and motion of the object. Called with data from Bullet.
+ public abstract void UpdateProperties(EntityProperties entprop);
+
+ public virtual OMV.Vector3 RawPosition { get; set; }
+ public abstract OMV.Vector3 ForcePosition { get; set; }
+
+ public virtual OMV.Quaternion RawOrientation { get; set; }
+ public abstract OMV.Quaternion ForceOrientation { get; set; }
+
+ public virtual OMV.Vector3 RawVelocity { get; set; }
+ public abstract OMV.Vector3 ForceVelocity { get; set; }
+
+ public OMV.Vector3 RawForce { get; set; }
+ public OMV.Vector3 RawTorque { get; set; }
+ public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
+ {
+ AddAngularForce(force, pushforce, false);
+ }
+ public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
+ public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
+
+ public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
+
+ public abstract float ForceBuoyancy { get; set; }
+
+ public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
+
+ public override bool PIDActive
+ {
+ get { return MoveToTargetActive; }
+ set { MoveToTargetActive = value; }
+ }
+
+ public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
+ public override float PIDTau { set { MoveToTargetTau = value; } }
+
+ public bool MoveToTargetActive { get; set; }
+ public OMV.Vector3 MoveToTargetTarget { get; set; }
+ public float MoveToTargetTau { get; set; }
+
+ // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
+ public override bool PIDHoverActive { set { HoverActive = value; } }
+ public override float PIDHoverHeight { set { HoverHeight = value; } }
+ public override PIDHoverType PIDHoverType { set { HoverType = value; } }
+ public override float PIDHoverTau { set { HoverTau = value; } }
+
+ public bool HoverActive { get; set; }
+ public float HoverHeight { get; set; }
+ public PIDHoverType HoverType { get; set; }
+ public float HoverTau { get; set; }
+
+ // For RotLookAt
+ public override OMV.Quaternion APIDTarget { set { return; } }
+ public override bool APIDActive { set { return; } }
+ public override float APIDStrength { set { return; } }
+ public override float APIDDamping { set { return; } }
+
+ // The current velocity forward
+ public virtual float ForwardSpeed
+ {
+ get
+ {
+ OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
+ return characterOrientedVelocity.X;
+ }
+ }
+ // The forward speed we are trying to achieve (TargetVelocity)
+ public virtual float TargetVelocitySpeed
+ {
+ get
+ {
+ OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
+ return characterOrientedVelocity.X;
+ }
+ }
+
+ // The user can optionally set the center of mass. The user's setting will override any
+ // computed center-of-mass (like in linksets).
+ // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
+ public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
+
+ public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
+ public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
+ public const float FreeAxis = 1f;
+ public const float LockedAxis = 0f;
+ public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
+
+ // If an axis is locked (flagged above) then the limits of that axis are specified here.
+ // Linear axis limits are relative to the object's starting coordinates.
+ // Angular limits are limited to -PI to +PI
+ public OMV.Vector3 LockedLinearAxisLow;
+ public OMV.Vector3 LockedLinearAxisHigh;
+ public OMV.Vector3 LockedAngularAxisLow;
+ public OMV.Vector3 LockedAngularAxisHigh;
+
+ // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
+ // they need waking up when parameters are changed.
+ // Called in taint-time!!
+ public void ActivateIfPhysical(bool forceIt)
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ if (IsPhysical)
+ {
+ // Physical objects might need activating
+ PhysScene.PE.Activate(PhysBody, forceIt);
+ }
+ else
+ {
+ // Clear the collision cache since we've changed some properties.
+ PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
+ }
+ }
+ }
+
+ // 'actors' act on the physical object to change or constrain its motion. These can range from
+ // hovering to complex vehicle motion.
+ // May be called at non-taint time as this just adds the actor to the action list and the real
+ // work is done during the simulation step.
+ // Note that, if the actor is already in the list and we are disabling same, the actor is just left
+ // in the list disabled.
+ public delegate BSActor CreateActor();
+ public void EnableActor(bool enableActor, string actorName, CreateActor creator)
+ {
+ lock (PhysicalActors)
+ {
+ BSActor theActor;
+ if (PhysicalActors.TryGetActor(actorName, out theActor))
+ {
+ // The actor already exists so just turn it on or off
+ DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
+ theActor.Enabled = enableActor;
+ }
+ else
+ {
+ // The actor does not exist. If it should, create it.
+ if (enableActor)
+ {
+ DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
+ theActor = creator();
+ PhysicalActors.Add(actorName, theActor);
+ theActor.Enabled = true;
+ }
+ else
+ {
+ DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
+ }
+ }
+ }
+ }
+
+ #region Collisions
+
+ // Requested number of milliseconds between collision events. Zero means disabled.
+ protected int SubscribedEventsMs { get; set; }
+ // Given subscription, the time that a collision may be passed up
+ protected int NextCollisionOkTime { get; set; }
+ // The simulation step that last had a collision
+ protected long CollidingStep { get; set; }
+ // The simulation step that last had a collision with the ground
+ protected long CollidingGroundStep { get; set; }
+ // The simulation step that last collided with an object
+ protected long CollidingObjectStep { get; set; }
+ // The collision flags we think are set in Bullet
+ protected CollisionFlags CurrentCollisionFlags { get; set; }
+ // On a collision, check the collider and remember if the last collider was moving
+ // Used to modify the standing of avatars (avatars on stationary things stand still)
+ public bool ColliderIsMoving;
+ // 'true' if the last collider was a volume detect object
+ public bool ColliderIsVolumeDetect;
+ // Used by BSCharacter to manage standing (and not slipping)
+ public bool IsStationary;
+
+ // Count of collisions for this object
+ protected long CollisionAccumulation { get; set; }
+
+ public override bool IsColliding {
+ get { return (CollidingStep == PhysScene.SimulationStep); }
+ set {
+ if (value)
+ CollidingStep = PhysScene.SimulationStep;
+ else
+ CollidingStep = BSScene.NotASimulationStep;
+ }
+ }
+ // Complex objects (like linksets) need to know if there is a collision on any part of
+ // their shape. 'IsColliding' has an existing definition of reporting a collision on
+ // only this specific prim or component of linksets.
+ // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
+ // the complex body that this prim is the root of.
+ public virtual bool HasSomeCollision
+ {
+ get { return IsColliding; }
+ set { IsColliding = value; }
+ }
+ public override bool CollidingGround {
+ get { return (CollidingGroundStep == PhysScene.SimulationStep); }
+ set
+ {
+ if (value)
+ CollidingGroundStep = PhysScene.SimulationStep;
+ else
+ CollidingGroundStep = BSScene.NotASimulationStep;
+ }
+ }
+ public override bool CollidingObj {
+ get { return (CollidingObjectStep == PhysScene.SimulationStep); }
+ set {
+ if (value)
+ CollidingObjectStep = PhysScene.SimulationStep;
+ else
+ CollidingObjectStep = BSScene.NotASimulationStep;
+ }
+ }
+
+ // The collisions that have been collected for the next collision reporting (throttled by subscription)
+ protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
+ // This is the collision collection last reported to the Simulator.
+ public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
+ // Remember the collisions recorded in the last tick for fancy collision checking
+ // (like a BSCharacter walking up stairs).
+ public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
+ private long CollisionsLastTickStep = -1;
+
+ // The simulation step is telling this object about a collision.
+ // Return 'true' if a collision was processed and should be sent up.
+ // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
+ // Called at taint time from within the Step() function
+ public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
+ public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
+ OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
+ {
+ bool ret = false;
+
+ // The following lines make IsColliding(), CollidingGround() and CollidingObj work
+ CollidingStep = PhysScene.SimulationStep;
+ if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
+ {
+ CollidingGroundStep = PhysScene.SimulationStep;
+ }
+ else
+ {
+ CollidingObjectStep = PhysScene.SimulationStep;
+ }
+
+ CollisionAccumulation++;
+
+ // For movement tests, remember if we are colliding with an object that is moving.
+ ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
+ ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
+
+ // Make a collection of the collisions that happened the last simulation tick.
+ // This is different than the collection created for sending up to the simulator as it is cleared every tick.
+ if (CollisionsLastTickStep != PhysScene.SimulationStep)
+ {
+ CollisionsLastTick = new CollisionEventUpdate();
+ CollisionsLastTickStep = PhysScene.SimulationStep;
+ }
+ CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
+
+ // If someone has subscribed for collision events log the collision so it will be reported up
+ if (SubscribedEvents()) {
+ lock (PhysScene.CollisionLock)
+ {
+ CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
+ }
+ DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
+ LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
+
+ ret = true;
+ }
+ return ret;
+ }
+
+ // Send the collected collisions into the simulator.
+ // Called at taint time from within the Step() function thus no locking problems
+ // with CollisionCollection and ObjectsWithNoMoreCollisions.
+ // Called with BSScene.CollisionLock locked to protect the collision lists.
+ // Return 'true' if there were some actual collisions passed up
+ public virtual bool SendCollisions()
+ {
+ bool ret = true;
+
+ // If no collisions this call but there were collisions last call, force the collision
+ // event to be happen right now so quick collision_end.
+ bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
+
+ // throttle the collisions to the number of milliseconds specified in the subscription
+ if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
+ {
+ NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
+
+ // We are called if we previously had collisions. If there are no collisions
+ // this time, send up one last empty event so OpenSim can sense collision end.
+ if (CollisionCollection.Count == 0)
+ {
+ // If I have no collisions this time, remove me from the list of objects with collisions.
+ ret = false;
+ }
+
+ DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
+ base.SendCollisionUpdate(CollisionCollection);
+
+ // Remember the collisions from this tick for some collision specific processing.
+ CollisionsLastReported = CollisionCollection;
+
+ // The CollisionCollection instance is passed around in the simulator.
+ // Make sure we don't have a handle to that one and that a new one is used for next time.
+ // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
+ // a race condition is created for the other users of this instance.
+ CollisionCollection = new CollisionEventUpdate();
+ }
+ return ret;
+ }
+
+ // Subscribe for collision events.
+ // Parameter is the millisecond rate the caller wishes collision events to occur.
+ public override void SubscribeEvents(int ms) {
+ // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
+ SubscribedEventsMs = ms;
+ if (ms > 0)
+ {
+ // make sure first collision happens
+ NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
+
+ PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+ });
+ }
+ else
+ {
+ // Subscribing for zero or less is the same as unsubscribing
+ UnSubscribeEvents();
+ }
+ }
+ public override void UnSubscribeEvents() {
+ // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
+ SubscribedEventsMs = 0;
+ PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
+ {
+ // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
+ if (PhysBody.HasPhysicalBody)
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+ });
+ }
+ // Return 'true' if the simulator wants collision events
+ public override bool SubscribedEvents() {
+ return (SubscribedEventsMs > 0);
+ }
+ // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
+ // each time called. So this is built to be light weight for each collision and to do
+ // all the processing when the user asks for the info.
+ public void ComputeCollisionScore()
+ {
+ // Scale the collision count by the time since the last collision.
+ // The "+1" prevents dividing by zero.
+ long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
+ CollisionScore = CollisionAccumulation / timeAgo;
+ }
+ public override float CollisionScore { get; set; }
+
+ #endregion // Collisions
+
+ #region Per Simulation Step actions
+
+ public BSActorCollection PhysicalActors = new BSActorCollection();
+
+ // When an update to the physical properties happens, this event is fired to let
+ // different actors to modify the update before it is passed around
+ public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
+ public event PreUpdatePropertyAction OnPreUpdateProperty;
+ protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
+ {
+ PreUpdatePropertyAction actions = OnPreUpdateProperty;
+ if (actions != null)
+ actions(ref entprop);
+ }
+
+ #endregion // Per Simulation Step actions
+
+ // High performance detailed logging routine used by the physical objects.
+ protected void DetailLog(string msg, params Object[] args)
+ {
+ if (PhysScene.PhysicsLogging.Enabled)
+ PhysScene.DetailLog(msg, args);
+ }
+
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
new file mode 100644
index 0000000..9442854
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPlugin.cs
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+ ///
+ /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
+ /// This module interfaces to an unmanaged C++ library which makes the
+ /// actual calls into the Bullet physics engine.
+ /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
+ /// The unmanaged library is compiled and linked statically with Bullet
+ /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit).
+ ///
+public class BSPlugin : IPhysicsPlugin
+{
+ //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private BSScene _mScene;
+
+ public BSPlugin()
+ {
+ }
+
+ public bool Init()
+ {
+ return true;
+ }
+
+ public PhysicsScene GetScene(String sceneIdentifier)
+ {
+ if (_mScene == null)
+ {
+ _mScene = new BSScene(GetName(), sceneIdentifier);
+ }
+ return (_mScene);
+ }
+
+ public string GetName()
+ {
+ return ("BulletSim");
+ }
+
+ public void Dispose()
+ {
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..a00991f
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1896 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+using System.Xml;
+using log4net;
+using OMV = OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.Physics.ConvexDecompositionDotNet;
+using OpenSim.Region.OptionalModules.Scripting; // for ExtendedPhysics
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+ [Serializable]
+public class BSPrim : BSPhysObject
+{
+ protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly string LogHeader = "[BULLETS PRIM]";
+
+ // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
+ private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
+
+ private bool _grabbed;
+ private bool _isSelected;
+ private bool _isVolumeDetect;
+
+ private float _mass; // the mass of this object
+ private OMV.Vector3 _acceleration;
+ private int _physicsActorType;
+ private bool _isPhysical;
+ private bool _flying;
+ private bool _setAlwaysRun;
+ private bool _throttleUpdates;
+ private bool _floatOnWater;
+ private OMV.Vector3 _rotationalVelocity;
+ private bool _kinematic;
+ private float _buoyancy;
+
+ private int CrossingFailures { get; set; }
+
+ // Keep a handle to the vehicle actor so it is easy to set parameters on same.
+ public const string VehicleActorName = "BasicVehicle";
+
+ // Parameters for the hover actor
+ public const string HoverActorName = "BSPrim.HoverActor";
+ // Parameters for the axis lock actor
+ public const String LockedAxisActorName = "BSPrim.LockedAxis";
+ // Parameters for the move to target actor
+ public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
+ // Parameters for the setForce and setTorque actors
+ public const string SetForceActorName = "BSPrim.SetForceActor";
+ public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
+
+ public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
+ OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
+ : base(parent_scene, localID, primName, "BSPrim")
+ {
+ // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
+ _physicsActorType = (int)ActorTypes.Prim;
+ RawPosition = pos;
+ _size = size;
+ Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
+ RawOrientation = rotation;
+ _buoyancy = 0f;
+ RawVelocity = OMV.Vector3.Zero;
+ _rotationalVelocity = OMV.Vector3.Zero;
+ BaseShape = pbs;
+ _isPhysical = pisPhysical;
+ _isVolumeDetect = false;
+
+ _mass = CalculateMass();
+
+ DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
+ // DetailLog("{0},BSPrim.constructor,call", LocalID);
+ // do the actual object creation at taint time
+ PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
+ {
+ // Make sure the object is being created with some sanity.
+ ExtremeSanityCheck(true /* inTaintTime */);
+
+ CreateGeomAndObject(true);
+
+ CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
+
+ IsInitialized = true;
+ });
+ }
+
+ // called when this prim is being destroyed and we should free all the resources
+ public override void Destroy()
+ {
+ // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
+ IsInitialized = false;
+
+ base.Destroy();
+
+ // Undo any vehicle properties
+ this.VehicleType = (int)Vehicle.TYPE_NONE;
+
+ PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate()
+ {
+ DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
+ // If there are physical body and shape, release my use of same.
+ PhysScene.Shapes.DereferenceBody(PhysBody, null);
+ PhysBody.Clear();
+ PhysShape.Dereference(PhysScene);
+ PhysShape = new BSShapeNull();
+ });
+ }
+
+ // No one uses this property.
+ public override bool Stopped {
+ get { return false; }
+ }
+
+ public override bool IsIncomplete {
+ get {
+ return ShapeRebuildScheduled;
+ }
+ }
+
+ // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
+ // The prim is still available but its underlying shape will change soon.
+ // This is protected by a 'lock(this)'.
+ public bool ShapeRebuildScheduled { get; protected set; }
+
+ public override OMV.Vector3 Size {
+ get { return _size; }
+ set {
+ // We presume the scale and size are the same. If scale must be changed for
+ // the physical shape, that is done when the geometry is built.
+ _size = value;
+ Scale = _size;
+ ForceBodyShapeRebuild(false);
+ }
+ }
+
+ public override PrimitiveBaseShape Shape {
+ set {
+ BaseShape = value;
+ DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
+ PrimAssetState = PrimAssetCondition.Unknown;
+ ForceBodyShapeRebuild(false);
+ }
+ }
+ // Cause the body and shape of the prim to be rebuilt if necessary.
+ // If there are no changes required, this is quick and does not make changes to the prim.
+ // If rebuilding is necessary (like changing from static to physical), that will happen.
+ // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
+ // The return parameter is not used by anyone.
+ public override bool ForceBodyShapeRebuild(bool inTaintTime)
+ {
+ if (inTaintTime)
+ {
+ // If called in taint time, do the operation immediately
+ _mass = CalculateMass(); // changing the shape changes the mass
+ CreateGeomAndObject(true);
+ }
+ else
+ {
+ lock (this)
+ {
+ // If a rebuild is not already in the queue
+ if (!ShapeRebuildScheduled)
+ {
+ // Remember that a rebuild is queued -- this is used to flag an incomplete object
+ ShapeRebuildScheduled = true;
+ PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
+ {
+ _mass = CalculateMass(); // changing the shape changes the mass
+ CreateGeomAndObject(true);
+ ShapeRebuildScheduled = false;
+ });
+ }
+ }
+ }
+ return true;
+ }
+ public override bool Grabbed {
+ set { _grabbed = value;
+ }
+ }
+ public override bool Selected {
+ set
+ {
+ if (value != _isSelected)
+ {
+ _isSelected = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
+ {
+ DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
+ SetObjectDynamic(false);
+ });
+ }
+ }
+ }
+ public override bool IsSelected
+ {
+ get { return _isSelected; }
+ }
+
+ public override void CrossingFailure()
+ {
+ CrossingFailures++;
+ if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
+ {
+ base.RaiseOutOfBounds(RawPosition);
+ }
+ else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
+ {
+ m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
+ }
+ return;
+ }
+
+ // link me to the specified parent
+ public override void link(PhysicsActor obj) {
+ }
+
+ // delink me from my linkset
+ public override void delink() {
+ }
+
+ // Set motion values to zero.
+ // Do it to the properties so the values get set in the physics engine.
+ // Push the setting of the values to the viewer.
+ // Called at taint time!
+ public override void ZeroMotion(bool inTaintTime)
+ {
+ RawVelocity = OMV.Vector3.Zero;
+ _acceleration = OMV.Vector3.Zero;
+ _rotationalVelocity = OMV.Vector3.Zero;
+
+ // Zero some other properties in the physics engine
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ PhysScene.PE.ClearAllForces(PhysBody);
+ });
+ }
+ public override void ZeroAngularMotion(bool inTaintTime)
+ {
+ _rotationalVelocity = OMV.Vector3.Zero;
+ // Zero some other properties in the physics engine
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
+ {
+ // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
+ PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
+ }
+ });
+ }
+
+ public override void LockAngularMotion(OMV.Vector3 axis)
+ {
+ DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
+
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
+ if (axis.X != 1)
+ {
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
+ }
+ if (axis.Y != 1)
+ {
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
+ }
+ if (axis.Z != 1)
+ {
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
+ }
+
+ InitializeAxisActor();
+
+ return;
+ }
+
+ public override OMV.Vector3 Position {
+ get {
+ // don't do the GetObjectPosition for root elements because this function is called a zillion times.
+ // RawPosition = ForcePosition;
+ return RawPosition;
+ }
+ set {
+ // If the position must be forced into the physics engine, use ForcePosition.
+ // All positions are given in world positions.
+ if (RawPosition == value)
+ {
+ DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
+ return;
+ }
+ RawPosition = value;
+ PositionSanityCheck(false);
+
+ PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
+ {
+ DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
+ ForcePosition = RawPosition;
+ });
+ }
+ }
+
+ // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
+ public override OMV.Vector3 ForcePosition {
+ get {
+ RawPosition = PhysScene.PE.GetPosition(PhysBody);
+ return RawPosition;
+ }
+ set {
+ RawPosition = value;
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
+ ActivateIfPhysical(false);
+ }
+ }
+ }
+
+ // Check that the current position is sane and, if not, modify the position to make it so.
+ // Check for being below terrain and being out of bounds.
+ // Returns 'true' of the position was made sane by some action.
+ private bool PositionSanityCheck(bool inTaintTime)
+ {
+ bool ret = false;
+
+ // We don't care where non-physical items are placed
+ if (!IsPhysicallyActive)
+ return ret;
+
+ if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
+ {
+ // The physical object is out of the known/simulated area.
+ // Upper levels of code will handle the transition to other areas so, for
+ // the time, we just ignore the position.
+ return ret;
+ }
+
+ float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
+ OMV.Vector3 upForce = OMV.Vector3.Zero;
+ float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
+ if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
+ {
+ DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
+ float targetHeight = terrainHeight + (Size.Z / 2f);
+ // If the object is below ground it just has to be moved up because pushing will
+ // not get it through the terrain
+ RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
+ if (inTaintTime)
+ {
+ ForcePosition = RawPosition;
+ }
+ // If we are throwing the object around, zero its other forces
+ ZeroMotion(inTaintTime);
+ ret = true;
+ }
+
+ if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
+ {
+ float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
+ // TODO: a floating motor so object will bob in the water
+ if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
+ {
+ // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
+ upForce.Z = (waterHeight - RawPosition.Z) * 1f;
+
+ // Apply upforce and overcome gravity.
+ OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
+ DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
+ AddForce(correctionForce, false, inTaintTime);
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ // Occasionally things will fly off and really get lost.
+ // Find the wanderers and bring them back.
+ // Return 'true' if some parameter need some sanity.
+ private bool ExtremeSanityCheck(bool inTaintTime)
+ {
+ bool ret = false;
+
+ int wayOverThere = -1000;
+ int wayOutThere = 10000;
+ // There have been instances of objects getting thrown way out of bounds and crashing
+ // the border crossing code.
+ if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
+ || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
+ || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
+ {
+ RawPosition = new OMV.Vector3(10, 10, 50);
+ ZeroMotion(inTaintTime);
+ ret = true;
+ }
+ if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
+ {
+ RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
+ ret = true;
+ }
+ if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
+ {
+ _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ // Return the effective mass of the object.
+ // The definition of this call is to return the mass of the prim.
+ // If the simulator cares about the mass of the linkset, it will sum it itself.
+ public override float Mass
+ {
+ get { return _mass; }
+ }
+ // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
+ public virtual float TotalMass
+ {
+ get { return _mass; }
+ }
+ // used when we only want this prim's mass and not the linkset thing
+ public override float RawMass {
+ get { return _mass; }
+ }
+ // Set the physical mass to the passed mass.
+ // Note that this does not change _mass!
+ public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
+ {
+ if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
+ {
+ if (IsStatic)
+ {
+ PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
+ Inertia = OMV.Vector3.Zero;
+ PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
+ PhysScene.PE.UpdateInertiaTensor(PhysBody);
+ }
+ else
+ {
+ if (inWorld)
+ {
+ // Changing interesting properties doesn't change proxy and collision cache
+ // information. The Bullet solution is to re-add the object to the world
+ // after parameters are changed.
+ PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
+ }
+
+ // The computation of mass props requires gravity to be set on the object.
+ Gravity = ComputeGravity(Buoyancy);
+ PhysScene.PE.SetGravity(PhysBody, Gravity);
+
+ // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
+ // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
+
+ Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
+ PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
+ PhysScene.PE.UpdateInertiaTensor(PhysBody);
+
+ DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
+ LocalID, physMass, Inertia, Gravity, inWorld);
+
+ if (inWorld)
+ {
+ AddObjectToPhysicalWorld();
+ }
+ }
+ }
+ }
+
+ // Return what gravity should be set to this very moment
+ public OMV.Vector3 ComputeGravity(float buoyancy)
+ {
+ OMV.Vector3 ret = PhysScene.DefaultGravity;
+
+ if (!IsStatic)
+ {
+ ret *= (1f - buoyancy);
+ ret *= GravModifier;
+ }
+
+ return ret;
+ }
+
+ // Is this used?
+ public override OMV.Vector3 CenterOfMass
+ {
+ get { return RawPosition; }
+ }
+
+ // Is this used?
+ public override OMV.Vector3 GeometricCenter
+ {
+ get { return RawPosition; }
+ }
+
+ public override OMV.Vector3 Force {
+ get { return RawForce; }
+ set {
+ RawForce = value;
+ EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
+ {
+ return new BSActorSetForce(PhysScene, this, SetForceActorName);
+ });
+
+ // Call update so actor Refresh() is called to start things off
+ PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+
+ // Find and return a handle to the current vehicle actor.
+ // Return 'null' if there is no vehicle actor.
+ public BSDynamics GetVehicleActor(bool createIfNone)
+ {
+ BSDynamics ret = null;
+ BSActor actor;
+ if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
+ {
+ ret = actor as BSDynamics;
+ }
+ else
+ {
+ if (createIfNone)
+ {
+ ret = new BSDynamics(PhysScene, this, VehicleActorName);
+ PhysicalActors.Add(ret.ActorName, ret);
+ }
+ }
+ return ret;
+ }
+
+ public override int VehicleType {
+ get {
+ int ret = (int)Vehicle.TYPE_NONE;
+ BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
+ if (vehicleActor != null)
+ ret = (int)vehicleActor.Type;
+ return ret;
+ }
+ set {
+ Vehicle type = (Vehicle)value;
+
+ PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
+ {
+ // Some vehicle scripts change vehicle type on the fly as an easy way to
+ // change all the parameters. Like a plane changing to CAR when on the
+ // ground. In this case, don't want to zero motion.
+ // ZeroMotion(true /* inTaintTime */);
+ if (type == Vehicle.TYPE_NONE)
+ {
+ // Vehicle type is 'none' so get rid of any actor that may have been allocated.
+ BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
+ }
+ }
+ else
+ {
+ // Vehicle type is not 'none' so create an actor and set it running.
+ BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ vehicleActor.ProcessTypeChange(type);
+ ActivateIfPhysical(false);
+ }
+ }
+ });
+ }
+ }
+ public override void VehicleFloatParam(int param, float value)
+ {
+ PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
+ {
+ BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ public override void VehicleVectorParam(int param, OMV.Vector3 value)
+ {
+ PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
+ {
+ BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
+ {
+ PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
+ {
+ BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ public override void VehicleFlags(int param, bool remove)
+ {
+ PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
+ {
+ BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
+ if (vehicleActor != null)
+ {
+ vehicleActor.ProcessVehicleFlags(param, remove);
+ }
+ });
+ }
+
+ // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
+ public override void SetVolumeDetect(int param) {
+ bool newValue = (param != 0);
+ if (_isVolumeDetect != newValue)
+ {
+ _isVolumeDetect = newValue;
+ PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
+ {
+ // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
+ SetObjectDynamic(true);
+ });
+ }
+ return;
+ }
+ public override bool IsVolumeDetect
+ {
+ get { return _isVolumeDetect; }
+ }
+ public override void SetMaterial(int material)
+ {
+ base.SetMaterial(material);
+ PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ public override float Friction
+ {
+ get { return base.Friction; }
+ set
+ {
+ if (base.Friction != value)
+ {
+ base.Friction = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override float Restitution
+ {
+ get { return base.Restitution; }
+ set
+ {
+ if (base.Restitution != value)
+ {
+ base.Restitution = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ // The simulator/viewer keep density as 100kg/m3.
+ // Remember to use BSParam.DensityScaleFactor to create the physical density.
+ public override float Density
+ {
+ get { return base.Density; }
+ set
+ {
+ if (base.Density != value)
+ {
+ base.Density = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override float GravModifier
+ {
+ get { return base.GravModifier; }
+ set
+ {
+ if (base.GravModifier != value)
+ {
+ base.GravModifier = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ }
+ public override OMV.Vector3 Velocity {
+ get { return RawVelocity; }
+ set {
+ RawVelocity = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
+ {
+ // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
+ ForceVelocity = RawVelocity;
+ });
+ }
+ }
+ public override OMV.Vector3 ForceVelocity {
+ get { return RawVelocity; }
+ set {
+ PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
+
+ RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
+ if (PhysBody.HasPhysicalBody)
+ {
+ DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
+ PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
+ ActivateIfPhysical(false);
+ }
+ }
+ }
+ public override OMV.Vector3 Torque {
+ get { return RawTorque; }
+ set {
+ RawTorque = value;
+ EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
+ {
+ return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
+ });
+ DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
+
+ // Call update so actor Refresh() is called to start things off
+ PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+ public override OMV.Vector3 Acceleration {
+ get { return _acceleration; }
+ set { _acceleration = value; }
+ }
+
+ public override OMV.Quaternion Orientation {
+ get {
+ return RawOrientation;
+ }
+ set {
+ if (RawOrientation == value)
+ return;
+ RawOrientation = value;
+
+ PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
+ {
+ ForceOrientation = RawOrientation;
+ });
+ }
+ }
+ // Go directly to Bullet to get/set the value.
+ public override OMV.Quaternion ForceOrientation
+ {
+ get
+ {
+ RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
+ return RawOrientation;
+ }
+ set
+ {
+ RawOrientation = value;
+ if (PhysBody.HasPhysicalBody)
+ PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
+ }
+ }
+ public override int PhysicsActorType {
+ get { return _physicsActorType; }
+ set { _physicsActorType = value; }
+ }
+ public override bool IsPhysical {
+ get { return _isPhysical; }
+ set {
+ if (_isPhysical != value)
+ {
+ _isPhysical = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
+ {
+ DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
+ SetObjectDynamic(true);
+ // whether phys-to-static or static-to-phys, the object is not moving.
+ ZeroMotion(true);
+
+ });
+ }
+ }
+ }
+
+ // An object is static (does not move) if selected or not physical
+ public override bool IsStatic
+ {
+ get { return _isSelected || !IsPhysical; }
+ }
+
+ // An object is solid if it's not phantom and if it's not doing VolumeDetect
+ public override bool IsSolid
+ {
+ get { return !IsPhantom && !_isVolumeDetect; }
+ }
+
+ // The object is moving and is actively being dynamic in the physical world
+ public override bool IsPhysicallyActive
+ {
+ get { return !_isSelected && IsPhysical; }
+ }
+
+ // Make gravity work if the object is physical and not selected
+ // Called at taint-time!!
+ private void SetObjectDynamic(bool forceRebuild)
+ {
+ // Recreate the physical object if necessary
+ CreateGeomAndObject(forceRebuild);
+ }
+
+ // Convert the simulator's physical properties into settings on BulletSim objects.
+ // There are four flags we're interested in:
+ // IsStatic: Object does not move, otherwise the object has mass and moves
+ // isSolid: other objects bounce off of this object
+ // isVolumeDetect: other objects pass through but can generate collisions
+ // collisionEvents: whether this object returns collision events
+ // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
+ public virtual void UpdatePhysicalParameters()
+ {
+ if (!PhysBody.HasPhysicalBody)
+ {
+ // This would only happen if updates are called for during initialization when the body is not set up yet.
+ // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
+ return;
+ }
+
+ // Mangling all the physical properties requires the object not be in the physical world.
+ // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
+ PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
+
+ // Set up the object physicalness (does gravity and collisions move this object)
+ MakeDynamic(IsStatic);
+
+ // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
+ PhysicalActors.Refresh();
+
+ // Arrange for collision events if the simulator wants them
+ EnableCollisions(SubscribedEvents());
+
+ // Make solid or not (do things bounce off or pass through this object).
+ MakeSolid(IsSolid);
+
+ AddObjectToPhysicalWorld();
+
+ // Rebuild its shape
+ PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
+
+ DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
+ LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
+ CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
+ }
+
+ // "Making dynamic" means changing to and from static.
+ // When static, gravity does not effect the object and it is fixed in space.
+ // When dynamic, the object can fall and be pushed by others.
+ // This is independent of its 'solidness' which controls what passes through
+ // this object and what interacts with it.
+ protected virtual void MakeDynamic(bool makeStatic)
+ {
+ if (makeStatic)
+ {
+ // Become a Bullet 'static' object type
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
+ // Stop all movement
+ ZeroMotion(true);
+
+ // Set various physical properties so other object interact properly
+ PhysScene.PE.SetFriction(PhysBody, Friction);
+ PhysScene.PE.SetRestitution(PhysBody, Restitution);
+ PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
+
+ // Mass is zero which disables a bunch of physics stuff in Bullet
+ UpdatePhysicalMassProperties(0f, false);
+ // Set collision detection parameters
+ if (BSParam.CcdMotionThreshold > 0f)
+ {
+ PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
+ PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
+ }
+
+ // The activation state is 'disabled' so Bullet will not try to act on it.
+ // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
+ // Start it out sleeping and physical actions could wake it up.
+ PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
+
+ // This collides like a static object
+ PhysBody.collisionType = CollisionType.Static;
+ }
+ else
+ {
+ // Not a Bullet static object
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
+
+ // Set various physical properties so other object interact properly
+ PhysScene.PE.SetFriction(PhysBody, Friction);
+ PhysScene.PE.SetRestitution(PhysBody, Restitution);
+ // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
+
+ // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
+ // Since this can be called multiple times, only zero forces when becoming physical
+ // PhysicsScene.PE.ClearAllForces(BSBody);
+
+ // For good measure, make sure the transform is set through to the motion state
+ ForcePosition = RawPosition;
+ ForceVelocity = RawVelocity;
+ ForceRotationalVelocity = _rotationalVelocity;
+
+ // A dynamic object has mass
+ UpdatePhysicalMassProperties(RawMass, false);
+
+ // Set collision detection parameters
+ if (BSParam.CcdMotionThreshold > 0f)
+ {
+ PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
+ PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
+ }
+
+ // Various values for simulation limits
+ PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
+ PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
+ PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
+ PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
+
+ // This collides like an object.
+ PhysBody.collisionType = CollisionType.Dynamic;
+
+ // Force activation of the object so Bullet will act on it.
+ // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
+ PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
+ }
+ }
+
+ // "Making solid" means that other object will not pass through this object.
+ // To make transparent, we create a Bullet ghost object.
+ // Note: This expects to be called from the UpdatePhysicalParameters() routine as
+ // the functions after this one set up the state of a possibly newly created collision body.
+ private void MakeSolid(bool makeSolid)
+ {
+ CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
+ if (makeSolid)
+ {
+ // Verify the previous code created the correct shape for this type of thing.
+ if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
+ {
+ m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
+ }
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
+ }
+ else
+ {
+ if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
+ {
+ m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
+ }
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
+
+ // Change collision info from a static object to a ghosty collision object
+ PhysBody.collisionType = CollisionType.VolumeDetect;
+ }
+ }
+
+ // Turn on or off the flag controlling whether collision events are returned to the simulator.
+ private void EnableCollisions(bool wantsCollisionEvents)
+ {
+ if (wantsCollisionEvents)
+ {
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+ }
+ else
+ {
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
+ }
+ }
+
+ // Add me to the physical world.
+ // Object MUST NOT already be in the world.
+ // This routine exists because some assorted properties get mangled by adding to the world.
+ internal void AddObjectToPhysicalWorld()
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
+ }
+ else
+ {
+ m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
+ DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
+ }
+ }
+
+ // prims don't fly
+ public override bool Flying {
+ get { return _flying; }
+ set {
+ _flying = value;
+ }
+ }
+ public override bool SetAlwaysRun {
+ get { return _setAlwaysRun; }
+ set { _setAlwaysRun = value; }
+ }
+ public override bool ThrottleUpdates {
+ get { return _throttleUpdates; }
+ set { _throttleUpdates = value; }
+ }
+ public bool IsPhantom {
+ get {
+ // SceneObjectPart removes phantom objects from the physics scene
+ // so, although we could implement touching and such, we never
+ // are invoked as a phantom object
+ return false;
+ }
+ }
+ public override bool FloatOnWater {
+ set {
+ _floatOnWater = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
+ {
+ if (_floatOnWater)
+ CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
+ else
+ CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
+ });
+ }
+ }
+ public override OMV.Vector3 RotationalVelocity {
+ get {
+ return _rotationalVelocity;
+ }
+ set {
+ _rotationalVelocity = value;
+ Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
+ // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
+ PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
+ {
+ ForceRotationalVelocity = _rotationalVelocity;
+ });
+ }
+ }
+ public override OMV.Vector3 ForceRotationalVelocity {
+ get {
+ return _rotationalVelocity;
+ }
+ set {
+ _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
+ if (PhysBody.HasPhysicalBody)
+ {
+ DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
+ PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
+ // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
+ ActivateIfPhysical(false);
+ }
+ }
+ }
+ public override bool Kinematic {
+ get { return _kinematic; }
+ set { _kinematic = value;
+ // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
+ }
+ }
+ public override float Buoyancy {
+ get { return _buoyancy; }
+ set {
+ _buoyancy = value;
+ PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
+ {
+ ForceBuoyancy = _buoyancy;
+ });
+ }
+ }
+ public override float ForceBuoyancy {
+ get { return _buoyancy; }
+ set {
+ _buoyancy = value;
+ // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
+ // Force the recalculation of the various inertia,etc variables in the object
+ UpdatePhysicalMassProperties(RawMass, true);
+ DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
+ ActivateIfPhysical(false);
+ }
+ }
+
+ public override bool PIDActive
+ {
+ get
+ {
+ return MoveToTargetActive;
+ }
+
+ set
+ {
+ MoveToTargetActive = value;
+
+ EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
+ {
+ return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
+ });
+
+ // Call update so actor Refresh() is called to start things off
+ PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+
+ public override OMV.Vector3 PIDTarget
+ {
+ set
+ {
+ base.PIDTarget = value;
+ BSActor actor;
+ if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
+ {
+ // if the actor exists, tell it to refresh its values.
+ actor.Refresh();
+ }
+
+ }
+ }
+ // Used for llSetHoverHeight and maybe vehicle height
+ // Hover Height will override MoveTo target's Z
+ public override bool PIDHoverActive {
+ set {
+ base.HoverActive = value;
+ EnableActor(HoverActive, HoverActorName, delegate()
+ {
+ return new BSActorHover(PhysScene, this, HoverActorName);
+ });
+
+ // Call update so actor Refresh() is called to start things off
+ PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+ }
+
+ public override void AddForce(OMV.Vector3 force, bool pushforce) {
+ // Per documentation, max force is limited.
+ OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
+
+ // Since this force is being applied in only one step, make this a force per second.
+ addForce /= PhysScene.LastTimeStep;
+ AddForce(addForce, pushforce, false /* inTaintTime */);
+ }
+
+ // Applying a force just adds this to the total force on the object.
+ // This added force will only last the next simulation tick.
+ public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
+ // for an object, doesn't matter if force is a pushforce or not
+ if (IsPhysicallyActive)
+ {
+ if (force.IsFinite())
+ {
+ // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
+
+ OMV.Vector3 addForce = force;
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
+ {
+ // Bullet adds this central force to the total force for this tick.
+ // Deep down in Bullet:
+ // linearVelocity += totalForce / mass * timeStep;
+ DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ else
+ {
+ m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
+ return;
+ }
+ }
+ }
+
+ public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
+ // for an object, doesn't matter if force is a pushforce or not
+ if (!IsPhysicallyActive)
+ {
+ if (impulse.IsFinite())
+ {
+ OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
+ // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
+
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
+ {
+ // Bullet adds this impulse immediately to the velocity
+ DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ else
+ {
+ m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
+ return;
+ }
+ }
+ }
+
+ // BSPhysObject.AddAngularForce()
+ public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
+ {
+ if (force.IsFinite())
+ {
+ OMV.Vector3 angForce = force;
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
+ PhysScene.PE.ApplyTorque(PhysBody, angForce);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+ else
+ {
+ m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
+ return;
+ }
+ }
+
+ // A torque impulse.
+ // ApplyTorqueImpulse adds torque directly to the angularVelocity.
+ // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
+ // Computed as: angularVelocity += impulse * inertia;
+ public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
+ {
+ OMV.Vector3 applyImpulse = impulse;
+ PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
+ {
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
+ ActivateIfPhysical(false);
+ }
+ });
+ }
+
+ public override void SetMomentum(OMV.Vector3 momentum) {
+ // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
+ }
+ #region Mass Calculation
+
+ private float CalculateMass()
+ {
+ float volume = _size.X * _size.Y * _size.Z; // default
+ float tmp;
+
+ float returnMass = 0;
+ float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
+ float hollowVolume = hollowAmount * hollowAmount;
+
+ switch (BaseShape.ProfileShape)
+ {
+ case ProfileShape.Square:
+ // default box
+
+ if (BaseShape.PathCurve == (byte)Extrusion.Straight)
+ {
+ if (hollowAmount > 0.0)
+ {
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Square:
+ case HollowShape.Same:
+ break;
+
+ case HollowShape.Circle:
+
+ hollowVolume *= 0.78539816339f;
+ break;
+
+ case HollowShape.Triangle:
+
+ hollowVolume *= (0.5f * .5f);
+ break;
+
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+
+ else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
+ {
+ //a tube
+
+ volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
+ tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
+ volume -= volume*tmp*tmp;
+
+ if (hollowAmount > 0.0)
+ {
+ hollowVolume *= hollowAmount;
+
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Square:
+ case HollowShape.Same:
+ break;
+
+ case HollowShape.Circle:
+ hollowVolume *= 0.78539816339f;;
+ break;
+
+ case HollowShape.Triangle:
+ hollowVolume *= 0.5f * 0.5f;
+ break;
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+
+ break;
+
+ case ProfileShape.Circle:
+
+ if (BaseShape.PathCurve == (byte)Extrusion.Straight)
+ {
+ volume *= 0.78539816339f; // elipse base
+
+ if (hollowAmount > 0.0)
+ {
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Same:
+ case HollowShape.Circle:
+ break;
+
+ case HollowShape.Square:
+ hollowVolume *= 0.5f * 2.5984480504799f;
+ break;
+
+ case HollowShape.Triangle:
+ hollowVolume *= .5f * 1.27323954473516f;
+ break;
+
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+
+ else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
+ {
+ volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
+ tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
+ volume *= (1.0f - tmp * tmp);
+
+ if (hollowAmount > 0.0)
+ {
+
+ // calculate the hollow volume by it's shape compared to the prim shape
+ hollowVolume *= hollowAmount;
+
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Same:
+ case HollowShape.Circle:
+ break;
+
+ case HollowShape.Square:
+ hollowVolume *= 0.5f * 2.5984480504799f;
+ break;
+
+ case HollowShape.Triangle:
+ hollowVolume *= .5f * 1.27323954473516f;
+ break;
+
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+ break;
+
+ case ProfileShape.HalfCircle:
+ if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
+ {
+ volume *= 0.52359877559829887307710723054658f;
+ }
+ break;
+
+ case ProfileShape.EquilateralTriangle:
+
+ if (BaseShape.PathCurve == (byte)Extrusion.Straight)
+ {
+ volume *= 0.32475953f;
+
+ if (hollowAmount > 0.0)
+ {
+
+ // calculate the hollow volume by it's shape compared to the prim shape
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Same:
+ case HollowShape.Triangle:
+ hollowVolume *= .25f;
+ break;
+
+ case HollowShape.Square:
+ hollowVolume *= 0.499849f * 3.07920140172638f;
+ break;
+
+ case HollowShape.Circle:
+ // Hollow shape is a perfect cyllinder in respect to the cube's scale
+ // Cyllinder hollow volume calculation
+
+ hollowVolume *= 0.1963495f * 3.07920140172638f;
+ break;
+
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+ else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
+ {
+ volume *= 0.32475953f;
+ volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
+ tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
+ volume *= (1.0f - tmp * tmp);
+
+ if (hollowAmount > 0.0)
+ {
+
+ hollowVolume *= hollowAmount;
+
+ switch (BaseShape.HollowShape)
+ {
+ case HollowShape.Same:
+ case HollowShape.Triangle:
+ hollowVolume *= .25f;
+ break;
+
+ case HollowShape.Square:
+ hollowVolume *= 0.499849f * 3.07920140172638f;
+ break;
+
+ case HollowShape.Circle:
+
+ hollowVolume *= 0.1963495f * 3.07920140172638f;
+ break;
+
+ default:
+ hollowVolume = 0;
+ break;
+ }
+ volume *= (1.0f - hollowVolume);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+
+
+ float taperX1;
+ float taperY1;
+ float taperX;
+ float taperY;
+ float pathBegin;
+ float pathEnd;
+ float profileBegin;
+ float profileEnd;
+
+ if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
+ {
+ taperX1 = BaseShape.PathScaleX * 0.01f;
+ if (taperX1 > 1.0f)
+ taperX1 = 2.0f - taperX1;
+ taperX = 1.0f - taperX1;
+
+ taperY1 = BaseShape.PathScaleY * 0.01f;
+ if (taperY1 > 1.0f)
+ taperY1 = 2.0f - taperY1;
+ taperY = 1.0f - taperY1;
+ }
+ else
+ {
+ taperX = BaseShape.PathTaperX * 0.01f;
+ if (taperX < 0.0f)
+ taperX = -taperX;
+ taperX1 = 1.0f - taperX;
+
+ taperY = BaseShape.PathTaperY * 0.01f;
+ if (taperY < 0.0f)
+ taperY = -taperY;
+ taperY1 = 1.0f - taperY;
+
+ }
+
+
+ volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
+
+ pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
+ pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
+ volume *= (pathEnd - pathBegin);
+
+ // this is crude aproximation
+ profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
+ profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
+ volume *= (profileEnd - profileBegin);
+
+ returnMass = Density * BSParam.DensityScaleFactor * volume;
+
+ returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
+ // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
+ DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
+ LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
+
+ return returnMass;
+ }// end CalculateMass
+ #endregion Mass Calculation
+
+ // Rebuild the geometry and object.
+ // This is called when the shape changes so we need to recreate the mesh/hull.
+ // Called at taint-time!!!
+ public void CreateGeomAndObject(bool forceRebuild)
+ {
+ // Create the correct physical representation for this type of object.
+ // Updates base.PhysBody and base.PhysShape with the new information.
+ // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
+ PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
+ {
+ // Called if the current prim body is about to be destroyed.
+ // Remove all the physical dependencies on the old body.
+ // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
+ // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
+ RemoveDependencies();
+ });
+
+ // Make sure the properties are set on the new object
+ UpdatePhysicalParameters();
+ return;
+ }
+
+ // Called at taint-time
+ protected virtual void RemoveDependencies()
+ {
+ PhysicalActors.RemoveDependencies();
+ }
+
+ #region Extension
+ public override object Extension(string pFunct, params object[] pParams)
+ {
+ DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
+ object ret = null;
+ switch (pFunct)
+ {
+ case ExtendedPhysics.PhysFunctAxisLockLimits:
+ ret = SetAxisLockLimitsExtension(pParams);
+ break;
+ default:
+ ret = base.Extension(pFunct, pParams);
+ break;
+ }
+ return ret;
+ }
+
+ private void InitializeAxisActor()
+ {
+ EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
+ LockedAxisActorName, delegate()
+ {
+ return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
+ });
+
+ // Update parameters so the new actor's Refresh() action is called at the right time.
+ PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
+ {
+ UpdatePhysicalParameters();
+ });
+ }
+
+ // Passed an array of an array of parameters, set the axis locking.
+ // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
+ // followed by another int and floats, etc.
+ private object SetAxisLockLimitsExtension(object[] pParams)
+ {
+ DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
+ object ret = null;
+ try
+ {
+ if (pParams.GetLength(0) > 1)
+ {
+ int index = 2;
+ while (index < pParams.GetLength(0))
+ {
+ var funct = pParams[index];
+ DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
+ if (funct is Int32 || funct is Int64)
+ {
+ switch ((int)funct)
+ {
+ // Those that take no parameters
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK:
+ ApplyAxisLimits((int)funct, 0f, 0f);
+ index += 1;
+ break;
+ // Those that take two parameters (the limits)
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
+ ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
+ index += 3;
+ break;
+ default:
+ m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
+ index += 1;
+ break;
+ }
+ }
+ }
+ InitializeAxisActor();
+ ret = (object)index;
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
+ ret = null;
+ }
+ return ret; // not implemented yet
+ }
+
+ // Set the locking parameters.
+ // If an axis is locked, the limits for the axis are set to zero,
+ // If the axis is being constrained, the high and low value are passed and set.
+ // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
+ protected void ApplyAxisLimits(int funct, float low, float high)
+ {
+ DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
+ float linearMax = 23000f;
+ float angularMax = (float)Math.PI;
+
+ switch (funct)
+ {
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
+ this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
+ this.LockedLinearAxisLow = OMV.Vector3.Zero;
+ this.LockedLinearAxisHigh = OMV.Vector3.Zero;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
+ this.LockedLinearAxis.X = LockedAxis;
+ this.LockedLinearAxisLow.X = 0f;
+ this.LockedLinearAxisHigh.X = 0f;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
+ this.LockedLinearAxis.X = LockedAxis;
+ this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
+ this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
+ this.LockedLinearAxis.Y = LockedAxis;
+ this.LockedLinearAxisLow.Y = 0f;
+ this.LockedLinearAxisHigh.Y = 0f;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
+ this.LockedLinearAxis.Y = LockedAxis;
+ this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
+ this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
+ this.LockedLinearAxis.Z = LockedAxis;
+ this.LockedLinearAxisLow.Z = 0f;
+ this.LockedLinearAxisHigh.Z = 0f;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
+ this.LockedLinearAxis.Z = LockedAxis;
+ this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
+ this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
+ this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
+ this.LockedAngularAxisLow = OMV.Vector3.Zero;
+ this.LockedAngularAxisHigh = OMV.Vector3.Zero;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
+ this.LockedAngularAxis.X = LockedAxis;
+ this.LockedAngularAxisLow.X = 0;
+ this.LockedAngularAxisHigh.X = 0;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
+ this.LockedAngularAxis.X = LockedAxis;
+ this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
+ this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
+ this.LockedAngularAxis.Y = LockedAxis;
+ this.LockedAngularAxisLow.Y = 0;
+ this.LockedAngularAxisHigh.Y = 0;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
+ this.LockedAngularAxis.Y = LockedAxis;
+ this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
+ this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
+ this.LockedAngularAxis.Z = LockedAxis;
+ this.LockedAngularAxisLow.Z = 0;
+ this.LockedAngularAxisHigh.Z = 0;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
+ this.LockedAngularAxis.Z = LockedAxis;
+ this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
+ this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
+ this.LockedLinearAxis = LockedAxisFree;
+ this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
+ this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
+ this.LockedLinearAxis.X = FreeAxis;
+ this.LockedLinearAxisLow.X = -linearMax;
+ this.LockedLinearAxisHigh.X = linearMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
+ this.LockedLinearAxis.Y = FreeAxis;
+ this.LockedLinearAxisLow.Y = -linearMax;
+ this.LockedLinearAxisHigh.Y = linearMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
+ this.LockedLinearAxis.Z = FreeAxis;
+ this.LockedLinearAxisLow.Z = -linearMax;
+ this.LockedLinearAxisHigh.Z = linearMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
+ this.LockedAngularAxis = LockedAxisFree;
+ this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
+ this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
+ this.LockedAngularAxis.X = FreeAxis;
+ this.LockedAngularAxisLow.X = -angularMax;
+ this.LockedAngularAxisHigh.X = angularMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
+ this.LockedAngularAxis.Y = FreeAxis;
+ this.LockedAngularAxisLow.Y = -angularMax;
+ this.LockedAngularAxisHigh.Y = angularMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
+ this.LockedAngularAxis.Z = FreeAxis;
+ this.LockedAngularAxisLow.Z = -angularMax;
+ this.LockedAngularAxisHigh.Z = angularMax;
+ break;
+ case ExtendedPhysics.PHYS_AXIS_UNLOCK:
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
+ ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ #endregion // Extension
+
+ // The physics engine says that properties have updated. Update same and inform
+ // the world that things have changed.
+ // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
+ // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
+ public override void UpdateProperties(EntityProperties entprop)
+ {
+ // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
+ TriggerPreUpdatePropertyAction(ref entprop);
+
+ // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
+
+ // Assign directly to the local variables so the normal set actions do not happen
+ RawPosition = entprop.Position;
+ RawOrientation = entprop.Rotation;
+ // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
+ // very sensitive to velocity changes.
+ if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
+ RawVelocity = entprop.Velocity;
+ _acceleration = entprop.Acceleration;
+ _rotationalVelocity = entprop.RotationalVelocity;
+
+ // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
+
+ // The sanity check can change the velocity and/or position.
+ if (PositionSanityCheck(true /* inTaintTime */ ))
+ {
+ entprop.Position = RawPosition;
+ entprop.Velocity = RawVelocity;
+ entprop.RotationalVelocity = _rotationalVelocity;
+ entprop.Acceleration = _acceleration;
+ }
+
+ OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
+ DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
+
+ // remember the current and last set values
+ LastEntityProperties = CurrentEntityProperties;
+ CurrentEntityProperties = entprop;
+
+ PhysScene.PostUpdate(this);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
new file mode 100755
index 0000000..2eb1440
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSPrimDisplaced : BSPrim
+{
+ // The purpose of this subclass is to do any mapping between what the simulator thinks
+ // the prim position and orientation is and what the physical position/orientation.
+ // This difference happens because Bullet assumes the center-of-mass is the <0,0,0>
+ // of the prim/linkset. The simulator, on the other hand, tracks the location of
+ // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere
+ // but the origin of the root prim, the physical origin is displaced from the simulator origin.
+ //
+ // This routine works by capturing ForcePosition and
+ // adjusting the simulator values (being set) into the physical values.
+ // The conversion is also done in the opposite direction (physical origin -> simulator origin).
+ //
+ // The updateParameter call is also captured and the values from the physics engine
+ // are converted into simulator origin values before being passed to the base
+ // class.
+
+ // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass.
+ public virtual OMV.Vector3 PositionDisplacement { get; set; }
+
+ public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
+ OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
+ : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
+ {
+ ClearDisplacement();
+ }
+
+ // Clears any center-of-mass displacement introduced by linksets, etc.
+ // Does not clear the displacement set by the user.
+ public void ClearDisplacement()
+ {
+ if (UserSetCenterOfMassDisplacement.HasValue)
+ PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement;
+ else
+ PositionDisplacement = OMV.Vector3.Zero;
+ }
+
+ // Set this sets and computes the displacement from the passed prim to the center-of-mass.
+ // A user set value for center-of-mass overrides whatever might be passed in here.
+ // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates).
+ // Returns the relative offset from the root position to the center-of-mass.
+ // Called at taint time.
+ public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement)
+ {
+ PhysScene.AssertInTaintTime("BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement");
+ Vector3 comDisp;
+ if (UserSetCenterOfMassDisplacement.HasValue)
+ comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement;
+ else
+ comDisp = centerOfMassDisplacement;
+
+ // Eliminate any jitter caused be very slight differences in masses and positions
+ if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) )
+ comDisp = Vector3.Zero;
+
+ DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}",
+ LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp);
+ if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) )
+ {
+ // Displacement setting is changing.
+ // The relationship between the physical object and simulated object must be aligned.
+ PositionDisplacement = comDisp;
+ this.ForcePosition = RawPosition;
+ }
+
+ return PositionDisplacement;
+ }
+
+ // 'ForcePosition' is the one way to set the physical position of the body in the physics engine.
+ // Displace the simulator idea of position (center of root prim) to the physical position.
+ public override Vector3 ForcePosition
+ {
+ get {
+ OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody);
+ if (PositionDisplacement != OMV.Vector3.Zero)
+ {
+ // If there is some displacement, return the physical position (center-of-mass)
+ // location minus the displacement to give the center of the root prim.
+ OMV.Vector3 displacement = PositionDisplacement * ForceOrientation;
+ DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}",
+ LocalID, physPosition, displacement, physPosition - displacement);
+ physPosition -= displacement;
+ }
+ RawPosition = physPosition;
+ return physPosition;
+ }
+ set
+ {
+ if (PositionDisplacement != OMV.Vector3.Zero)
+ {
+ // This value is the simulator's idea of where the prim is: the center of the root prim
+ RawPosition = value;
+
+ // Move the passed root prim postion to the center-of-mass position and set in the physics engine.
+ OMV.Vector3 displacement = PositionDisplacement * RawOrientation;
+ OMV.Vector3 displacedPos = RawPosition + displacement;
+ DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}",
+ LocalID, RawPosition, displacement, displacedPos);
+ if (PhysBody.HasPhysicalBody)
+ {
+ PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation);
+ ActivateIfPhysical(false);
+ }
+ }
+ else
+ {
+ base.ForcePosition = value;
+ }
+ }
+ }
+
+ // These are also overridden by BSPrimLinkable if the prim can be part of a linkset
+ public override OMV.Vector3 CenterOfMass
+ {
+ get { return RawPosition; }
+ }
+
+ public override OMV.Vector3 GeometricCenter
+ {
+ get { return RawPosition; }
+ }
+
+ public override void UpdateProperties(EntityProperties entprop)
+ {
+ // Undo any center-of-mass displacement that might have been done.
+ if (PositionDisplacement != OMV.Vector3.Zero)
+ {
+ // The origional shape was offset from 'zero' by PositionDisplacement.
+ // These physical location must be back converted to be centered around the displaced
+ // root shape.
+
+ // Move the returned center-of-mass location to the root prim location.
+ OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation;
+ OMV.Vector3 displacedPos = entprop.Position - displacement;
+ DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}",
+ LocalID, entprop.Position, displacement, displacedPos);
+ entprop.Position = displacedPos;
+ }
+
+ base.UpdateProperties(entprop);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
new file mode 100755
index 0000000..430d645
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using OpenSim.Framework;
+using OpenSim.Region.OptionalModules.Scripting;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public class BSPrimLinkable : BSPrimDisplaced
+{
+ // The purpose of this subclass is to add linkset functionality to the prim. This overrides
+ // operations necessary for keeping the linkset created and, additionally, this
+ // calls the linkset implementation for its creation and management.
+
+#pragma warning disable 414
+ private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]";
+#pragma warning restore 414
+
+ // This adds the overrides for link() and delink() so the prim is linkable.
+
+ public BSLinkset Linkset { get; set; }
+ // The index of this child prim.
+ public int LinksetChildIndex { get; set; }
+
+ public BSLinkset.LinksetImplementation LinksetType { get; set; }
+
+ public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
+ OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
+ : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)
+ {
+ // Default linkset implementation for this prim
+ LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation;
+
+ Linkset = BSLinkset.Factory(PhysScene, this);
+
+ Linkset.Refresh(this);
+ }
+
+ public override void Destroy()
+ {
+ Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */);
+ base.Destroy();
+ }
+
+ public override void link(Manager.PhysicsActor obj)
+ {
+ BSPrimLinkable parent = obj as BSPrimLinkable;
+ if (parent != null)
+ {
+ BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
+ int childrenBefore = Linkset.NumberOfChildren; // DEBUG
+
+ Linkset = parent.Linkset.AddMeToLinkset(this);
+
+ DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
+ LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
+ }
+ return;
+ }
+
+ public override void delink()
+ {
+ // TODO: decide if this parent checking needs to happen at taint time
+ // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
+
+ BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG
+ int childrenBefore = Linkset.NumberOfChildren; // DEBUG
+
+ Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/);
+
+ DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
+ LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
+ return;
+ }
+
+ // When simulator changes position, this might be moving a child of the linkset.
+ public override OMV.Vector3 Position
+ {
+ get { return base.Position; }
+ set
+ {
+ base.Position = value;
+ PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate()
+ {
+ Linkset.UpdateProperties(UpdatedProperties.Position, this);
+ });
+ }
+ }
+
+ // When simulator changes orientation, this might be moving a child of the linkset.
+ public override OMV.Quaternion Orientation
+ {
+ get { return base.Orientation; }
+ set
+ {
+ base.Orientation = value;
+ PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate()
+ {
+ Linkset.UpdateProperties(UpdatedProperties.Orientation, this);
+ });
+ }
+ }
+
+ public override float TotalMass
+ {
+ get { return Linkset.LinksetMass; }
+ }
+
+ public override OMV.Vector3 CenterOfMass
+ {
+ get { return Linkset.CenterOfMass; }
+ }
+
+ public override OMV.Vector3 GeometricCenter
+ {
+ get { return Linkset.GeometricCenter; }
+ }
+
+ // Refresh the linkset structure and parameters when the prim's physical parameters are changed.
+ public override void UpdatePhysicalParameters()
+ {
+ base.UpdatePhysicalParameters();
+ // Recompute any linkset parameters.
+ // When going from non-physical to physical, this re-enables the constraints that
+ // had been automatically disabled when the mass was set to zero.
+ // For compound based linksets, this enables and disables interactions of the children.
+ if (Linkset != null) // null can happen during initialization
+ Linkset.Refresh(this);
+ }
+
+ // When the prim is made dynamic or static, the linkset needs to change.
+ protected override void MakeDynamic(bool makeStatic)
+ {
+ base.MakeDynamic(makeStatic);
+ if (Linkset != null) // null can happen during initialization
+ {
+ if (makeStatic)
+ Linkset.MakeStatic(this);
+ else
+ Linkset.MakeDynamic(this);
+ }
+ }
+
+ // Body is being taken apart. Remove physical dependencies and schedule a rebuild.
+ protected override void RemoveDependencies()
+ {
+ Linkset.RemoveDependencies(this);
+ base.RemoveDependencies();
+ }
+
+ // Called after a simulation step for the changes in physical object properties.
+ // Do any filtering/modification needed for linksets.
+ public override void UpdateProperties(EntityProperties entprop)
+ {
+ if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this))
+ {
+ // Properties are only updated for the roots of a linkset.
+ // TODO: this will have to change when linksets are articulated.
+ base.UpdateProperties(entprop);
+ }
+ /*
+ else
+ {
+ // For debugging, report the movement of children
+ DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
+ LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
+ entprop.Acceleration, entprop.RotationalVelocity);
+ }
+ */
+ // The linkset might like to know about changing locations
+ Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
+ }
+
+ // Called after a simulation step to post a collision with this object.
+ // This returns 'true' if the collision has been queued and the SendCollisions call must
+ // be made at the end of the simulation step.
+ public override bool Collide(uint collidingWith, BSPhysObject collidee,
+ OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
+ {
+ bool ret = false;
+ // Ask the linkset if it wants to handle the collision
+ if (!Linkset.HandleCollide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth))
+ {
+ // The linkset didn't handle it so pass the collision through normal processing
+ ret = base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
+ }
+ return ret;
+ }
+
+ // A linkset reports any collision on any part of the linkset.
+ public long SomeCollisionSimulationStep = 0;
+ public override bool HasSomeCollision
+ {
+ get
+ {
+ return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding;
+ }
+ set
+ {
+ if (value)
+ SomeCollisionSimulationStep = PhysScene.SimulationStep;
+ else
+ SomeCollisionSimulationStep = 0;
+
+ base.HasSomeCollision = value;
+ }
+ }
+
+ // Convert the existing linkset of this prim into a new type.
+ public bool ConvertLinkset(BSLinkset.LinksetImplementation newType)
+ {
+ bool ret = false;
+ if (LinksetType != newType)
+ {
+ DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType);
+
+ // Set the implementation type first so the call to BSLinkset.Factory gets the new type.
+ this.LinksetType = newType;
+
+ BSLinkset oldLinkset = this.Linkset;
+ BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this);
+
+ this.Linkset = newLinkset;
+
+ // Pick up any physical dependencies this linkset might have in the physics engine.
+ oldLinkset.RemoveDependencies(this);
+
+ // Create a list of the children (mainly because can't interate through a list that's changing)
+ List children = new List();
+ oldLinkset.ForEachMember((child) =>
+ {
+ if (!oldLinkset.IsRoot(child))
+ children.Add(child);
+ return false; // 'false' says to continue to next member
+ });
+
+ // Remove the children from the old linkset and add to the new (will be a new instance from the factory)
+ foreach (BSPrimLinkable child in children)
+ {
+ oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/);
+ }
+ foreach (BSPrimLinkable child in children)
+ {
+ newLinkset.AddMeToLinkset(child);
+ child.Linkset = newLinkset;
+ }
+
+ // Force the shape and linkset to get reconstructed
+ newLinkset.Refresh(this);
+ this.ForceBodyShapeRebuild(true /* inTaintTime */);
+ }
+ return ret;
+ }
+
+ #region Extension
+ public override object Extension(string pFunct, params object[] pParams)
+ {
+ DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length);
+ object ret = null;
+ switch (pFunct)
+ {
+ // physGetLinksetType();
+ // pParams = [ BSPhysObject root, null ]
+ case ExtendedPhysics.PhysFunctGetLinksetType:
+ {
+ ret = (object)LinksetType;
+ DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret);
+ break;
+ }
+ // physSetLinksetType(type);
+ // pParams = [ BSPhysObject root, null, integer type ]
+ case ExtendedPhysics.PhysFunctSetLinksetType:
+ {
+ if (pParams.Length > 2)
+ {
+ BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2];
+ if (Linkset.IsRoot(this))
+ {
+ PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate()
+ {
+ // Cause the linkset type to change
+ DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}",
+ LocalID, Linkset.LinksetImpl, linksetType);
+ ConvertLinkset(linksetType);
+ });
+ }
+ ret = (object)(int)linksetType;
+ }
+ break;
+ }
+ // physChangeLinkType(linknum, typeCode);
+ // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ]
+ case ExtendedPhysics.PhysFunctChangeLinkType:
+ {
+ ret = Linkset.Extension(pFunct, pParams);
+ break;
+ }
+ // physGetLinkType(linknum);
+ // pParams = [ BSPhysObject root, BSPhysObject child ]
+ case ExtendedPhysics.PhysFunctGetLinkType:
+ {
+ ret = Linkset.Extension(pFunct, pParams);
+ break;
+ }
+ // physChangeLinkParams(linknum, [code, value, code, value, ...]);
+ // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ]
+ case ExtendedPhysics.PhysFunctChangeLinkParams:
+ {
+ ret = Linkset.Extension(pFunct, pParams);
+ break;
+ }
+ default:
+ ret = base.Extension(pFunct, pParams);
+ break;
+ }
+ return ret;
+ }
+ #endregion // Extension
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
new file mode 100644
index 0000000..8a19944
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSScene.cs
@@ -0,0 +1,1281 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using OpenSim.Framework;
+using OpenSim.Framework.Monitoring;
+using OpenSim.Region.Framework;
+using OpenSim.Region.CoreModules;
+using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging;
+using OpenSim.Region.Physics.Manager;
+using Nini.Config;
+using log4net;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSScene : PhysicsScene, IPhysicsParameters
+{
+ internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ internal static readonly string LogHeader = "[BULLETS SCENE]";
+
+ // The name of the region we're working for.
+ public string RegionName { get; private set; }
+
+ public string BulletSimVersion = "?";
+
+ // The handle to the underlying managed or unmanaged version of Bullet being used.
+ public string BulletEngineName { get; private set; }
+ public BSAPITemplate PE;
+
+ // If the physics engine is running on a separate thread
+ public Thread m_physicsThread;
+
+ public Dictionary PhysObjects;
+ public BSShapeCollection Shapes;
+
+ // Keeping track of the objects with collisions so we can report begin and end of a collision
+ public HashSet ObjectsWithCollisions = new HashSet();
+ public HashSet ObjectsWithNoMoreCollisions = new HashSet();
+
+ // All the collision processing is protected with this lock object
+ public Object CollisionLock = new Object();
+
+ // Properties are updated here
+ public Object UpdateLock = new Object();
+ public HashSet ObjectsWithUpdates = new HashSet();
+
+ // Keep track of all the avatars so we can send them a collision event
+ // every tick so OpenSim will update its animation.
+ private HashSet AvatarsInScene = new HashSet();
+ private Object AvatarsInSceneLock = new Object();
+
+ // let my minuions use my logger
+ public ILog Logger { get { return m_log; } }
+
+ public IMesher mesher;
+ public uint WorldID { get; private set; }
+ public BulletWorld World { get; private set; }
+
+ // All the constraints that have been allocated in this instance.
+ public BSConstraintCollection Constraints { get; private set; }
+
+ // Simulation parameters
+ //internal float m_physicsStepTime; // if running independently, the interval simulated by default
+
+ internal int m_maxSubSteps;
+ internal float m_fixedTimeStep;
+
+ internal float m_simulatedTime; // the time simulated previously. Used for physics framerate calc.
+
+ internal long m_simulationStep = 0; // The current simulation step.
+ public long SimulationStep { get { return m_simulationStep; } }
+ // A number to use for SimulationStep that is probably not any step value
+ // Used by the collision code (which remembers the step when a collision happens) to remember not any simulation step.
+ public static long NotASimulationStep = -1234;
+
+ internal float LastTimeStep { get; private set; } // The simulation time from the last invocation of Simulate()
+
+ internal float NominalFrameRate { get; set; } // Parameterized ideal frame rate that simulation is scaled to
+
+ // Physical objects can register for prestep or poststep events
+ public delegate void PreStepAction(float timeStep);
+ public delegate void PostStepAction(float timeStep);
+ public event PreStepAction BeforeStep;
+ public event PostStepAction AfterStep;
+
+ // A value of the time 'now' so all the collision and update routines do not have to get their own
+ // Set to 'now' just before all the prims and actors are called for collisions and updates
+ public int SimulationNowTime { get; private set; }
+
+ // True if initialized and ready to do simulation steps
+ private bool m_initialized = false;
+
+ // Flag which is true when processing taints.
+ // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
+ public bool InTaintTime { get; private set; }
+
+ // Pinned memory used to pass step information between managed and unmanaged
+ internal int m_maxCollisionsPerFrame;
+ internal CollisionDesc[] m_collisionArray;
+
+ internal int m_maxUpdatesPerFrame;
+ internal EntityProperties[] m_updateArray;
+
+ ///
+ /// Used to control physics simulation timing if Bullet is running on its own thread.
+ ///
+ private ManualResetEvent m_updateWaitEvent;
+
+ public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
+ public const uint GROUNDPLANE_ID = 1;
+ public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
+
+ public float SimpleWaterLevel { get; set; }
+ public BSTerrainManager TerrainManager { get; private set; }
+
+ public ConfigurationParameters Params
+ {
+ get { return UnmanagedParams[0]; }
+ }
+ public Vector3 DefaultGravity
+ {
+ get { return new Vector3(0f, 0f, Params.gravity); }
+ }
+ // Just the Z value of the gravity
+ public float DefaultGravityZ
+ {
+ get { return Params.gravity; }
+ }
+
+ // When functions in the unmanaged code must be called, it is only
+ // done at a known time just before the simulation step. The taint
+ // system saves all these function calls and executes them in
+ // order before the simulation.
+ public delegate void TaintCallback();
+ private struct TaintCallbackEntry
+ {
+ public String originator;
+ public String ident;
+ public TaintCallback callback;
+ public TaintCallbackEntry(string pIdent, TaintCallback pCallBack)
+ {
+ originator = BSScene.DetailLogZero;
+ ident = pIdent;
+ callback = pCallBack;
+ }
+ public TaintCallbackEntry(string pOrigin, string pIdent, TaintCallback pCallBack)
+ {
+ originator = pOrigin;
+ ident = pIdent;
+ callback = pCallBack;
+ }
+ }
+ private Object _taintLock = new Object(); // lock for using the next object
+ private List _taintOperations;
+ private Dictionary _postTaintOperations;
+ private List _postStepOperations;
+
+ // A pointer to an instance if this structure is passed to the C++ code
+ // Used to pass basic configuration values to the unmanaged code.
+ internal ConfigurationParameters[] UnmanagedParams;
+
+ // Sometimes you just have to log everything.
+ public Logging.LogWriter PhysicsLogging;
+ private bool m_physicsLoggingEnabled;
+ private string m_physicsLoggingDir;
+ private string m_physicsLoggingPrefix;
+ private int m_physicsLoggingFileMinutes;
+ private bool m_physicsLoggingDoFlush;
+ private bool m_physicsPhysicalDumpEnabled;
+ public int PhysicsMetricDumpFrames { get; set; }
+ // 'true' of the vehicle code is to log lots of details
+ public bool VehicleLoggingEnabled { get; private set; }
+ public bool VehiclePhysicalLoggingEnabled { get; private set; }
+
+ #region Construction and Initialization
+ public BSScene(string engineType, string identifier)
+ {
+ m_initialized = false;
+
+ // The name of the region we're working for is passed to us. Keep for identification.
+ RegionName = identifier;
+
+ // Set identifying variables in the PhysicsScene interface.
+ EngineType = engineType;
+ Name = EngineType + "/" + RegionName;
+ }
+
+ // Old version of initialization that assumes legacy sized regions (256x256)
+ public override void Initialise(IMesher meshmerizer, IConfigSource config)
+ {
+ m_log.ErrorFormat("{0} WARNING WARNING WARNING! BulletSim initialized without region extent specification. Terrain will be messed up.");
+ Vector3 regionExtent = new Vector3( Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
+ Initialise(meshmerizer, config, regionExtent);
+
+ }
+
+ public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
+ {
+ mesher = meshmerizer;
+ _taintOperations = new List();
+ _postTaintOperations = new Dictionary();
+ _postStepOperations = new List();
+ PhysObjects = new Dictionary();
+ Shapes = new BSShapeCollection(this);
+
+ m_simulatedTime = 0f;
+ LastTimeStep = 0.1f;
+
+ // Allocate pinned memory to pass parameters.
+ UnmanagedParams = new ConfigurationParameters[1];
+
+ // Set default values for physics parameters plus any overrides from the ini file
+ GetInitialParameterValues(config);
+
+ // Force some parameters to values depending on other configurations
+ // Only use heightmap terrain implementation if terrain larger than legacy size
+ if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
+ {
+ m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
+ BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
+ }
+
+ // Get the connection to the physics engine (could be native or one of many DLLs)
+ PE = SelectUnderlyingBulletEngine(BulletEngineName);
+
+ // Enable very detailed logging.
+ // By creating an empty logger when not logging, the log message invocation code
+ // can be left in and every call doesn't have to check for null.
+ if (m_physicsLoggingEnabled)
+ {
+ PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes, m_physicsLoggingDoFlush);
+ PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output its own error messages.
+ }
+ else
+ {
+ PhysicsLogging = new Logging.LogWriter();
+ }
+
+ // Allocate memory for returning of the updates and collisions from the physics engine
+ m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
+ m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
+
+ // The bounding box for the simulated world. The origin is 0,0,0 unless we're
+ // a child in a mega-region.
+ // Bullet actually doesn't care about the extents of the simulated
+ // area. It tracks active objects no matter where they are.
+ Vector3 worldExtent = regionExtent;
+
+ World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
+
+ Constraints = new BSConstraintCollection(World);
+
+ TerrainManager = new BSTerrainManager(this, worldExtent);
+ TerrainManager.CreateInitialGroundPlaneAndTerrain();
+
+ // Put some informational messages into the log file.
+ m_log.InfoFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
+
+ InTaintTime = false;
+ m_initialized = true;
+
+ // If the physics engine runs on its own thread, start same.
+ if (BSParam.UseSeparatePhysicsThread)
+ {
+ // The physics simulation should happen independently of the heartbeat loop
+ m_physicsThread
+ = WorkManager.StartThread(
+ BulletSPluginPhysicsThread,
+ string.Format("{0} ({1})", BulletEngineName, RegionName),
+ ThreadPriority.Normal,
+ true,
+ true);
+ }
+ }
+
+ // All default parameter values are set here. There should be no values set in the
+ // variable definitions.
+ private void GetInitialParameterValues(IConfigSource config)
+ {
+ ConfigurationParameters parms = new ConfigurationParameters();
+ UnmanagedParams[0] = parms;
+
+ BSParam.SetParameterDefaultValues(this);
+
+ if (config != null)
+ {
+ // If there are specifications in the ini file, use those values
+ IConfig pConfig = config.Configs["BulletSim"];
+ if (pConfig != null)
+ {
+ BSParam.SetParameterConfigurationValues(this, pConfig);
+
+ // There are two Bullet implementations to choose from
+ BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
+
+ // Very detailed logging for physics debugging
+ // TODO: the boolean values can be moved to the normal parameter processing.
+ m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
+ m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
+ m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
+ m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
+ m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
+ m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
+ // Very detailed logging for vehicle debugging
+ VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
+ VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
+
+ // Do any replacements in the parameters
+ m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
+ }
+ else
+ {
+ // Nothing in the configuration INI file so assume unmanaged and other defaults.
+ BulletEngineName = "BulletUnmanaged";
+ m_physicsLoggingEnabled = false;
+ VehicleLoggingEnabled = false;
+ }
+
+ // The material characteristics.
+ BSMaterials.InitializeFromDefaults(Params);
+ if (pConfig != null)
+ {
+ // Let the user add new and interesting material property values.
+ BSMaterials.InitializefromParameters(pConfig);
+ }
+ }
+ }
+
+ // A helper function that handles a true/false parameter and returns the proper float number encoding
+ float ParamBoolean(IConfig config, string parmName, float deflt)
+ {
+ float ret = deflt;
+ if (config.Contains(parmName))
+ {
+ ret = ConfigurationParameters.numericFalse;
+ if (config.GetBoolean(parmName, false))
+ {
+ ret = ConfigurationParameters.numericTrue;
+ }
+ }
+ return ret;
+ }
+
+ // Select the connection to the actual Bullet implementation.
+ // The main engine selection is the engineName up to the first hypen.
+ // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
+ // is passed to the engine to do its special selection, etc.
+ private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
+ {
+ // For the moment, do a simple switch statement.
+ // Someday do fancyness with looking up the interfaces in the assembly.
+ BSAPITemplate ret = null;
+
+ string selectionName = engineName.ToLower();
+ int hyphenIndex = engineName.IndexOf("-");
+ if (hyphenIndex > 0)
+ selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
+
+ switch (selectionName)
+ {
+ case "bullet":
+ case "bulletunmanaged":
+ ret = new BSAPIUnman(engineName, this);
+ break;
+ case "bulletxna":
+ ret = new BSAPIXNA(engineName, this);
+ // Disable some features that are not implemented in BulletXNA
+ m_log.InfoFormat("{0} Disabling some physics features not implemented by BulletXNA", LogHeader);
+ m_log.InfoFormat("{0} Disabling ShouldUseBulletHACD", LogHeader);
+ BSParam.ShouldUseBulletHACD = false;
+ m_log.InfoFormat("{0} Disabling ShouldUseSingleConvexHullForPrims", LogHeader);
+ BSParam.ShouldUseSingleConvexHullForPrims = false;
+ m_log.InfoFormat("{0} Disabling ShouldUseGImpactShapeForPrims", LogHeader);
+ BSParam.ShouldUseGImpactShapeForPrims = false;
+ m_log.InfoFormat("{0} Setting terrain implimentation to Heightmap", LogHeader);
+ BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
+ break;
+ }
+
+ if (ret == null)
+ {
+ m_log.ErrorFormat("{0} COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
+ }
+ else
+ {
+ m_log.InfoFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
+ }
+
+ return ret;
+ }
+
+ public override void Dispose()
+ {
+ // m_log.DebugFormat("{0}: Dispose()", LogHeader);
+
+ // make sure no stepping happens while we're deleting stuff
+ m_initialized = false;
+
+ lock (PhysObjects)
+ {
+ foreach (KeyValuePair kvp in PhysObjects)
+ {
+ kvp.Value.Destroy();
+ }
+ PhysObjects.Clear();
+ }
+
+ // Now that the prims are all cleaned up, there should be no constraints left
+ if (Constraints != null)
+ {
+ Constraints.Dispose();
+ Constraints = null;
+ }
+
+ if (Shapes != null)
+ {
+ Shapes.Dispose();
+ Shapes = null;
+ }
+
+ if (TerrainManager != null)
+ {
+ TerrainManager.ReleaseGroundPlaneAndTerrain();
+ TerrainManager.Dispose();
+ TerrainManager = null;
+ }
+
+ // Anything left in the unmanaged code should be cleaned out
+ PE.Shutdown(World);
+
+ // Not logging any more
+ PhysicsLogging.Close();
+ }
+ #endregion // Construction and Initialization
+
+ #region Prim and Avatar addition and removal
+
+ public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
+ {
+ m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
+ return null;
+ }
+
+ public override PhysicsActor AddAvatar(uint localID, string avName, Vector3 position, Vector3 velocity, Vector3 size, bool isFlying)
+ {
+ // m_log.DebugFormat("{0}: AddAvatar: {1}", LogHeader, avName);
+
+ if (!m_initialized) return null;
+
+ BSCharacter actor = new BSCharacter(localID, avName, this, position, velocity, size, isFlying);
+ lock (PhysObjects)
+ PhysObjects.Add(localID, actor);
+
+ // TODO: Remove kludge someday.
+ // We must generate a collision for avatars whether they collide or not.
+ // This is required by OpenSim to update avatar animations, etc.
+ lock (AvatarsInSceneLock)
+ AvatarsInScene.Add(actor);
+
+ return actor;
+ }
+
+ public override void RemoveAvatar(PhysicsActor actor)
+ {
+ // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader);
+
+ if (!m_initialized) return;
+
+ BSCharacter bsactor = actor as BSCharacter;
+ if (bsactor != null)
+ {
+ try
+ {
+ lock (PhysObjects)
+ PhysObjects.Remove(bsactor.LocalID);
+ // Remove kludge someday
+ lock (AvatarsInSceneLock)
+ AvatarsInScene.Remove(bsactor);
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e);
+ }
+ bsactor.Destroy();
+ // bsactor.dispose();
+ }
+ else
+ {
+ m_log.ErrorFormat("{0}: Requested to remove avatar that is not a BSCharacter. ID={1}, type={2}",
+ LogHeader, actor.LocalID, actor.GetType().Name);
+ }
+ }
+
+ public override void RemovePrim(PhysicsActor prim)
+ {
+ if (!m_initialized) return;
+
+ BSPhysObject bsprim = prim as BSPhysObject;
+ if (bsprim != null)
+ {
+ DetailLog("{0},RemovePrim,call", bsprim.LocalID);
+ // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
+ try
+ {
+ lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e);
+ }
+ bsprim.Destroy();
+ // bsprim.dispose();
+ }
+ else
+ {
+ m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader);
+ }
+ }
+
+ public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position,
+ Vector3 size, Quaternion rotation, bool isPhysical, uint localID)
+ {
+ // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName);
+
+ if (!m_initialized) return null;
+
+ // DetailLog("{0},BSScene.AddPrimShape,call", localID);
+
+ BSPhysObject prim = new BSPrimLinkable(localID, primName, this, position, size, rotation, pbs, isPhysical);
+ lock (PhysObjects) PhysObjects.Add(localID, prim);
+ return prim;
+ }
+
+ // This is a call from the simulator saying that some physical property has been updated.
+ // The BulletSim driver senses the changing of relevant properties so this taint
+ // information call is not needed.
+ public override void AddPhysicsActorTaint(PhysicsActor prim) { }
+
+ #endregion // Prim and Avatar addition and removal
+
+ #region Simulation
+
+ // Call from the simulator to send physics information to the simulator objects.
+ // This pushes all the collision and property update events into the objects in
+ // the simulator and, since it is on the heartbeat thread, there is an implicit
+ // locking of those data structures from other heartbeat events.
+ // If the physics engine is running on a separate thread, the update information
+ // will be in the ObjectsWithCollions and ObjectsWithUpdates structures.
+ public override float Simulate(float timeStep)
+ {
+ if (!BSParam.UseSeparatePhysicsThread)
+ {
+ DoPhysicsStep(timeStep);
+ }
+ return SendUpdatesToSimulator(timeStep);
+ }
+
+ // Call the physics engine to do one 'timeStep' and collect collisions and updates
+ // into ObjectsWithCollisions and ObjectsWithUpdates data structures.
+ private void DoPhysicsStep(float timeStep)
+ {
+ // prevent simulation until we've been initialized
+ if (!m_initialized) return;
+
+ LastTimeStep = timeStep;
+
+ int updatedEntityCount = 0;
+ int collidersCount = 0;
+
+ int beforeTime = Util.EnvironmentTickCount();
+ int simTime = 0;
+
+ int numTaints = _taintOperations.Count;
+ InTaintTime = true; // Only used for debugging so locking is not necessary.
+
+ // update the prim states while we know the physics engine is not busy
+ ProcessTaints();
+
+ // Some of the physical objects requre individual, pre-step calls
+ // (vehicles and avatar movement, in particular)
+ TriggerPreStepEvent(timeStep);
+
+ // the prestep actions might have added taints
+ numTaints += _taintOperations.Count;
+ ProcessTaints();
+
+ InTaintTime = false; // Only used for debugging so locking is not necessary.
+
+ // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
+ // Only enable this in a limited test world with few objects.
+ if (m_physicsPhysicalDumpEnabled)
+ PE.DumpAllInfo(World);
+
+ // step the physical world one interval
+ m_simulationStep++;
+ int numSubSteps = 0;
+ try
+ {
+ numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
+
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
+ LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
+ DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
+ DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
+ updatedEntityCount = 0;
+ collidersCount = 0;
+ }
+
+ // Make the physics engine dump useful statistics periodically
+ if (PhysicsMetricDumpFrames != 0 && ((m_simulationStep % PhysicsMetricDumpFrames) == 0))
+ PE.DumpPhysicsStatistics(World);
+
+ // Get a value for 'now' so all the collision and update routines don't have to get their own.
+ SimulationNowTime = Util.EnvironmentTickCount();
+
+ // Send collision information to the colliding objects. The objects decide if the collision
+ // is 'real' (like linksets don't collide with themselves) and the individual objects
+ // know if the simulator has subscribed to collisions.
+ lock (CollisionLock)
+ {
+ if (collidersCount > 0)
+ {
+ lock (PhysObjects)
+ {
+ for (int ii = 0; ii < collidersCount; ii++)
+ {
+ uint cA = m_collisionArray[ii].aID;
+ uint cB = m_collisionArray[ii].bID;
+ Vector3 point = m_collisionArray[ii].point;
+ Vector3 normal = m_collisionArray[ii].normal;
+ float penetration = m_collisionArray[ii].penetration;
+ SendCollision(cA, cB, point, normal, penetration);
+ SendCollision(cB, cA, point, -normal, penetration);
+ }
+ }
+ }
+ }
+
+ // If any of the objects had updated properties, tell the managed objects about the update
+ // and remember that there was a change so it will be passed to the simulator.
+ lock (UpdateLock)
+ {
+ if (updatedEntityCount > 0)
+ {
+ lock (PhysObjects)
+ {
+ for (int ii = 0; ii < updatedEntityCount; ii++)
+ {
+ EntityProperties entprop = m_updateArray[ii];
+ BSPhysObject pobj;
+ if (PhysObjects.TryGetValue(entprop.ID, out pobj))
+ {
+ if (pobj.IsInitialized)
+ pobj.UpdateProperties(entprop);
+ }
+ }
+ }
+ }
+ }
+
+ // Some actors want to know when the simulation step is complete.
+ TriggerPostStepEvent(timeStep);
+
+ simTime = Util.EnvironmentTickCountSubtract(beforeTime);
+ if (PhysicsLogging.Enabled)
+ {
+ DetailLog("{0},DoPhysicsStep,complete,frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
+ DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
+ updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
+ }
+
+ // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
+ // Only enable this in a limited test world with few objects.
+ if (m_physicsPhysicalDumpEnabled)
+ PE.DumpAllInfo(World);
+
+ // The physics engine returns the number of milliseconds it simulated this call.
+ // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
+ // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
+ m_simulatedTime += (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
+ }
+
+ // Called by a BSPhysObject to note that it has changed properties and this information
+ // should be passed up to the simulator at the proper time.
+ // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
+ // this is is under UpdateLock.
+ public void PostUpdate(BSPhysObject updatee)
+ {
+ lock (UpdateLock)
+ {
+ ObjectsWithUpdates.Add(updatee);
+ }
+ }
+
+ // The simulator thinks it is physics time so return all the collisions and position
+ // updates that were collected in actual physics simulation.
+ private float SendUpdatesToSimulator(float timeStep)
+ {
+ if (!m_initialized) return 5.0f;
+
+ DetailLog("{0},SendUpdatesToSimulator,collisions={1},updates={2},simedTime={3}",
+ BSScene.DetailLogZero, ObjectsWithCollisions.Count, ObjectsWithUpdates.Count, m_simulatedTime);
+ // Push the collisions into the simulator.
+ lock (CollisionLock)
+ {
+ if (ObjectsWithCollisions.Count > 0)
+ {
+ foreach (BSPhysObject bsp in ObjectsWithCollisions)
+ if (!bsp.SendCollisions())
+ {
+ // If the object is done colliding, see that it's removed from the colliding list
+ ObjectsWithNoMoreCollisions.Add(bsp);
+ }
+ }
+
+ // This is a kludge to get avatar movement updates.
+ // The simulator expects collisions for avatars even if there are have been no collisions.
+ // The event updates avatar animations and stuff.
+ // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
+ // Note that we get a copy of the list to search because SendCollision() can take a while.
+ HashSet tempAvatarsInScene;
+ lock (AvatarsInSceneLock)
+ {
+ tempAvatarsInScene = new HashSet(AvatarsInScene);
+ }
+ foreach (BSPhysObject actor in tempAvatarsInScene)
+ {
+ if (!ObjectsWithCollisions.Contains(actor)) // don't call avatars twice
+ actor.SendCollisions();
+ }
+ tempAvatarsInScene = null;
+
+ // Objects that are done colliding are removed from the ObjectsWithCollisions list.
+ // Not done above because it is inside an iteration of ObjectWithCollisions.
+ // This complex collision processing is required to create an empty collision
+ // event call after all real collisions have happened on an object. This allows
+ // the simulator to generate the 'collision end' event.
+ if (ObjectsWithNoMoreCollisions.Count > 0)
+ {
+ foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
+ ObjectsWithCollisions.Remove(po);
+ ObjectsWithNoMoreCollisions.Clear();
+ }
+ }
+
+ // Call the simulator for each object that has physics property updates.
+ HashSet updatedObjects = null;
+ lock (UpdateLock)
+ {
+ if (ObjectsWithUpdates.Count > 0)
+ {
+ updatedObjects = ObjectsWithUpdates;
+ ObjectsWithUpdates = new HashSet();
+ }
+ }
+ if (updatedObjects != null)
+ {
+ foreach (BSPhysObject obj in updatedObjects)
+ {
+ obj.RequestPhysicsterseUpdate();
+ }
+ updatedObjects.Clear();
+ }
+
+ // Return the framerate simulated to give the above returned results.
+ // (Race condition here but this is just bookkeeping so rare mistakes do not merit a lock).
+ float simTime = m_simulatedTime;
+ m_simulatedTime = 0f;
+ return simTime;
+ }
+
+ // Something has collided
+ private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
+ {
+ if (localID <= TerrainManager.HighestTerrainID)
+ {
+ return; // don't send collisions to the terrain
+ }
+
+ BSPhysObject collider;
+ // NOTE that PhysObjects was locked before the call to SendCollision().
+ if (!PhysObjects.TryGetValue(localID, out collider))
+ {
+ // If the object that is colliding cannot be found, just ignore the collision.
+ DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
+ return;
+ }
+
+ // Note: the terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
+ BSPhysObject collidee = null;
+ PhysObjects.TryGetValue(collidingWith, out collidee);
+
+ // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
+
+ if (collider.IsInitialized)
+ {
+ if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
+ {
+ // If a collision was 'good', remember to send it to the simulator
+ lock (CollisionLock)
+ {
+ ObjectsWithCollisions.Add(collider);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public void BulletSPluginPhysicsThread()
+ {
+ Thread.CurrentThread.Priority = ThreadPriority.Highest;
+ m_updateWaitEvent = new ManualResetEvent(false);
+
+ while (m_initialized)
+ {
+ int beginSimulationRealtimeMS = Util.EnvironmentTickCount();
+
+ if (BSParam.Active)
+ DoPhysicsStep(BSParam.PhysicsTimeStep);
+
+ int simulationRealtimeMS = Util.EnvironmentTickCountSubtract(beginSimulationRealtimeMS);
+ int simulationTimeVsRealtimeDifferenceMS = ((int)(BSParam.PhysicsTimeStep*1000f)) - simulationRealtimeMS;
+
+ if (simulationTimeVsRealtimeDifferenceMS > 0)
+ {
+ // The simulation of the time interval took less than realtime.
+ // Do a wait for the rest of realtime.
+ m_updateWaitEvent.WaitOne(simulationTimeVsRealtimeDifferenceMS);
+ //Thread.Sleep(simulationTimeVsRealtimeDifferenceMS);
+ }
+ else
+ {
+ // The simulation took longer than realtime.
+ // Do some scaling of simulation time.
+ // TODO.
+ DetailLog("{0},BulletSPluginPhysicsThread,longerThanRealtime={1}", BSScene.DetailLogZero, simulationTimeVsRealtimeDifferenceMS);
+ }
+
+ Watchdog.UpdateThread();
+ }
+
+ Watchdog.RemoveThread();
+ }
+
+ #endregion // Simulation
+
+ public override void GetResults() { }
+
+ #region Terrain
+
+ public override void SetTerrain(float[] heightMap) {
+ TerrainManager.SetTerrain(heightMap);
+ }
+
+ public override void SetWaterLevel(float baseheight)
+ {
+ SimpleWaterLevel = baseheight;
+ }
+
+ public override void DeleteTerrain()
+ {
+ // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
+ }
+
+ // Although no one seems to check this, I do support combining.
+ public override bool SupportsCombining()
+ {
+ return TerrainManager.SupportsCombining();
+ }
+ // This call says I am a child to region zero in a mega-region. 'pScene' is that
+ // of region zero, 'offset' is my offset from regions zero's origin, and
+ // 'extents' is the largest XY that is handled in my region.
+ public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
+ {
+ TerrainManager.Combine(pScene, offset, extents);
+ }
+
+ // Unhook all the combining that I know about.
+ public override void UnCombine(PhysicsScene pScene)
+ {
+ TerrainManager.UnCombine(pScene);
+ }
+
+ #endregion // Terrain
+
+ public override Dictionary GetTopColliders()
+ {
+ Dictionary topColliders;
+
+ lock (PhysObjects)
+ {
+ foreach (KeyValuePair kvp in PhysObjects)
+ {
+ kvp.Value.ComputeCollisionScore();
+ }
+
+ List orderedPrims = new List(PhysObjects.Values);
+ orderedPrims.OrderByDescending(p => p.CollisionScore);
+ topColliders = orderedPrims.Take(25).ToDictionary(p => p.LocalID, p => p.CollisionScore);
+ }
+
+ return topColliders;
+ }
+
+ public override bool IsThreaded { get { return false; } }
+
+ #region Extensions
+ public override object Extension(string pFunct, params object[] pParams)
+ {
+ DetailLog("{0} BSScene.Extension,op={1}", DetailLogZero, pFunct);
+ return base.Extension(pFunct, pParams);
+ }
+ #endregion // Extensions
+
+ public static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
+ {
+ float pathShearX = pbs.PathShearX < 128 ? (float)pbs.PathShearX * 0.01f : (float)(pbs.PathShearX - 256) * 0.01f;
+ float pathShearY = pbs.PathShearY < 128 ? (float)pbs.PathShearY * 0.01f : (float)(pbs.PathShearY - 256) * 0.01f;
+ float pathBegin = (float)pbs.PathBegin * 2.0e-5f;
+ float pathEnd = 1.0f - (float)pbs.PathEnd * 2.0e-5f;
+ float pathScaleX = (float)(200 - pbs.PathScaleX) * 0.01f;
+ float pathScaleY = (float)(200 - pbs.PathScaleY) * 0.01f;
+ float pathTaperX = pbs.PathTaperX * 0.01f;
+ float pathTaperY = pbs.PathTaperY * 0.01f;
+
+ float profileBegin = (float)pbs.ProfileBegin * 2.0e-5f;
+ float profileEnd = 1.0f - (float)pbs.ProfileEnd * 2.0e-5f;
+ float profileHollow = (float)pbs.ProfileHollow * 2.0e-5f;
+ if (profileHollow > 0.95f)
+ profileHollow = 0.95f;
+
+ StringBuilder buff = new StringBuilder();
+ buff.Append("shape=");
+ buff.Append(((ProfileShape)pbs.ProfileShape).ToString());
+ buff.Append(",");
+ buff.Append("hollow=");
+ buff.Append(((HollowShape)pbs.HollowShape).ToString());
+ buff.Append(",");
+ buff.Append("pathCurve=");
+ buff.Append(((Extrusion)pbs.PathCurve).ToString());
+ buff.Append(",");
+ buff.Append("profCurve=");
+ buff.Append(((Extrusion)pbs.ProfileCurve).ToString());
+ buff.Append(",");
+ buff.Append("profHollow=");
+ buff.Append(profileHollow.ToString());
+ buff.Append(",");
+ buff.Append("pathBegEnd=");
+ buff.Append(pathBegin.ToString());
+ buff.Append("/");
+ buff.Append(pathEnd.ToString());
+ buff.Append(",");
+ buff.Append("profileBegEnd=");
+ buff.Append(profileBegin.ToString());
+ buff.Append("/");
+ buff.Append(profileEnd.ToString());
+ buff.Append(",");
+ buff.Append("scaleXY=");
+ buff.Append(pathScaleX.ToString());
+ buff.Append("/");
+ buff.Append(pathScaleY.ToString());
+ buff.Append(",");
+ buff.Append("shearXY=");
+ buff.Append(pathShearX.ToString());
+ buff.Append("/");
+ buff.Append(pathShearY.ToString());
+ buff.Append(",");
+ buff.Append("taperXY=");
+ buff.Append(pbs.PathTaperX.ToString());
+ buff.Append("/");
+ buff.Append(pbs.PathTaperY.ToString());
+ buff.Append(",");
+ buff.Append("skew=");
+ buff.Append(pbs.PathSkew.ToString());
+ buff.Append(",");
+ buff.Append("twist/Beg=");
+ buff.Append(pbs.PathTwist.ToString());
+ buff.Append("/");
+ buff.Append(pbs.PathTwistBegin.ToString());
+
+ return buff.ToString();
+ }
+
+ #region Taints
+ // The simulation execution order is:
+ // Simulate()
+ // DoOneTimeTaints
+ // TriggerPreStepEvent
+ // DoOneTimeTaints
+ // Step()
+ // ProcessAndSendToSimulatorCollisions
+ // ProcessAndSendToSimulatorPropertyUpdates
+ // TriggerPostStepEvent
+
+ // Calls to the PhysicsActors can't directly call into the physics engine
+ // because it might be busy. We delay changes to a known time.
+ // We rely on C#'s closure to save and restore the context for the delegate.
+ public void TaintedObject(string pOriginator, string pIdent, TaintCallback pCallback)
+ {
+ TaintedObject(false /*inTaintTime*/, pOriginator, pIdent, pCallback);
+ }
+ public void TaintedObject(uint pOriginator, String pIdent, TaintCallback pCallback)
+ {
+ TaintedObject(false /*inTaintTime*/, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
+ }
+ public void TaintedObject(bool inTaintTime, String pIdent, TaintCallback pCallback)
+ {
+ TaintedObject(inTaintTime, BSScene.DetailLogZero, pIdent, pCallback);
+ }
+ public void TaintedObject(bool inTaintTime, uint pOriginator, String pIdent, TaintCallback pCallback)
+ {
+ TaintedObject(inTaintTime, m_physicsLoggingEnabled ? pOriginator.ToString() : BSScene.DetailLogZero, pIdent, pCallback);
+ }
+ // Sometimes a potentially tainted operation can be used in and out of taint time.
+ // This routine executes the command immediately if in taint-time otherwise it is queued.
+ public void TaintedObject(bool inTaintTime, string pOriginator, string pIdent, TaintCallback pCallback)
+ {
+ if (!m_initialized) return;
+
+ if (inTaintTime)
+ pCallback();
+ else
+ {
+ lock (_taintLock)
+ {
+ _taintOperations.Add(new TaintCallbackEntry(pOriginator, pIdent, pCallback));
+ }
+ }
+ }
+
+ private void TriggerPreStepEvent(float timeStep)
+ {
+ PreStepAction actions = BeforeStep;
+ if (actions != null)
+ actions(timeStep);
+
+ }
+
+ private void TriggerPostStepEvent(float timeStep)
+ {
+ PostStepAction actions = AfterStep;
+ if (actions != null)
+ actions(timeStep);
+
+ }
+
+ // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
+ // a callback into itself to do the actual property change. That callback is called
+ // here just before the physics engine is called to step the simulation.
+ public void ProcessTaints()
+ {
+ ProcessRegularTaints();
+ ProcessPostTaintTaints();
+ }
+
+ private void ProcessRegularTaints()
+ {
+ if (m_initialized && _taintOperations.Count > 0) // save allocating new list if there is nothing to process
+ {
+ // swizzle a new list into the list location so we can process what's there
+ List oldList;
+ lock (_taintLock)
+ {
+ oldList = _taintOperations;
+ _taintOperations = new List();
+ }
+
+ foreach (TaintCallbackEntry tcbe in oldList)
+ {
+ try
+ {
+ DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", tcbe.originator, tcbe.ident); // DEBUG DEBUG DEBUG
+ tcbe.callback();
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
+ }
+ }
+ oldList.Clear();
+ }
+ }
+
+ // Schedule an update to happen after all the regular taints are processed.
+ // Note that new requests for the same operation ("ident") for the same object ("ID")
+ // will replace any previous operation by the same object.
+ public void PostTaintObject(String ident, uint ID, TaintCallback callback)
+ {
+ string IDAsString = ID.ToString();
+ string uniqueIdent = ident + "-" + IDAsString;
+ lock (_taintLock)
+ {
+ _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(IDAsString, uniqueIdent, callback);
+ }
+
+ return;
+ }
+
+ // Taints that happen after the normal taint processing but before the simulation step.
+ private void ProcessPostTaintTaints()
+ {
+ if (m_initialized && _postTaintOperations.Count > 0)
+ {
+ Dictionary oldList;
+ lock (_taintLock)
+ {
+ oldList = _postTaintOperations;
+ _postTaintOperations = new Dictionary();
+ }
+
+ foreach (KeyValuePair kvp in oldList)
+ {
+ try
+ {
+ DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
+ kvp.Value.callback();
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
+ }
+ }
+ oldList.Clear();
+ }
+ }
+
+ // Only used for debugging. Does not change state of anything so locking is not necessary.
+ public bool AssertInTaintTime(string whereFrom)
+ {
+ if (!InTaintTime)
+ {
+ DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
+ m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
+ // Util.PrintCallStack(DetailLog);
+ }
+ return InTaintTime;
+ }
+
+ #endregion // Taints
+
+ #region IPhysicsParameters
+ // Get the list of parameters this physics engine supports
+ public PhysParameterEntry[] GetParameterList()
+ {
+ BSParam.BuildParameterTable();
+ return BSParam.SettableParameters;
+ }
+
+ // Set parameter on a specific or all instances.
+ // Return 'false' if not able to set the parameter.
+ // Setting the value in the m_params block will change the value the physics engine
+ // will use the next time since it's pinned and shared memory.
+ // Some of the values require calling into the physics engine to get the new
+ // value activated ('terrainFriction' for instance).
+ public bool SetPhysicsParameter(string parm, string val, uint localID)
+ {
+ bool ret = false;
+
+ BSParam.ParameterDefnBase theParam;
+ if (BSParam.TryGetParameter(parm, out theParam))
+ {
+ // Set the value in the C# code
+ theParam.SetValue(this, val);
+
+ // Optionally set the parameter in the unmanaged code
+ if (theParam.HasSetOnObject)
+ {
+ // update all the localIDs specified
+ // If the local ID is APPLY_TO_NONE, just change the default value
+ // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
+ // If the localID is a specific object, apply the parameter change to only that object
+ List objectIDs = new List();
+ switch (localID)
+ {
+ case PhysParameterEntry.APPLY_TO_NONE:
+ // This will cause a call into the physical world if some operation is specified (SetOnObject).
+ objectIDs.Add(TERRAIN_ID);
+ TaintedUpdateParameter(parm, objectIDs, val);
+ break;
+ case PhysParameterEntry.APPLY_TO_ALL:
+ lock (PhysObjects) objectIDs = new List(PhysObjects.Keys);
+ TaintedUpdateParameter(parm, objectIDs, val);
+ break;
+ default:
+ // setting only one localID
+ objectIDs.Add(localID);
+ TaintedUpdateParameter(parm, objectIDs, val);
+ break;
+ }
+ }
+
+ ret = true;
+ }
+ return ret;
+ }
+
+ // schedule the actual updating of the paramter to when the phys engine is not busy
+ private void TaintedUpdateParameter(string parm, List lIDs, string val)
+ {
+ string xval = val;
+ List xlIDs = lIDs;
+ string xparm = parm;
+ TaintedObject(DetailLogZero, "BSScene.UpdateParameterSet", delegate() {
+ BSParam.ParameterDefnBase thisParam;
+ if (BSParam.TryGetParameter(xparm, out thisParam))
+ {
+ if (thisParam.HasSetOnObject)
+ {
+ foreach (uint lID in xlIDs)
+ {
+ BSPhysObject theObject = null;
+ if (PhysObjects.TryGetValue(lID, out theObject))
+ thisParam.SetOnObject(this, theObject);
+ }
+ }
+ }
+ });
+ }
+
+ // Get parameter.
+ // Return 'false' if not able to get the parameter.
+ public bool GetPhysicsParameter(string parm, out string value)
+ {
+ string val = String.Empty;
+ bool ret = false;
+ BSParam.ParameterDefnBase theParam;
+ if (BSParam.TryGetParameter(parm, out theParam))
+ {
+ val = theParam.GetValue(this);
+ ret = true;
+ }
+ value = val;
+ return ret;
+ }
+
+ #endregion IPhysicsParameters
+
+ // Invoke the detailed logger and output something if it's enabled.
+ public void DetailLog(string msg, params Object[] args)
+ {
+ PhysicsLogging.Write(msg, args);
+ }
+ // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
+ public const string DetailLogZero = "0000000000";
+
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
new file mode 100755
index 0000000..d1de844
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OMV = OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.Physics.ConvexDecompositionDotNet;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public sealed class BSShapeCollection : IDisposable
+{
+#pragma warning disable 414
+ private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
+#pragma warning restore 414
+
+ private BSScene m_physicsScene { get; set; }
+
+ private Object m_collectionActivityLock = new Object();
+
+ private bool DDetail = false;
+
+ public BSShapeCollection(BSScene physScene)
+ {
+ m_physicsScene = physScene;
+ // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
+ // While detailed debugging is still active, this is better than commenting out all the
+ // DetailLog statements. When debugging slows down, this and the protected logging
+ // statements can be commented/removed.
+ DDetail = true;
+ }
+
+ public void Dispose()
+ {
+ // TODO!!!!!!!!!
+ }
+
+ // Callbacks called just before either the body or shape is destroyed.
+ // Mostly used for changing bodies out from under Linksets.
+ // Useful for other cases where parameters need saving.
+ // Passing 'null' says no callback.
+ public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape);
+
+ // Called to update/change the body and shape for an object.
+ // The object has some shape and body on it. Here we decide if that is the correct shape
+ // for the current state of the object (static/dynamic/...).
+ // If bodyCallback is not null, it is called if either the body or the shape are changed
+ // so dependencies (like constraints) can be removed before the physical object is dereferenced.
+ // Return 'true' if either the body or the shape changed.
+ // Called at taint-time.
+ public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
+ {
+ m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
+
+ bool ret = false;
+
+ // This lock could probably be pushed down lower but building shouldn't take long
+ lock (m_collectionActivityLock)
+ {
+ // Do we have the correct geometry for this type of object?
+ // Updates prim.BSShape with information/pointers to shape.
+ // Returns 'true' of BSShape is changed to a new shape.
+ bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
+ // If we had to select a new shape geometry for the object,
+ // rebuild the body around it.
+ // Updates prim.BSBody with information/pointers to requested body
+ // Returns 'true' if BSBody was changed.
+ bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
+ ret = newGeom || newBody;
+ }
+ DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
+ prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
+
+ return ret;
+ }
+
+ public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
+ {
+ return GetBodyAndShape(forceRebuild, sim, prim, null);
+ }
+
+ // If the existing prim's shape is to be replaced, remove the tie to the existing shape
+ // before replacing it.
+ private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
+ {
+ if (prim.PhysShape.HasPhysicalShape)
+ {
+ if (shapeCallback != null)
+ shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
+ prim.PhysShape.Dereference(m_physicsScene);
+ }
+ prim.PhysShape = new BSShapeNull();
+ }
+
+ // Create the geometry information in Bullet for later use.
+ // The objects needs a hull if it's physical otherwise a mesh is enough.
+ // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
+ // shared geometries will be used. If the parameters of the existing shape are the same
+ // as this request, the shape is not rebuilt.
+ // Info in prim.BSShape is updated to the new shape.
+ // Returns 'true' if the geometry was rebuilt.
+ // Called at taint-time!
+ public const int AvatarShapeCapsule = 0;
+ public const int AvatarShapeCube = 1;
+ public const int AvatarShapeOvoid = 2;
+ public const int AvatarShapeMesh = 3;
+ private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
+ {
+ bool ret = false;
+ bool haveShape = false;
+ bool nativeShapePossible = true;
+ PrimitiveBaseShape pbs = prim.BaseShape;
+
+ // Kludge to create the capsule for the avatar.
+ // TDOD: Remove/redo this when BSShapeAvatar is working!!
+ BSCharacter theChar = prim as BSCharacter;
+ if (theChar != null)
+ {
+ DereferenceExistingShape(prim, shapeCallback);
+ switch (BSParam.AvatarShape)
+ {
+ case AvatarShapeCapsule:
+ prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
+ BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
+ ret = true;
+ haveShape = true;
+ break;
+ case AvatarShapeCube:
+ prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
+ BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE);
+ ret = true;
+ haveShape = true;
+ break;
+ case AvatarShapeOvoid:
+ // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape
+ prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
+ BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE);
+ ret = true;
+ haveShape = true;
+ break;
+ case AvatarShapeMesh:
+ break;
+ default:
+ break;
+ }
+ }
+
+ // If the prim attributes are simple, this could be a simple Bullet native shape
+ // Native shapes work whether to object is static or physical.
+ if (!haveShape
+ && nativeShapePossible
+ && pbs != null
+ && PrimHasNoCuts(pbs)
+ && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) )
+ )
+ {
+ // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
+ OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
+ if (prim.PhysShape.HasPhysicalShape)
+ scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
+
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
+ prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
+
+ // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
+ if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
+ && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
+ {
+ haveShape = true;
+ if (forceRebuild
+ || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
+ )
+ {
+ DereferenceExistingShape(prim, shapeCallback);
+ prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
+ BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
+ ret = true;
+ }
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
+ prim.LocalID, forceRebuild, ret, prim.PhysShape);
+ }
+ // If we didn't make a sphere, maybe a box will work.
+ if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
+ {
+ haveShape = true;
+ if (forceRebuild
+ || prim.Scale != scaleOfExistingShape
+ || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
+ )
+ {
+ DereferenceExistingShape(prim, shapeCallback);
+ prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
+ BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
+ ret = true;
+ }
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
+ prim.LocalID, forceRebuild, ret, prim.PhysShape);
+ }
+ }
+
+ // If a simple shape is not happening, create a mesh and possibly a hull.
+ if (!haveShape && pbs != null)
+ {
+ ret = CreateGeomMeshOrHull(prim, shapeCallback);
+ }
+
+ return ret;
+ }
+
+ // return 'true' if this shape description does not include any cutting or twisting.
+ public static bool PrimHasNoCuts(PrimitiveBaseShape pbs)
+ {
+ return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
+ && pbs.ProfileHollow == 0
+ && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
+ && pbs.PathBegin == 0 && pbs.PathEnd == 0
+ && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
+ && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
+ && pbs.PathShearX == 0 && pbs.PathShearY == 0;
+ }
+
+ // return 'true' if the prim's shape was changed.
+ private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
+ {
+
+ bool ret = false;
+ // Note that if it's a native shape, the check for physical/non-physical is not
+ // made. Native shapes work in either case.
+ if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
+ {
+ // Use a simple, single mesh convex hull shape if the object is simple enough
+ BSShape potentialHull = null;
+
+ PrimitiveBaseShape pbs = prim.BaseShape;
+ // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
+ if (BSParam.ShouldUseSingleConvexHullForPrims
+ && pbs != null
+ && !pbs.SculptEntry
+ && PrimHasNoCuts(pbs)
+ )
+ {
+ potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
+ }
+ // Use the GImpact shape if it is a prim that has some concaveness
+ if (potentialHull == null
+ && BSParam.ShouldUseGImpactShapeForPrims
+ && pbs != null
+ && !pbs.SculptEntry
+ )
+ {
+ potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
+ }
+ // If not any of the simple cases, just make a hull
+ if (potentialHull == null)
+ {
+ potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
+ }
+
+ // If the current shape is not what is on the prim at the moment, time to change.
+ if (!prim.PhysShape.HasPhysicalShape
+ || potentialHull.ShapeType != prim.PhysShape.ShapeType
+ || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
+ {
+ DereferenceExistingShape(prim, shapeCallback);
+ prim.PhysShape = potentialHull;
+ ret = true;
+ }
+ else
+ {
+ // The current shape on the prim is the correct one. We don't need the potential reference.
+ potentialHull.Dereference(m_physicsScene);
+ }
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
+ }
+ else
+ {
+ // Non-physical objects should be just meshes.
+ BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
+ // If the current shape is not what is on the prim at the moment, time to change.
+ if (!prim.PhysShape.HasPhysicalShape
+ || potentialMesh.ShapeType != prim.PhysShape.ShapeType
+ || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
+ {
+ DereferenceExistingShape(prim, shapeCallback);
+ prim.PhysShape = potentialMesh;
+ ret = true;
+ }
+ else
+ {
+ // We don't need this reference to the mesh that is already being using.
+ potentialMesh.Dereference(m_physicsScene);
+ }
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
+ }
+ return ret;
+ }
+
+ // Track another user of a body.
+ // We presume the caller has allocated the body.
+ // Bodies only have one user so the body is just put into the world if not already there.
+ private void ReferenceBody(BulletBody body)
+ {
+ lock (m_collectionActivityLock)
+ {
+ if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
+ if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body))
+ {
+ m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body);
+ if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
+ }
+ }
+ }
+
+ // Release the usage of a body.
+ // Called when releasing use of a BSBody. BSShape is handled separately.
+ // Called in taint time.
+ public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback )
+ {
+ if (!body.HasPhysicalBody)
+ return;
+
+ m_physicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");
+
+ lock (m_collectionActivityLock)
+ {
+ if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
+ // If the caller needs to know the old body is going away, pass the event up.
+ if (bodyCallback != null)
+ bodyCallback(body, null);
+
+ // Removing an object not in the world is a NOOP
+ m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);
+
+ // Zero any reference to the shape so it is not freed when the body is deleted.
+ m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);
+
+ m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
+ }
+ }
+
+ // Create a body object in Bullet.
+ // Updates prim.BSBody with the information about the new body if one is created.
+ // Returns 'true' if an object was actually created.
+ // Called at taint-time.
+ private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback)
+ {
+ bool ret = false;
+
+ // the mesh, hull or native shape must have already been created in Bullet
+ bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
+
+ // If there is an existing body, verify it's of an acceptable type.
+ // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
+ if (!mustRebuild)
+ {
+ CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody);
+ if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
+ || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
+ {
+ // If the collisionObject is not the correct type for solidness, rebuild what's there
+ mustRebuild = true;
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType);
+ }
+ }
+
+ if (mustRebuild || forceRebuild)
+ {
+ // Free any old body
+ DereferenceBody(prim.PhysBody, bodyCallback);
+
+ BulletBody aBody;
+ if (prim.IsSolid)
+ {
+ aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
+ }
+ else
+ {
+ aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation);
+ if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
+ }
+
+ ReferenceBody(aBody);
+
+ prim.PhysBody = aBody;
+
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ private void DetailLog(string msg, params Object[] args)
+ {
+ if (m_physicsScene.PhysicsLogging.Enabled)
+ m_physicsScene.DetailLog(msg, args);
+ }
+}
+}
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
new file mode 100755
index 0000000..86d86cb
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs
@@ -0,0 +1,1463 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyrightD
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using OpenSim.Framework;
+using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.Physics.Meshing;
+using OpenSim.Region.Physics.ConvexDecompositionDotNet;
+
+using OMV = OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+// Information class that holds stats for the shape. Which values mean
+// something depends on the type of shape.
+// This information is used for debugging and stats and is not used
+// for operational things.
+public class ShapeInfoInfo
+{
+ public int Vertices { get; set; }
+ private int m_hullCount;
+ private int[] m_verticesPerHull;
+ public ShapeInfoInfo()
+ {
+ Vertices = 0;
+ m_hullCount = 0;
+ m_verticesPerHull = null;
+ }
+ public int HullCount
+ {
+ set
+ {
+ m_hullCount = value;
+ m_verticesPerHull = new int[m_hullCount];
+ Array.Clear(m_verticesPerHull, 0, m_hullCount);
+ }
+ get { return m_hullCount; }
+ }
+ public void SetVerticesPerHull(int hullNum, int vertices)
+ {
+ if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
+ {
+ m_verticesPerHull[hullNum] = vertices;
+ }
+ }
+ public int GetVerticesPerHull(int hullNum)
+ {
+ if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length)
+ {
+ return m_verticesPerHull[hullNum];
+ }
+ return 0;
+ }
+ public override string ToString()
+ {
+ StringBuilder buff = new StringBuilder();
+ // buff.Append("ShapeInfo=<");
+ buff.Append("<");
+ if (Vertices > 0)
+ {
+ buff.Append("verts=");
+ buff.Append(Vertices.ToString());
+ }
+
+ if (Vertices > 0 && HullCount > 0) buff.Append(",");
+
+ if (HullCount > 0)
+ {
+ buff.Append("nHulls=");
+ buff.Append(HullCount.ToString());
+ buff.Append(",");
+ buff.Append("hullVerts=");
+ for (int ii = 0; ii < HullCount; ii++)
+ {
+ if (ii != 0) buff.Append(",");
+ buff.Append(GetVerticesPerHull(ii).ToString());
+ }
+ }
+ buff.Append(">");
+ return buff.ToString();
+ }
+}
+
+public abstract class BSShape
+{
+ private static string LogHeader = "[BULLETSIM SHAPE]";
+
+ public int referenceCount { get; set; }
+ public DateTime lastReferenced { get; set; }
+ public BulletShape physShapeInfo { get; set; }
+ public ShapeInfoInfo shapeInfo { get; private set; }
+
+ public BSShape()
+ {
+ referenceCount = 1;
+ lastReferenced = DateTime.Now;
+ physShapeInfo = new BulletShape();
+ shapeInfo = new ShapeInfoInfo();
+ }
+ public BSShape(BulletShape pShape)
+ {
+ referenceCount = 1;
+ lastReferenced = DateTime.Now;
+ physShapeInfo = pShape;
+ shapeInfo = new ShapeInfoInfo();
+ }
+
+ // Get another reference to this shape.
+ public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
+
+ // Called when this shape is being used again.
+ // Used internally. External callers should call instance.GetReference() to properly copy/reference
+ // the shape.
+ protected virtual void IncrementReference()
+ {
+ referenceCount++;
+ lastReferenced = DateTime.Now;
+ }
+
+ // Called when this shape is done being used.
+ protected virtual void DecrementReference()
+ {
+ referenceCount--;
+ lastReferenced = DateTime.Now;
+ }
+
+ // Release the use of a physical shape.
+ public abstract void Dereference(BSScene physicsScene);
+
+ // Return 'true' if there is an allocated physics physical shape under this class instance.
+ public virtual bool HasPhysicalShape
+ {
+ get
+ {
+ if (physShapeInfo != null)
+ return physShapeInfo.HasPhysicalShape;
+ return false;
+ }
+ }
+ public virtual BSPhysicsShapeType ShapeType
+ {
+ get
+ {
+ BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
+ if (physShapeInfo != null && physShapeInfo.HasPhysicalShape)
+ ret = physShapeInfo.shapeType;
+ return ret;
+ }
+ }
+
+ // Returns a string for debugging that uniquily identifies the memory used by this instance
+ public virtual string AddrString
+ {
+ get
+ {
+ if (physShapeInfo != null)
+ return physShapeInfo.AddrString;
+ return "unknown";
+ }
+ }
+
+ public override string ToString()
+ {
+ StringBuilder buff = new StringBuilder();
+ if (physShapeInfo == null)
+ {
+ buff.Append("");
+ return buff.ToString();
+ }
+
+ #region Common shape routines
+ // Create a hash of all the shape parameters to be used as a key for this particular shape.
+ public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
+ {
+ // level of detail based on size and type of the object
+ float lod = BSParam.MeshLOD;
+ if (pbs.SculptEntry)
+ lod = BSParam.SculptLOD;
+
+ // Mega prims usually get more detail because one can interact with shape approximations at this size.
+ float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
+ if (maxAxis > BSParam.MeshMegaPrimThreshold)
+ lod = BSParam.MeshMegaPrimLOD;
+
+ retLod = lod;
+ return pbs.GetMeshKey(size, lod);
+ }
+
+ // The creation of a mesh or hull can fail if an underlying asset is not available.
+ // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
+ // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
+ // The first case causes the asset to be fetched. The second case requires
+ // us to not loop forever.
+ // Called after creating a physical mesh or hull. If the physical shape was created,
+ // just return.
+ public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
+ {
+ // If the shape was successfully created, nothing more to do
+ if (newShape.HasPhysicalShape)
+ return newShape;
+
+ // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
+ // fetched but we end up here again, the meshing of the asset must have failed.
+ // Prevent trying to keep fetching the mesh by declaring failure.
+ if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
+ {
+ prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
+ physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
+ LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
+ prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ }
+ else
+ {
+ // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
+ if (prim.BaseShape.SculptEntry
+ && !prim.AssetFailed()
+ && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
+ && prim.BaseShape.SculptTexture != OMV.UUID.Zero
+ )
+ {
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
+ prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
+ // Multiple requestors will know we're waiting for this asset
+ prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;
+
+ BSPhysObject xprim = prim;
+ RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
+ if (assetProvider != null)
+ {
+ BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
+ assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
+ {
+ // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
+ bool assetFound = false;
+ string mismatchIDs = String.Empty; // DEBUG DEBUG
+ if (asset != null && yprim.BaseShape.SculptEntry)
+ {
+ if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
+ {
+ yprim.BaseShape.SculptData = asset.Data;
+ // This will cause the prim to see that the filler shape is not the right
+ // one and try again to build the object.
+ // No race condition with the normal shape setting since the rebuild is at taint time.
+ yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
+ yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
+ assetFound = true;
+ }
+ else
+ {
+ mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
+ }
+ }
+ if (!assetFound)
+ {
+ yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
+ }
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
+ yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs );
+ });
+ }
+ else
+ {
+ xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
+ physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
+ LogHeader, physicsScene.Name);
+ }
+ }
+ else
+ {
+ if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
+ {
+ physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}",
+ LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}",
+ prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ }
+ if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing)
+ {
+ physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}",
+ LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}",
+ prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
+ }
+ }
+ }
+
+ // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
+ BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
+ physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);
+
+ return fillShape.physShapeInfo;
+ }
+
+ public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim)
+ {
+ StringBuilder buff = new StringBuilder(prim.PhysObjectName);
+ buff.Append("/pos=");
+ buff.Append(prim.RawPosition.ToString());
+ if (pScene != null)
+ {
+ buff.Append("/rgn=");
+ buff.Append(pScene.Name);
+ }
+ return buff.ToString();
+ }
+
+ #endregion // Common shape routines
+}
+
+// ============================================================================================================
+public class BSShapeNull : BSShape
+{
+ public BSShapeNull() : base()
+ {
+ }
+ public static BSShape GetReference() { return new BSShapeNull(); }
+ public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); }
+ public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
+}
+
+// ============================================================================================================
+// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere.
+// They are odd in that they don't allocate meshes but are computated/procedural.
+// This means allocation and freeing is different than meshes.
+public class BSShapeNative : BSShape
+{
+ private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
+ public BSShapeNative(BulletShape pShape) : base(pShape)
+ {
+ }
+
+ public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
+ BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
+ {
+ // Native shapes are not shared and are always built anew.
+ return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey));
+ }
+
+ public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
+ {
+ // Native shapes are not shared so we return a new shape.
+ BSShape ret = null;
+ lock (physShapeInfo)
+ {
+ ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim,
+ physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey));
+ }
+ return ret;
+ }
+
+ // Make this reference to the physical shape go away since native shapes are not shared.
+ public override void Dereference(BSScene physicsScene)
+ {
+ // Native shapes are not tracked and are released immediately
+ lock (physShapeInfo)
+ {
+ if (physShapeInfo.HasPhysicalShape)
+ {
+ physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
+ physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo);
+ }
+ physShapeInfo.Clear();
+ // Garbage collection will free up this instance.
+ }
+ }
+
+ private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim,
+ BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
+ {
+ BulletShape newShape;
+
+ ShapeData nativeShapeData = new ShapeData();
+ nativeShapeData.Type = shapeType;
+ nativeShapeData.ID = prim.LocalID;
+ nativeShapeData.Scale = prim.Scale;
+ nativeShapeData.Size = prim.Scale;
+ nativeShapeData.MeshKey = (ulong)shapeKey;
+ nativeShapeData.HullKey = (ulong)shapeKey;
+
+ if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
+ {
+ newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
+ physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale);
+ }
+ else
+ {
+ newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
+ }
+ if (!newShape.HasPhysicalShape)
+ {
+ physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
+ LogHeader, prim.LocalID, shapeType);
+ }
+ newShape.shapeType = shapeType;
+ newShape.isNativeShape = true;
+ newShape.shapeKey = (UInt64)shapeKey;
+ return newShape;
+ }
+
+}
+
+// ============================================================================================================
+// BSShapeMesh is a simple mesh.
+public class BSShapeMesh : BSShape
+{
+ private static string LogHeader = "[BULLETSIM SHAPE MESH]";
+ public static Dictionary Meshes = new Dictionary();
+
+ public BSShapeMesh(BulletShape pShape) : base(pShape)
+ {
+ }
+ public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
+ {
+ float lod;
+ System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
+
+ BSShapeMesh retMesh = null;
+ lock (Meshes)
+ {
+ if (Meshes.TryGetValue(newMeshKey, out retMesh))
+ {
+ // The mesh has already been created. Return a new reference to same.
+ retMesh.IncrementReference();
+ }
+ else
+ {
+ retMesh = new BSShapeMesh(new BulletShape());
+ // An instance of this mesh has not been created. Build and remember same.
+ BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod);
+
+ // Check to see if mesh was created (might require an asset).
+ newShape = VerifyMeshCreated(physicsScene, newShape, prim);
+ if (!newShape.isNativeShape || prim.AssetFailed() )
+ {
+ // If a mesh was what was created, remember the built shape for later sharing.
+ // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh.
+ Meshes.Add(newMeshKey, retMesh);
+ }
+
+ retMesh.physShapeInfo = newShape;
+ }
+ }
+ physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod);
+ return retMesh;
+ }
+ public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
+ {
+ BSShape ret = null;
+ // If the underlying shape is native, the actual shape has not been build (waiting for asset)
+ // and we must create a copy of the native shape since they are never shared.
+ if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
+ {
+ // TODO: decide when the native shapes should be freed. Check in Dereference?
+ ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
+ }
+ else
+ {
+ // Another reference to this shape is just counted.
+ IncrementReference();
+ ret = this;
+ }
+ return ret;
+ }
+ public override void Dereference(BSScene physicsScene)
+ {
+ lock (Meshes)
+ {
+ this.DecrementReference();
+ physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this);
+ // TODO: schedule aging and destruction of unused meshes.
+ }
+ }
+ // Loop through all the known meshes and return the description based on the physical address.
+ public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
+ {
+ bool ret = false;
+ BSShapeMesh foundDesc = null;
+ lock (Meshes)
+ {
+ foreach (BSShapeMesh sm in Meshes.Values)
+ {
+ if (sm.physShapeInfo.ReferenceSame(pShape))
+ {
+ foundDesc = sm;
+ ret = true;
+ break;
+ }
+
+ }
+ }
+ outMesh = foundDesc;
+ return ret;
+ }
+
+ public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices );
+ private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
+ PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
+ {
+ return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod,
+ (w, iC, i, vC, v) =>
+ {
+ shapeInfo.Vertices = vC;
+ return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v);
+ });
+ }
+
+ // Code that uses the mesher to create the index/vertices info for a trimesh shape.
+ // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
+ // The actual build call is passed so this logic can be used by several of the shapes that use a
+ // simple mesh as their base shape.
+ public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey,
+ PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
+ {
+ BulletShape newShape = new BulletShape();
+
+ IMesh meshData = null;
+ lock (physicsScene.mesher)
+ {
+ meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
+ false, // say it is not physical so a bounding box is not built
+ false // do not cache the mesh and do not use previously built versions
+ );
+ }
+
+ if (meshData != null)
+ {
+ if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
+ {
+ // Release the fetched asset data once it has been used.
+ pbs.SculptData = new byte[0];
+ prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
+ }
+
+ int[] indices = meshData.getIndexListAsInt();
+ int realIndicesIndex = indices.Length;
+ float[] verticesAsFloats = meshData.getVertexListAsFloat();
+
+ if (BSParam.ShouldRemoveZeroWidthTriangles)
+ {
+ // Remove degenerate triangles. These are triangles with two of the vertices
+ // are the same. This is complicated by the problem that vertices are not
+ // made unique in sculpties so we have to compare the values in the vertex.
+ realIndicesIndex = 0;
+ for (int tri = 0; tri < indices.Length; tri += 3)
+ {
+ // Compute displacements into vertex array for each vertex of the triangle
+ int v1 = indices[tri + 0] * 3;
+ int v2 = indices[tri + 1] * 3;
+ int v3 = indices[tri + 2] * 3;
+ // Check to see if any two of the vertices are the same
+ if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
+ && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
+ && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
+ || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
+ && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
+ && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
+ || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
+ && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
+ && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) )
+ )
+ {
+ // None of the vertices of the triangles are the same. This is a good triangle;
+ indices[realIndicesIndex + 0] = indices[tri + 0];
+ indices[realIndicesIndex + 1] = indices[tri + 1];
+ indices[realIndicesIndex + 2] = indices[tri + 2];
+ realIndicesIndex += 3;
+ }
+ }
+ }
+ physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
+ BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3);
+
+ if (realIndicesIndex != 0)
+ {
+ newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats);
+ }
+ else
+ {
+ // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
+ prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
+ physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) );
+ physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey);
+ }
+ }
+ newShape.shapeKey = newMeshKey;
+
+ return newShape;
+ }
+}
+
+// ============================================================================================================
+// BSShapeHull is a physical shape representation htat is made up of many convex hulls.
+// The convex hulls are either supplied with the asset or are approximated by one of the
+// convex hull creation routines (in OpenSim or in Bullet).
+public class BSShapeHull : BSShape
+{
+#pragma warning disable 414
+ private static string LogHeader = "[BULLETSIM SHAPE HULL]";
+#pragma warning restore 414
+
+ public static Dictionary Hulls = new Dictionary();
+
+
+ public BSShapeHull(BulletShape pShape) : base(pShape)
+ {
+ }
+ public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
+ {
+ float lod;
+ System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
+
+ BSShapeHull retHull = null;
+ lock (Hulls)
+ {
+ if (Hulls.TryGetValue(newHullKey, out retHull))
+ {
+ // The mesh has already been created. Return a new reference to same.
+ retHull.IncrementReference();
+ }
+ else
+ {
+ retHull = new BSShapeHull(new BulletShape());
+ // An instance of this mesh has not been created. Build and remember same.
+ BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod);
+
+ // Check to see if hull was created (might require an asset).
+ newShape = VerifyMeshCreated(physicsScene, newShape, prim);
+ if (!newShape.isNativeShape || prim.AssetFailed())
+ {
+ // If a mesh was what was created, remember the built shape for later sharing.
+ Hulls.Add(newHullKey, retHull);
+ }
+ retHull.physShapeInfo = newShape;
+ }
+ }
+ physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod);
+ return retHull;
+ }
+ public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
+ {
+ BSShape ret = null;
+ // If the underlying shape is native, the actual shape has not been build (waiting for asset)
+ // and we must create a copy of the native shape since they are never shared.
+ if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape)
+ {
+ // TODO: decide when the native shapes should be freed. Check in Dereference?
+ ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
+ }
+ else
+ {
+ // Another reference to this shape is just counted.
+ IncrementReference();
+ ret = this;
+ }
+ return ret;
+ }
+ public override void Dereference(BSScene physicsScene)
+ {
+ lock (Hulls)
+ {
+ this.DecrementReference();
+ physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this);
+ // TODO: schedule aging and destruction of unused meshes.
+ }
+ }
+
+ List m_hulls;
+ private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey,
+ PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
+ {
+ BulletShape newShape = new BulletShape();
+
+ IMesh meshData = null;
+ List> allHulls = null;
+ lock (physicsScene.mesher)
+ {
+ // Pass true for physicalness as this prevents the creation of bounding box which is not needed
+ meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */);
+
+ // If we should use the asset's hull info, fetch it out of the locked mesher
+ if (meshData != null && BSParam.ShouldUseAssetHulls)
+ {
+ Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
+ if (realMesher != null)
+ {
+ allHulls = realMesher.GetConvexHulls(size);
+ }
+ if (allHulls == null)
+ {
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
+ }
+ }
+ }
+
+ // If there is hull data in the mesh asset, build the hull from that
+ if (allHulls != null && BSParam.ShouldUseAssetHulls)
+ {
+ int hullCount = allHulls.Count;
+ shapeInfo.HullCount = hullCount;
+ int totalVertices = 1; // include one for the count of the hulls
+ // Using the structure described for HACD hulls, create the memory sturcture
+ // to pass the hull data to the creater.
+ foreach (List hullVerts in allHulls)
+ {
+ totalVertices += 4; // add four for the vertex count and centroid
+ totalVertices += hullVerts.Count * 3; // one vertex is three dimensions
+ }
+ float[] convHulls = new float[totalVertices];
+
+ convHulls[0] = (float)hullCount;
+ int jj = 1;
+ int hullIndex = 0;
+ foreach (List hullVerts in allHulls)
+ {
+ convHulls[jj + 0] = hullVerts.Count;
+ convHulls[jj + 1] = 0f; // centroid x,y,z
+ convHulls[jj + 2] = 0f;
+ convHulls[jj + 3] = 0f;
+ jj += 4;
+ foreach (OMV.Vector3 oneVert in hullVerts)
+ {
+ convHulls[jj + 0] = oneVert.X;
+ convHulls[jj + 1] = oneVert.Y;
+ convHulls[jj + 2] = oneVert.Z;
+ jj += 3;
+ }
+ shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
+ hullIndex++;
+ }
+
+ // create the hull data structure in Bullet
+ newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
+
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}",
+ prim.LocalID, hullCount, totalVertices, newShape);
+ }
+
+ // If no hull specified in the asset and we should use Bullet's HACD approximation...
+ if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
+ {
+ // Build the hull shape from an existing mesh shape.
+ // The mesh should have already been created in Bullet.
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
+ BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);
+
+ if (meshShape.physShapeInfo.HasPhysicalShape)
+ {
+ HACDParams parms = new HACDParams();
+ parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
+ parms.minClusters = BSParam.BHullMinClusters;
+ parms.compacityWeight = BSParam.BHullCompacityWeight;
+ parms.volumeWeight = BSParam.BHullVolumeWeight;
+ parms.concavity = BSParam.BHullConcavity;
+ parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
+ parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
+ parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
+ parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
+ parms.whichHACD = 0; // Use the HACD routine that comes with Bullet
+
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape);
+ newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape);
+
+ // Now done with the mesh shape.
+ shapeInfo.HullCount = 1;
+ BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
+ if (maybeMesh != null)
+ shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
+ meshShape.Dereference(physicsScene);
+ }
+ physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape);
+ }
+
+ // If no other hull specifications, use our HACD hull approximation.
+ if (!newShape.HasPhysicalShape && meshData != null)
+ {
+ if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
+ {
+ // Release the fetched asset data once it has been used.
+ pbs.SculptData = new byte[0];
+ prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
+ }
+
+ int[] indices = meshData.getIndexListAsInt();
+ List vertices = meshData.getVertexList();
+
+ //format conversion from IMesh format to DecompDesc format
+ List convIndices = new List();
+ List convVertices = new List();
+ for (int ii = 0; ii < indices.GetLength(0); ii++)
+ {
+ convIndices.Add(indices[ii]);
+ }
+ foreach (OMV.Vector3 vv in vertices)
+ {
+ convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
+ }
+
+ uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit;
+ if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
+ {
+ // Simple primitive shapes we know are convex so they are better implemented with
+ // fewer hulls.
+ // Check for simple shape (prim without cuts) and reduce split parameter if so.
+ if (BSShapeCollection.PrimHasNoCuts(pbs))
+ {
+ maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes;
+ }
+ }
+
+ // setup and do convex hull conversion
+ m_hulls = new List();
+ DecompDesc dcomp = new DecompDesc();
+ dcomp.mIndices = convIndices;
+ dcomp.mVertices = convVertices;
+ dcomp.mDepth = maxDepthSplit;
+ dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
+ dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
+ dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices;
+ dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
+ ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
+ // create the hull into the _hulls variable
+ convexBuilder.process(dcomp);
+
+ physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
+ BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count);
+
+ // Convert the vertices and indices for passing to unmanaged.
+ // The hull information is passed as a large floating point array.
+ // The format is:
+ // convHulls[0] = number of hulls
+ // convHulls[1] = number of vertices in first hull
+ // convHulls[2] = hull centroid X coordinate
+ // convHulls[3] = hull centroid Y coordinate
+ // convHulls[4] = hull centroid Z coordinate
+ // convHulls[5] = first hull vertex X
+ // convHulls[6] = first hull vertex Y
+ // convHulls[7] = first hull vertex Z
+ // convHulls[8] = second hull vertex X
+ // ...
+ // convHulls[n] = number of vertices in second hull
+ // convHulls[n+1] = second hull centroid X coordinate
+ // ...
+ //
+ // TODO: is is very inefficient. Someday change the convex hull generator to return
+ // data structures that do not need to be converted in order to pass to Bullet.
+ // And maybe put the values directly into pinned memory rather than marshaling.
+ int hullCount = m_hulls.Count;
+ int totalVertices = 1; // include one for the count of the hulls
+ foreach (ConvexResult cr in m_hulls)
+ {
+ totalVertices += 4; // add four for the vertex count and centroid
+ totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
+ }
+ float[] convHulls = new float[totalVertices];
+
+ convHulls[0] = (float)hullCount;
+ int jj = 1;
+ foreach (ConvexResult cr in m_hulls)
+ {
+ // copy vertices for index access
+ float3[] verts = new float3[cr.HullVertices.Count];
+ int kk = 0;
+ foreach (float3 ff in cr.HullVertices)
+ {
+ verts[kk++] = ff;
+ }
+
+ // add to the array one hull's worth of data
+ convHulls[jj++] = cr.HullIndices.Count;
+ convHulls[jj++] = 0f; // centroid x,y,z
+ convHulls[jj++] = 0f;
+ convHulls[jj++] = 0f;
+ foreach (int ind in cr.HullIndices)
+ {
+ convHulls[jj++] = verts[ind].x;
+ convHulls[jj++] = verts[ind].y;
+ convHulls[jj++] = verts[ind].z;
+ }
+ }
+ // create the hull data structure in Bullet
+ newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
+ }
+ newShape.shapeKey = newHullKey;
+ return newShape;
+ }
+ // Callback from convex hull creater with a newly created hull.
+ // Just add it to our collection of hulls for this shape.
+ private void HullReturn(ConvexResult result)
+ {
+ m_hulls.Add(result);
+ return;
+ }
+ // Loop through all the known hulls and return the description based on the physical address.
+ public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
+ {
+ bool ret = false;
+ BSShapeHull foundDesc = null;
+ lock (Hulls)
+ {
+ foreach (BSShapeHull sh in Hulls.Values)
+ {
+ if (sh.physShapeInfo.ReferenceSame(pShape))
+ {
+ foundDesc = sh;
+ ret = true;
+ break;
+ }
+
+ }
+ }
+ outHull = foundDesc;
+ return ret;
+ }
+}
+
+// ============================================================================================================
+// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate
+// meshes. Used by BulletSim for complex shapes like linksets.
+public class BSShapeCompound : BSShape
+{
+ private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
+ public static Dictionary CompoundShapes = new Dictionary