aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs58
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs441
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs21
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs137
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs112
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs378
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs161
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs928
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs123
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs735
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs133
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs291
13 files changed, 2150 insertions, 1372 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
index 683bc51..3306a97 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
@@ -34,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public class BS6DofConstraint : BSConstraint 35public class BS6DofConstraint : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
37 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
38 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
39 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
@@ -44,11 +48,14 @@ public class BS6DofConstraint : BSConstraint
44 m_body1 = obj1; 48 m_body1 = obj1;
45 m_body2 = obj2; 49 m_body2 = obj2;
46 m_constraint = new BulletConstraint( 50 m_constraint = new BulletConstraint(
47 BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
48 frame1, frame1rot, 52 frame1, frame1rot,
49 frame2, frame2rot, 53 frame2, frame2rot,
50 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
51 m_enabled = true; 55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
52 } 59 }
53 60
54 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
@@ -58,11 +65,36 @@ public class BS6DofConstraint : BSConstraint
58 m_world = world; 65 m_world = world;
59 m_body1 = obj1; 66 m_body1 = obj1;
60 m_body2 = obj2; 67 m_body2 = obj2;
61 m_constraint = new BulletConstraint( 68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
62 BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 69 {
63 joinPoint, 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
64 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 71 BSScene.DetailLogZero, world.worldID,
65 m_enabled = true; 72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 "[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
75 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
76 m_enabled = false;
77 }
78 else
79 {
80 m_constraint = new BulletConstraint(
81 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
82 joinPoint,
83 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
84 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
85 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
86 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
87 if (m_constraint.ptr == IntPtr.Zero)
88 {
89 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
90 LogHeader, obj1.ID, obj2.ID);
91 m_enabled = false;
92 }
93 else
94 {
95 m_enabled = true;
96 }
97 }
66 } 98 }
67 99
68 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 100 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
@@ -70,7 +102,7 @@ public class BS6DofConstraint : BSConstraint
70 bool ret = false; 102 bool ret = false;
71 if (m_enabled) 103 if (m_enabled)
72 { 104 {
73 BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); 105 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
74 ret = true; 106 ret = true;
75 } 107 }
76 return ret; 108 return ret;
@@ -81,9 +113,9 @@ public class BS6DofConstraint : BSConstraint
81 bool ret = false; 113 bool ret = false;
82 if (m_enabled) 114 if (m_enabled)
83 { 115 {
84 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
85 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
86 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 118 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
87 ret = true; 119 ret = true;
88 } 120 }
89 return ret; 121 return ret;
@@ -94,7 +126,7 @@ public class BS6DofConstraint : BSConstraint
94 bool ret = false; 126 bool ret = false;
95 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 127 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
96 if (m_enabled) 128 if (m_enabled)
97 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); 129 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
98 return ret; 130 return ret;
99 } 131 }
100 132
@@ -103,7 +135,7 @@ public class BS6DofConstraint : BSConstraint
103 bool ret = false; 135 bool ret = false;
104 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 136 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
105 if (m_enabled) 137 if (m_enabled)
106 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); 138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
107 return ret; 139 return ret;
108 } 140 }
109 141
@@ -111,7 +143,7 @@ public class BS6DofConstraint : BSConstraint
111 { 143 {
112 bool ret = false; 144 bool ret = false;
113 if (m_enabled) 145 if (m_enabled)
114 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); 146 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
115 return ret; 147 return ret;
116 } 148 }
117} 149}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 526dbad..b88ec3c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,7 +28,7 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
@@ -39,48 +39,35 @@ public class BSCharacter : BSPhysObject
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
41 41
42 public BSScene Scene { get; private set; }
43 private String _avName;
44 // private bool _stopped; 42 // private bool _stopped;
45 private Vector3 _size; 43 private OMV.Vector3 _size;
46 private Vector3 _scale; 44 private OMV.Vector3 _scale;
47 private PrimitiveBaseShape _pbs; 45 private PrimitiveBaseShape _pbs;
48 private uint _localID = 0;
49 private bool _grabbed; 46 private bool _grabbed;
50 private bool _selected; 47 private bool _selected;
51 private Vector3 _position; 48 private OMV.Vector3 _position;
52 private float _mass; 49 private float _mass;
53 public float _density; 50 private float _avatarDensity;
54 public float _avatarVolume; 51 private float _avatarVolume;
55 private Vector3 _force; 52 private OMV.Vector3 _force;
56 private Vector3 _velocity; 53 private OMV.Vector3 _velocity;
57 private Vector3 _torque; 54 private OMV.Vector3 _torque;
58 private float _collisionScore; 55 private float _collisionScore;
59 private Vector3 _acceleration; 56 private OMV.Vector3 _acceleration;
60 private Quaternion _orientation; 57 private OMV.Quaternion _orientation;
61 private int _physicsActorType; 58 private int _physicsActorType;
62 private bool _isPhysical; 59 private bool _isPhysical;
63 private bool _flying; 60 private bool _flying;
64 private bool _setAlwaysRun; 61 private bool _setAlwaysRun;
65 private bool _throttleUpdates; 62 private bool _throttleUpdates;
66 private bool _isColliding; 63 private bool _isColliding;
67 private long _collidingStep;
68 private bool _collidingGround;
69 private long _collidingGroundStep;
70 private bool _collidingObj; 64 private bool _collidingObj;
71 private bool _floatOnWater; 65 private bool _floatOnWater;
72 private Vector3 _rotationalVelocity; 66 private OMV.Vector3 _rotationalVelocity;
73 private bool _kinematic; 67 private bool _kinematic;
74 private float _buoyancy; 68 private float _buoyancy;
75 69
76 public override BulletBody BSBody { get; set; } 70 private OMV.Vector3 _PIDTarget;
77 public override BulletShape BSShape { get; set; }
78 public override BSLinkset Linkset { get; set; }
79
80 private int _subscribedEventsMs = 0;
81 private int _nextCollisionOkTime = 0;
82
83 private Vector3 _PIDTarget;
84 private bool _usePID; 71 private bool _usePID;
85 private float _PIDTau; 72 private float _PIDTau;
86 private bool _useHoverPID; 73 private bool _useHoverPID;
@@ -88,28 +75,26 @@ public class BSCharacter : BSPhysObject
88 private PIDHoverType _PIDHoverType; 75 private PIDHoverType _PIDHoverType;
89 private float _PIDHoverTao; 76 private float _PIDHoverTao;
90 77
91 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 78 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
92 { 79 {
93 _localID = localID; 80 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
94 _avName = avName;
95 Scene = parent_scene;
96 _physicsActorType = (int)ActorTypes.Agent; 81 _physicsActorType = (int)ActorTypes.Agent;
97 _position = pos; 82 _position = pos;
98 _size = size; 83 _size = size;
99 _flying = isFlying; 84 _flying = isFlying;
100 _orientation = Quaternion.Identity; 85 _orientation = OMV.Quaternion.Identity;
101 _velocity = Vector3.Zero; 86 _velocity = OMV.Vector3.Zero;
102 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 87 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
88
103 // The dimensions of the avatar capsule are kept in the scale. 89 // The dimensions of the avatar capsule are kept in the scale.
104 // Physics creates a unit capsule which is scaled by the physics engine. 90 // Physics creates a unit capsule which is scaled by the physics engine.
105 _scale = new Vector3(Scene.Params.avatarCapsuleRadius, Scene.Params.avatarCapsuleRadius, size.Z); 91 ComputeAvatarScale(_size);
106 _density = Scene.Params.avatarDensity; 92 _avatarDensity = PhysicsScene.Params.avatarDensity;
107 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 93 // set _avatarVolume and _mass based on capsule size, _density and _scale
108 94 ComputeAvatarVolumeAndMass();
109 Linkset = new BSLinkset(Scene, this);
110 95
111 ShapeData shapeData = new ShapeData(); 96 ShapeData shapeData = new ShapeData();
112 shapeData.ID = _localID; 97 shapeData.ID = LocalID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR; 98 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position; 99 shapeData.Position = _position;
115 shapeData.Rotation = _orientation; 100 shapeData.Rotation = _orientation;
@@ -118,21 +103,25 @@ public class BSCharacter : BSPhysObject
118 shapeData.Mass = _mass; 103 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy; 104 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse; 105 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = Scene.Params.avatarFriction; 106 shapeData.Friction = PhysicsScene.Params.avatarFriction;
122 shapeData.Restitution = Scene.Params.avatarRestitution; 107 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
123 108
124 // do actual create at taint time 109 // do actual create at taint time
125 Scene.TaintedObject("BSCharacter.create", delegate() 110 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 111 {
127 DetailLog("{0},BSCharacter.create", _localID); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
128 BulletSimAPI.CreateObject(Scene.WorldID, shapeData); 113 BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData);
129 114
130 // Set the buoyancy for flying. This will be refactored when all the settings happen in C# 115 // Set the buoyancy for flying. This will be refactored when all the settings happen in C#.
131 BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy); 116 // If not set at creation, the avatar will stop flying when created after crossing a region boundry.
117 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
132 118
133 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(Scene.World.Ptr, LocalID)); 119 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID));
120
121 // This works here because CreateObject has already put the character into the physical world.
122 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr,
123 (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask);
134 }); 124 });
135
136 return; 125 return;
137 } 126 }
138 127
@@ -140,9 +129,9 @@ public class BSCharacter : BSPhysObject
140 public override void Destroy() 129 public override void Destroy()
141 { 130 {
142 DetailLog("{0},BSCharacter.Destroy", LocalID); 131 DetailLog("{0},BSCharacter.Destroy", LocalID);
143 Scene.TaintedObject("BSCharacter.destroy", delegate() 132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
144 { 133 {
145 BulletSimAPI.DestroyObject(Scene.WorldID, _localID); 134 BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID);
146 }); 135 });
147 } 136 }
148 137
@@ -151,70 +140,83 @@ public class BSCharacter : BSPhysObject
151 base.RequestPhysicsterseUpdate(); 140 base.RequestPhysicsterseUpdate();
152 } 141 }
153 // No one calls this method so I don't know what it could possibly mean 142 // No one calls this method so I don't know what it could possibly mean
154 public override bool Stopped { 143 public override bool Stopped {
155 get { return false; } 144 get { return false; }
156 } 145 }
157 public override Vector3 Size { 146 public override OMV.Vector3 Size {
158 get 147 get
159 { 148 {
160 // Avatar capsule size is kept in the scale parameter. 149 // Avatar capsule size is kept in the scale parameter.
161 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 150 return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z);
162 } 151 }
163 152
164 set { 153 set {
165 // When an avatar's size is set, only the height is changed 154 // When an avatar's size is set, only the height is changed
166 // and that really only depends on the radius. 155 // and that really only depends on the radius.
167 _size = value; 156 _size = value;
168 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 157 ComputeAvatarScale(_size);
169 158
170 // TODO: something has to be done with the avatar's vertical position 159 // TODO: something has to be done with the avatar's vertical position
171 160
172 ComputeAvatarVolumeAndMass(); 161 ComputeAvatarVolumeAndMass();
173 162
174 Scene.TaintedObject("BSCharacter.setSize", delegate() 163 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
175 { 164 {
176 BulletSimAPI.SetObjectScaleMass(Scene.WorldID, LocalID, _scale, _mass, true); 165 BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true);
177 }); 166 });
178 167
179 } 168 }
180 }
181 public override PrimitiveBaseShape Shape {
182 set { _pbs = value;
183 }
184 } 169 }
185 public override uint LocalID { 170 public override PrimitiveBaseShape Shape {
186 set { _localID = value; 171 set { _pbs = value;
187 } 172 }
188 get { return _localID; }
189 } 173 }
190 public override bool Grabbed { 174 public override bool Grabbed {
191 set { _grabbed = value; 175 set { _grabbed = value;
192 } 176 }
193 } 177 }
194 public override bool Selected { 178 public override bool Selected {
195 set { _selected = value; 179 set { _selected = value;
196 } 180 }
197 } 181 }
198 public override void CrossingFailure() { return; } 182 public override void CrossingFailure() { return; }
199 public override void link(PhysicsActor obj) { return; } 183 public override void link(PhysicsActor obj) { return; }
200 public override void delink() { return; } 184 public override void delink() { return; }
201 public override void LockAngularMotion(Vector3 axis) { return; }
202 185
203 public override Vector3 Position { 186 // Set motion values to zero.
187 // Do it to the properties so the values get set in the physics engine.
188 // Push the setting of the values to the viewer.
189 // Called at taint time!
190 public override void ZeroMotion()
191 {
192 _velocity = OMV.Vector3.Zero;
193 _acceleration = OMV.Vector3.Zero;
194 _rotationalVelocity = OMV.Vector3.Zero;
195
196 // Zero some other properties directly into the physics engine
197 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero);
198 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero);
199 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
200 BulletSimAPI.ClearForces2(BSBody.ptr);
201 }
202
203 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
204
205 public override OMV.Vector3 Position {
204 get { 206 get {
205 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 207 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
206 return _position; 208 return _position;
207 } 209 }
208 set { 210 set {
209 _position = value; 211 _position = value;
210 PositionSanityCheck(); 212 PositionSanityCheck();
211 213
212 Scene.TaintedObject("BSCharacter.setPosition", delegate() 214 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
213 { 215 {
214 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 216 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
215 BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); 217 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
216 }); 218 });
217 } 219 }
218 } 220 }
219 221
220 // Check that the current position is sane and, if not, modify the position to make it so. 222 // Check that the current position is sane and, if not, modify the position to make it so.
@@ -223,9 +225,9 @@ public class BSCharacter : BSPhysObject
223 private bool PositionSanityCheck() 225 private bool PositionSanityCheck()
224 { 226 {
225 bool ret = false; 227 bool ret = false;
226 228
227 // If below the ground, move the avatar up 229 // If below the ground, move the avatar up
228 float terrainHeight = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); 230 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
229 if (Position.Z < terrainHeight) 231 if (Position.Z < terrainHeight)
230 { 232 {
231 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 233 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
@@ -247,200 +249,200 @@ public class BSCharacter : BSPhysObject
247 { 249 {
248 // The new position value must be pushed into the physics engine but we can't 250 // The new position value must be pushed into the physics engine but we can't
249 // just assign to "Position" because of potential call loops. 251 // just assign to "Position" because of potential call loops.
250 Scene.TaintedObject("BSCharacter.PositionSanityCheck", delegate() 252 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", delegate()
251 { 253 {
252 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 254 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
253 BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); 255 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
254 }); 256 });
255 ret = true; 257 ret = true;
256 } 258 }
257 return ret; 259 return ret;
258 } 260 }
259 261
260 public override float Mass { 262 public override float Mass {
261 get { 263 get {
262 return _mass; 264 return _mass;
263 } 265 }
264 } 266 }
265 267
266 // used when we only want this prim's mass and not the linkset thing 268 // used when we only want this prim's mass and not the linkset thing
267 public override float MassRaw { get {return _mass; } } 269 public override float MassRaw { get {return _mass; } }
268 270
269 public override Vector3 Force { 271 public override OMV.Vector3 Force {
270 get { return _force; } 272 get { return _force; }
271 set { 273 set {
272 _force = value; 274 _force = value;
273 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 275 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
274 Scene.TaintedObject("BSCharacter.SetForce", delegate() 276 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
275 { 277 {
276 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 278 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
277 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 279 BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force);
278 }); 280 });
279 } 281 }
280 } 282 }
281 283
282 public override int VehicleType { 284 public override int VehicleType {
283 get { return 0; } 285 get { return 0; }
284 set { return; } 286 set { return; }
285 } 287 }
286 public override void VehicleFloatParam(int param, float value) { } 288 public override void VehicleFloatParam(int param, float value) { }
287 public override void VehicleVectorParam(int param, Vector3 value) {} 289 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
288 public override void VehicleRotationParam(int param, Quaternion rotation) { } 290 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
289 public override void VehicleFlags(int param, bool remove) { } 291 public override void VehicleFlags(int param, bool remove) { }
290 292
291 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 293 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
292 public override void SetVolumeDetect(int param) { return; } 294 public override void SetVolumeDetect(int param) { return; }
293 295
294 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 296 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
295 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 297 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
296 public override Vector3 Velocity { 298 public override OMV.Vector3 Velocity {
297 get { return _velocity; } 299 get { return _velocity; }
298 set { 300 set {
299 _velocity = value; 301 _velocity = value;
300 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 302 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
301 Scene.TaintedObject("BSCharacter.setVelocity", delegate() 303 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
302 { 304 {
303 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 305 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
304 BulletSimAPI.SetObjectVelocity(Scene.WorldID, _localID, _velocity); 306 BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity);
305 }); 307 });
306 } 308 }
307 } 309 }
308 public override Vector3 Torque { 310 public override OMV.Vector3 Torque {
309 get { return _torque; } 311 get { return _torque; }
310 set { _torque = value; 312 set { _torque = value;
311 } 313 }
312 } 314 }
313 public override float CollisionScore { 315 public override float CollisionScore {
314 get { return _collisionScore; } 316 get { return _collisionScore; }
315 set { _collisionScore = value; 317 set { _collisionScore = value;
316 } 318 }
317 } 319 }
318 public override Vector3 Acceleration { 320 public override OMV.Vector3 Acceleration {
319 get { return _acceleration; } 321 get { return _acceleration; }
320 set { _acceleration = value; } 322 set { _acceleration = value; }
321 } 323 }
322 public override Quaternion Orientation { 324 public override OMV.Quaternion Orientation {
323 get { return _orientation; } 325 get { return _orientation; }
324 set { 326 set {
325 _orientation = value; 327 _orientation = value;
326 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 328 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
327 Scene.TaintedObject("BSCharacter.setOrientation", delegate() 329 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
328 { 330 {
329 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); 331 // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID);
330 BulletSimAPI.SetObjectTranslation(Scene.WorldID, _localID, _position, _orientation); 332 BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation);
331 }); 333 });
332 } 334 }
333 } 335 }
334 public override int PhysicsActorType { 336 public override int PhysicsActorType {
335 get { return _physicsActorType; } 337 get { return _physicsActorType; }
336 set { _physicsActorType = value; 338 set { _physicsActorType = value;
337 } 339 }
338 } 340 }
339 public override bool IsPhysical { 341 public override bool IsPhysical {
340 get { return _isPhysical; } 342 get { return _isPhysical; }
341 set { _isPhysical = value; 343 set { _isPhysical = value;
342 } 344 }
343 } 345 }
344 public override bool Flying { 346 public override bool Flying {
345 get { return _flying; } 347 get { return _flying; }
346 set { 348 set {
347 _flying = value; 349 _flying = value;
348 // simulate flying by changing the effect of gravity 350 // simulate flying by changing the effect of gravity
349 this.Buoyancy = ComputeBuoyancyFromFlying(_flying); 351 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
350 } 352 }
351 } 353 }
352 // Flying is implimented by changing the avatar's buoyancy. 354 // Flying is implimented by changing the avatar's buoyancy.
353 // Would this be done better with a vehicle type? 355 // Would this be done better with a vehicle type?
354 private float ComputeBuoyancyFromFlying(bool ifFlying) { 356 private float ComputeBuoyancyFromFlying(bool ifFlying) {
355 return ifFlying ? 1f : 0f; 357 return ifFlying ? 1f : 0f;
356 } 358 }
357 public override bool 359 public override bool
358 SetAlwaysRun { 360 SetAlwaysRun {
359 get { return _setAlwaysRun; } 361 get { return _setAlwaysRun; }
360 set { _setAlwaysRun = value; } 362 set { _setAlwaysRun = value; }
361 } 363 }
362 public override bool ThrottleUpdates { 364 public override bool ThrottleUpdates {
363 get { return _throttleUpdates; } 365 get { return _throttleUpdates; }
364 set { _throttleUpdates = value; } 366 set { _throttleUpdates = value; }
365 } 367 }
366 public override bool IsColliding { 368 public override bool IsColliding {
367 get { return (_collidingStep == Scene.SimulationStep); } 369 get { return (CollidingStep == PhysicsScene.SimulationStep); }
368 set { _isColliding = value; } 370 set { _isColliding = value; }
369 } 371 }
370 public override bool CollidingGround { 372 public override bool CollidingGround {
371 get { return (_collidingGroundStep == Scene.SimulationStep); } 373 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
372 set { _collidingGround = value; } 374 set { CollidingGround = value; }
373 } 375 }
374 public override bool CollidingObj { 376 public override bool CollidingObj {
375 get { return _collidingObj; } 377 get { return _collidingObj; }
376 set { _collidingObj = value; } 378 set { _collidingObj = value; }
377 } 379 }
378 public override bool FloatOnWater { 380 public override bool FloatOnWater {
379 set { _floatOnWater = value; } 381 set { _floatOnWater = value; }
380 } 382 }
381 public override Vector3 RotationalVelocity { 383 public override OMV.Vector3 RotationalVelocity {
382 get { return _rotationalVelocity; } 384 get { return _rotationalVelocity; }
383 set { _rotationalVelocity = value; } 385 set { _rotationalVelocity = value; }
384 } 386 }
385 public override bool Kinematic { 387 public override bool Kinematic {
386 get { return _kinematic; } 388 get { return _kinematic; }
387 set { _kinematic = value; } 389 set { _kinematic = value; }
388 } 390 }
389 // neg=fall quickly, 0=1g, 1=0g, pos=float up 391 // neg=fall quickly, 0=1g, 1=0g, pos=float up
390 public override float Buoyancy { 392 public override float Buoyancy {
391 get { return _buoyancy; } 393 get { return _buoyancy; }
392 set { _buoyancy = value; 394 set { _buoyancy = value;
393 Scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 395 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
394 { 396 {
395 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 397 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
396 BulletSimAPI.SetObjectBuoyancy(Scene.WorldID, LocalID, _buoyancy); 398 BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy);
397 }); 399 });
398 } 400 }
399 } 401 }
400 402
401 // Used for MoveTo 403 // Used for MoveTo
402 public override Vector3 PIDTarget { 404 public override OMV.Vector3 PIDTarget {
403 set { _PIDTarget = value; } 405 set { _PIDTarget = value; }
404 } 406 }
405 public override bool PIDActive { 407 public override bool PIDActive {
406 set { _usePID = value; } 408 set { _usePID = value; }
407 } 409 }
408 public override float PIDTau { 410 public override float PIDTau {
409 set { _PIDTau = value; } 411 set { _PIDTau = value; }
410 } 412 }
411 413
412 // Used for llSetHoverHeight and maybe vehicle height 414 // Used for llSetHoverHeight and maybe vehicle height
413 // Hover Height will override MoveTo target's Z 415 // Hover Height will override MoveTo target's Z
414 public override bool PIDHoverActive { 416 public override bool PIDHoverActive {
415 set { _useHoverPID = value; } 417 set { _useHoverPID = value; }
416 } 418 }
417 public override float PIDHoverHeight { 419 public override float PIDHoverHeight {
418 set { _PIDHoverHeight = value; } 420 set { _PIDHoverHeight = value; }
419 } 421 }
420 public override PIDHoverType PIDHoverType { 422 public override PIDHoverType PIDHoverType {
421 set { _PIDHoverType = value; } 423 set { _PIDHoverType = value; }
422 } 424 }
423 public override float PIDHoverTau { 425 public override float PIDHoverTau {
424 set { _PIDHoverTao = value; } 426 set { _PIDHoverTao = value; }
425 } 427 }
426 428
427 // For RotLookAt 429 // For RotLookAt
428 public override Quaternion APIDTarget { set { return; } } 430 public override OMV.Quaternion APIDTarget { set { return; } }
429 public override bool APIDActive { set { return; } } 431 public override bool APIDActive { set { return; } }
430 public override float APIDStrength { set { return; } } 432 public override float APIDStrength { set { return; } }
431 public override float APIDDamping { set { return; } } 433 public override float APIDDamping { set { return; } }
432 434
433 public override void AddForce(Vector3 force, bool pushforce) { 435 public override void AddForce(OMV.Vector3 force, bool pushforce) {
434 if (force.IsFinite()) 436 if (force.IsFinite())
435 { 437 {
436 _force.X += force.X; 438 _force.X += force.X;
437 _force.Y += force.Y; 439 _force.Y += force.Y;
438 _force.Z += force.Z; 440 _force.Z += force.Z;
439 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 441 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
440 Scene.TaintedObject("BSCharacter.AddForce", delegate() 442 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
441 { 443 {
442 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 444 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
443 BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force); 445 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
444 }); 446 });
445 } 447 }
446 else 448 else
@@ -450,42 +452,19 @@ public class BSCharacter : BSPhysObject
450 //m_lastUpdateSent = false; 452 //m_lastUpdateSent = false;
451 } 453 }
452 454
453 public override void AddAngularForce(Vector3 force, bool pushforce) { 455 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
454 } 456 }
455 public override void SetMomentum(Vector3 momentum) { 457 public override void SetMomentum(OMV.Vector3 momentum) {
456 } 458 }
457 459
458 // Turn on collision events at a rate no faster than one every the given milliseconds 460 private void ComputeAvatarScale(OMV.Vector3 size)
459 public override void SubscribeEvents(int ms) {
460 _subscribedEventsMs = ms;
461 if (ms > 0)
462 {
463 // make sure first collision happens
464 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
465
466 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate()
467 {
468 BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
469 });
470 }
471 }
472
473 public override void ZeroMotion()
474 { 461 {
475 return; 462 _scale.X = PhysicsScene.Params.avatarCapsuleRadius;
476 } 463 _scale.Y = PhysicsScene.Params.avatarCapsuleRadius;
477 464
478 // Stop collision events 465 // The 1.15 came from ODE but it seems to cause the avatar to float off the ground
479 public override void UnSubscribeEvents() { 466 // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y);
480 _subscribedEventsMs = 0; 467 _scale.Z = (_size.Z) - (_scale.X + _scale.Y);
481 Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
482 {
483 BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
484 });
485 }
486 // Return 'true' if someone has subscribed to events
487 public override bool SubscribedEvents() {
488 return (_subscribedEventsMs > 0);
489 } 468 }
490 469
491 // set _avatarVolume and _mass based on capsule size, _density and _scale 470 // set _avatarVolume and _mass based on capsule size, _density and _scale
@@ -502,7 +481,7 @@ public class BSCharacter : BSPhysObject
502 * Math.Min(_scale.X, _scale.Y) 481 * Math.Min(_scale.X, _scale.Y)
503 * _scale.Y // plus the volume of the capsule end caps 482 * _scale.Y // plus the volume of the capsule end caps
504 ); 483 );
505 _mass = _density * _avatarVolume; 484 _mass = _avatarDensity * _avatarVolume;
506 } 485 }
507 486
508 // The physics engine says that properties have updated. Update same and inform 487 // The physics engine says that properties have updated. Update same and inform
@@ -520,67 +499,9 @@ public class BSCharacter : BSPhysObject
520 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 499 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
521 PositionSanityCheck2(); 500 PositionSanityCheck2();
522 501
523 float heightHere = Scene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug 502 float heightHere = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); // only for debug
524 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}", 503 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5},terrain={6}",
525 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere); 504 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity, heightHere);
526 } 505 }
527
528 // Called by the scene when a collision with this object is reported
529 // The collision, if it should be reported to the character, is placed in a collection
530 // that will later be sent to the simulator when SendCollisions() is called.
531 CollisionEventUpdate collisionCollection = null;
532 public override bool Collide(uint collidingWith, BSPhysObject collidee, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
533 {
534 bool ret = false;
535
536 // The following makes IsColliding() and IsCollidingGround() work
537 _collidingStep = Scene.SimulationStep;
538 if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
539 {
540 _collidingGroundStep = Scene.SimulationStep;
541 }
542 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
543
544 // throttle collisions to the rate specified in the subscription
545 if (SubscribedEvents()) {
546 int nowTime = Scene.SimulationNowTime;
547 if (nowTime >= _nextCollisionOkTime) {
548 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
549
550 if (collisionCollection == null)
551 collisionCollection = new CollisionEventUpdate();
552 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
553 ret = true;
554 }
555 }
556 return ret;
557 }
558
559 public override void SendCollisions()
560 {
561 /*
562 if (collisionCollection != null && collisionCollection.Count > 0)
563 {
564 base.SendCollisionUpdate(collisionCollection);
565 collisionCollection = null;
566 }
567 */
568 // Kludge to make a collision call even if there are no collisions.
569 // This causes the avatar animation to get updated.
570 if (collisionCollection == null)
571 collisionCollection = new CollisionEventUpdate();
572 base.SendCollisionUpdate(collisionCollection);
573 // If there were any collisions in the collection, make sure we don't use the
574 // same instance next time.
575 if (collisionCollection.Count > 0)
576 collisionCollection = null;
577 // End kludge
578 }
579
580 // Invoke the detailed logger and output something if it's enabled.
581 private void DetailLog(string msg, params Object[] args)
582 {
583 Scene.PhysicsLogging.Write(msg, args);
584 }
585} 506}
586} 507}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 1376a29..63a4127 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -49,20 +49,23 @@ public abstract class BSConstraint : IDisposable
49 if (m_enabled) 49 if (m_enabled)
50 { 50 {
51 m_enabled = false; 51 m_enabled = false;
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr); 52 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); 53 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
54 m_constraint.Ptr = System.IntPtr.Zero; 54 m_constraint.ptr = System.IntPtr.Zero;
55 } 55 }
56 } 56 }
57 57
58 public BulletBody Body1 { get { return m_body1; } } 58 public BulletBody Body1 { get { return m_body1; } }
59 public BulletBody Body2 { get { return m_body2; } } 59 public BulletBody Body2 { get { return m_body2; } }
60 public BulletConstraint Constraint { get { return m_constraint; } }
61 public abstract ConstraintType Type { get; }
62
60 63
61 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 64 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
62 { 65 {
63 bool ret = false; 66 bool ret = false;
64 if (m_enabled) 67 if (m_enabled)
65 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); 68 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
66 return ret; 69 return ret;
67 } 70 }
68 71
@@ -70,7 +73,7 @@ public abstract class BSConstraint : IDisposable
70 { 73 {
71 bool ret = false; 74 bool ret = false;
72 if (m_enabled) 75 if (m_enabled)
73 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); 76 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
74 return ret; 77 return ret;
75 } 78 }
76 79
@@ -79,7 +82,7 @@ public abstract class BSConstraint : IDisposable
79 bool ret = false; 82 bool ret = false;
80 if (m_enabled) 83 if (m_enabled)
81 { 84 {
82 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.Ptr, cnt); 85 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
83 ret = true; 86 ret = true;
84 } 87 }
85 return ret; 88 return ret;
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
91 if (m_enabled) 94 if (m_enabled)
92 { 95 {
93 // Recompute the internal transforms 96 // Recompute the internal transforms
94 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); 97 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
95 ret = true; 98 ret = true;
96 } 99 }
97 return ret; 100 return ret;
@@ -110,11 +113,11 @@ public abstract class BSConstraint : IDisposable
110 // Setting an object's mass to zero (making it static like when it's selected) 113 // Setting an object's mass to zero (making it static like when it's selected)
111 // automatically disables the constraints. 114 // automatically disables the constraints.
112 // If the link is enabled, be sure to set the constraint itself to enabled. 115 // If the link is enabled, be sure to set the constraint itself to enabled.
113 BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); 116 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
114 } 117 }
115 else 118 else
116 { 119 {
117 m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 120 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID);
118 } 121 }
119 } 122 }
120 return ret; 123 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 61006f0..65b38d6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -54,18 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public class BSDynamics
56 { 56 {
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private BSScene PhysicsScene { get; set; }
58 // every 100th frame 58 // the prim this dynamic controller belongs to
59 59 private BSPrim Prim { get; set; }
60 private BSScene m_physicsScene;
61 private BSPrim m_prim; // the prim this dynamic controller belongs to
62 60
63 // Vehicle properties 61 // Vehicle properties
64 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind 62 public Vehicle Type { get; set; }
65 public Vehicle Type 63
66 {
67 get { return m_type; }
68 }
69 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier 64 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
70 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: 65 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
71 // HOVER_TERRAIN_ONLY 66 // HOVER_TERRAIN_ONLY
@@ -126,14 +121,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
126 121
127 public BSDynamics(BSScene myScene, BSPrim myPrim) 122 public BSDynamics(BSScene myScene, BSPrim myPrim)
128 { 123 {
129 m_physicsScene = myScene; 124 PhysicsScene = myScene;
130 m_prim = myPrim; 125 Prim = myPrim;
131 m_type = Vehicle.TYPE_NONE; 126 Type = Vehicle.TYPE_NONE;
127 }
128
129 // Return 'true' if this vehicle is doing vehicle things
130 public bool IsActive
131 {
132 get { return Type != Vehicle.TYPE_NONE; }
132 } 133 }
133 134
134 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 135 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
135 { 136 {
136 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 137 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
137 switch (pParam) 138 switch (pParam)
138 { 139 {
139 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -232,7 +233,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
232 233
233 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 234 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
234 { 235 {
235 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 236 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
236 switch (pParam) 237 switch (pParam)
237 { 238 {
238 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 239 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@@ -267,7 +268,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
267 268
268 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 269 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
269 { 270 {
270 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 271 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
271 switch (pParam) 272 switch (pParam)
272 { 273 {
273 case Vehicle.REFERENCE_FRAME: 274 case Vehicle.REFERENCE_FRAME:
@@ -281,7 +282,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
281 282
282 internal void ProcessVehicleFlags(int pParam, bool remove) 283 internal void ProcessVehicleFlags(int pParam, bool remove)
283 { 284 {
284 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); 285 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
285 VehicleFlag parm = (VehicleFlag)pParam; 286 VehicleFlag parm = (VehicleFlag)pParam;
286 if (remove) 287 if (remove)
287 { 288 {
@@ -301,9 +302,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
301 302
302 internal void ProcessTypeChange(Vehicle pType) 303 internal void ProcessTypeChange(Vehicle pType)
303 { 304 {
304 VDetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); 305 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
305 // Set Defaults For Type 306 // Set Defaults For Type
306 m_type = pType; 307 Type = pType;
307 switch (pType) 308 switch (pType)
308 { 309 {
309 case Vehicle.TYPE_NONE: 310 case Vehicle.TYPE_NONE:
@@ -465,26 +466,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin
465 } 466 }
466 }//end SetDefaultsForType 467 }//end SetDefaultsForType
467 468
469 // Some of the properties of this prim may have changed.
470 // Do any updating needed for a vehicle
471 public void Refresh()
472 {
473 if (Type == Vehicle.TYPE_NONE) return;
474
475 // Set the prim's inertia to zero. The vehicle code handles that and this
476 // removes the torque action introduced by Bullet.
477 Vector3 inertia = Vector3.Zero;
478 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
479 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
480 }
481
468 // One step of the vehicle properties for the next 'pTimestep' seconds. 482 // One step of the vehicle properties for the next 'pTimestep' seconds.
469 internal void Step(float pTimestep) 483 internal void Step(float pTimestep)
470 { 484 {
471 if (m_type == Vehicle.TYPE_NONE) return; 485 if (!IsActive) return;
472
473 frcount++; // used to limit debug comment output
474 if (frcount > 100)
475 frcount = 0;
476 486
477 MoveLinear(pTimestep); 487 MoveLinear(pTimestep);
478 MoveAngular(pTimestep); 488 MoveAngular(pTimestep);
479 LimitRotation(pTimestep); 489 LimitRotation(pTimestep);
480 490
481 // remember the position so next step we can limit absolute movement effects 491 // remember the position so next step we can limit absolute movement effects
482 m_lastPositionVector = m_prim.Position; 492 m_lastPositionVector = Prim.Position;
483 493
484 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 494 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
485 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); 495 Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
486 }// end Step 496 }// end Step
487 497
498 // Apply the effect of the linear motor.
499 // Also does hover and float.
488 private void MoveLinear(float pTimestep) 500 private void MoveLinear(float pTimestep)
489 { 501 {
490 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates 502 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
@@ -499,8 +511,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
499 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep); 511 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep);
500 // lastLinearVelocityVector is the current body velocity vector 512 // lastLinearVelocityVector is the current body velocity vector
501 // RA: Not sure what the *10 is for. A correction for pTimestep? 513 // RA: Not sure what the *10 is for. A correction for pTimestep?
502 // m_lastLinearVelocityVector += (addAmount*10); 514 // m_lastLinearVelocityVector += (addAmount*10);
503 m_lastLinearVelocityVector += addAmount; 515 m_lastLinearVelocityVector += addAmount;
504 516
505 // Limit the velocity vector to less than the last set linear motor direction 517 // Limit the velocity vector to less than the last set linear motor direction
506 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 518 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
@@ -520,18 +532,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
520 m_linearMotorDirection *= keepfraction; 532 m_linearMotorDirection *= keepfraction;
521 533
522 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}", 534 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
523 m_prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector); 535 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
524 } 536 }
525 else 537 else
526 { 538 {
527 // if what remains of direction is very small, zero it. 539 // if what remains of direction is very small, zero it.
528 m_linearMotorDirection = Vector3.Zero; 540 m_linearMotorDirection = Vector3.Zero;
529 m_lastLinearVelocityVector = Vector3.Zero; 541 m_lastLinearVelocityVector = Vector3.Zero;
530 VDetailLog("{0},MoveLinear,zeroed", m_prim.LocalID); 542 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
531 } 543 }
532 544
533 // convert requested object velocity to object relative vector 545 // convert requested object velocity to object relative vector
534 Quaternion rotq = m_prim.Orientation; 546 Quaternion rotq = Prim.Orientation;
535 m_newVelocity = m_lastLinearVelocityVector * rotq; 547 m_newVelocity = m_lastLinearVelocityVector * rotq;
536 548
537 // Add the various forces into m_dir which will be our new direction vector (velocity) 549 // Add the various forces into m_dir which will be our new direction vector (velocity)
@@ -539,7 +551,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
539 // add Gravity and Buoyancy 551 // add Gravity and Buoyancy
540 // There is some gravity, make a gravity force vector that is applied after object velocity. 552 // There is some gravity, make a gravity force vector that is applied after object velocity.
541 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 553 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
542 Vector3 grav = m_prim.Scene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy)); 554 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
543 555
544 /* 556 /*
545 * RA: Not sure why one would do this 557 * RA: Not sure why one would do this
@@ -548,11 +560,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
548 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 560 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
549 */ 561 */
550 562
551 Vector3 pos = m_prim.Position; 563 Vector3 pos = Prim.Position;
552// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); 564// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
553 565
554 // If below the terrain, move us above the ground a little. 566 // If below the terrain, move us above the ground a little.
555 float terrainHeight = m_prim.Scene.TerrainManager.GetTerrainHeightAtXYZ(pos); 567 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
556 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 568 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
557 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. 569 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
558 // Vector3 rotatedSize = m_prim.Size * m_prim.Orientation; 570 // Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
@@ -560,8 +572,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
560 if (pos.Z < terrainHeight) 572 if (pos.Z < terrainHeight)
561 { 573 {
562 pos.Z = terrainHeight + 2; 574 pos.Z = terrainHeight + 2;
563 m_prim.Position = pos; 575 Prim.Position = pos;
564 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", m_prim.LocalID, terrainHeight, pos); 576 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
565 } 577 }
566 578
567 // Check if hovering 579 // Check if hovering
@@ -570,7 +582,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
570 // We should hover, get the target height 582 // We should hover, get the target height
571 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 583 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
572 { 584 {
573 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 585 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
574 } 586 }
575 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 587 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
576 { 588 {
@@ -590,7 +602,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
590 { 602 {
591 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 603 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
592 { 604 {
593 m_prim.Position = pos; 605 Prim.Position = pos;
594 } 606 }
595 } 607 }
596 else 608 else
@@ -608,7 +620,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
608 } 620 }
609 } 621 }
610 622
611 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 623 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
612 } 624 }
613 625
614 Vector3 posChange = pos - m_lastPositionVector; 626 Vector3 posChange = pos - m_lastPositionVector;
@@ -642,9 +654,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
642 } 654 }
643 if (changed) 655 if (changed)
644 { 656 {
645 m_prim.Position = pos; 657 Prim.Position = pos;
646 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 658 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
647 m_prim.LocalID, m_BlockingEndPoint, posChange, pos); 659 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
648 } 660 }
649 } 661 }
650 662
@@ -664,7 +676,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
664 float postemp = (pos.Z - terrainHeight); 676 float postemp = (pos.Z - terrainHeight);
665 if (postemp > 2.5f) 677 if (postemp > 2.5f)
666 grav.Z = (float)(grav.Z * 1.037125); 678 grav.Z = (float)(grav.Z * 1.037125);
667 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav); 679 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
668 } 680 }
669 if ((m_flags & (VehicleFlag.NO_X)) != 0) 681 if ((m_flags & (VehicleFlag.NO_X)) != 0)
670 m_newVelocity.X = 0; 682 m_newVelocity.X = 0;
@@ -674,7 +686,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
674 m_newVelocity.Z = 0; 686 m_newVelocity.Z = 0;
675 687
676 // Apply velocity 688 // Apply velocity
677 m_prim.Velocity = m_newVelocity; 689 Prim.Velocity = m_newVelocity;
678 // apply gravity force 690 // apply gravity force
679 // Why is this set here? The physics engine already does gravity. 691 // Why is this set here? The physics engine already does gravity.
680 // m_prim.AddForce(grav, false); 692 // m_prim.AddForce(grav, false);
@@ -683,11 +695,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
683 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 695 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep));
684 m_lastLinearVelocityVector *= keepFraction; 696 m_lastLinearVelocityVector *= keepFraction;
685 697
686 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", 698 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
687 m_prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); 699 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
688 700
689 } // end MoveLinear() 701 } // end MoveLinear()
690 702
703 // Apply the effect of the angular motor.
691 private void MoveAngular(float pTimestep) 704 private void MoveAngular(float pTimestep)
692 { 705 {
693 // m_angularMotorDirection // angular velocity requested by LSL motor 706 // m_angularMotorDirection // angular velocity requested by LSL motor
@@ -699,7 +712,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
699 // m_lastAngularVelocity // what was last applied to body 712 // m_lastAngularVelocity // what was last applied to body
700 713
701 // Get what the body is doing, this includes 'external' influences 714 // Get what the body is doing, this includes 'external' influences
702 Vector3 angularVelocity = m_prim.RotationalVelocity; 715 Vector3 angularVelocity = Prim.RotationalVelocity;
703 716
704 if (m_angularMotorApply > 0) 717 if (m_angularMotorApply > 0)
705 { 718 {
@@ -715,8 +728,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
715 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 728 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep);
716 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 729 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
717 730
718 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}", 731 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}",
719 m_prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); 732 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
720 733
721 // This is done so that if script request rate is less than phys frame rate the expected 734 // This is done so that if script request rate is less than phys frame rate the expected
722 // velocity may still be acheived. 735 // velocity may still be acheived.
@@ -737,7 +750,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
737 { 750 {
738 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); 751 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
739 // get present body rotation 752 // get present body rotation
740 Quaternion rotq = m_prim.Orientation; 753 Quaternion rotq = Prim.Orientation;
741 // make a vector pointing up 754 // make a vector pointing up
742 Vector3 verterr = Vector3.Zero; 755 Vector3 verterr = Vector3.Zero;
743 verterr.Z = 1.0f; 756 verterr.Z = 1.0f;
@@ -766,8 +779,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
766 vertattr.X += bounce * angularVelocity.X; 779 vertattr.X += bounce * angularVelocity.X;
767 vertattr.Y += bounce * angularVelocity.Y; 780 vertattr.Y += bounce * angularVelocity.Y;
768 781
769 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 782 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
770 m_prim.LocalID, verterr, bounce, vertattr); 783 Prim.LocalID, verterr, bounce, vertattr);
771 784
772 } // else vertical attractor is off 785 } // else vertical attractor is off
773 786
@@ -779,18 +792,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
779 792
780 // Sum velocities 793 // Sum velocities
781 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 794 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection
782 795
783 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 796 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
784 { 797 {
785 m_lastAngularVelocity.X = 0; 798 m_lastAngularVelocity.X = 0;
786 m_lastAngularVelocity.Y = 0; 799 m_lastAngularVelocity.Y = 0;
787 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 800 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
788 } 801 }
789 802
790 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 803 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
791 { 804 {
792 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 805 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
793 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 806 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
794 } 807 }
795 808
796 // apply friction 809 // apply friction
@@ -798,14 +811,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
798 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; 811 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
799 812
800 // Apply to the body 813 // Apply to the body
801 m_prim.RotationalVelocity = m_lastAngularVelocity; 814 Prim.RotationalVelocity = m_lastAngularVelocity;
802 815
803 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); 816 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
804 } //end MoveAngular 817 } //end MoveAngular
805 818
806 internal void LimitRotation(float timestep) 819 internal void LimitRotation(float timestep)
807 { 820 {
808 Quaternion rotq = m_prim.Orientation; 821 Quaternion rotq = Prim.Orientation;
809 Quaternion m_rot = rotq; 822 Quaternion m_rot = rotq;
810 bool changed = false; 823 bool changed = false;
811 if (m_RollreferenceFrame != Quaternion.Identity) 824 if (m_RollreferenceFrame != Quaternion.Identity)
@@ -840,8 +853,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
840 } 853 }
841 if (changed) 854 if (changed)
842 { 855 {
843 m_prim.Orientation = m_rot; 856 Prim.Orientation = m_rot;
844 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", m_prim.LocalID, rotq, m_rot); 857 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
845 } 858 }
846 859
847 } 860 }
@@ -849,8 +862,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
849 // Invoke the detailed logger and output something if it's enabled. 862 // Invoke the detailed logger and output something if it's enabled.
850 private void VDetailLog(string msg, params Object[] args) 863 private void VDetailLog(string msg, params Object[] args)
851 { 864 {
852 if (m_prim.Scene.VehicleLoggingEnabled) 865 if (Prim.PhysicsScene.VehicleLoggingEnabled)
853 m_prim.Scene.PhysicsLogging.Write(msg, args); 866 Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
854 } 867 }
855 } 868 }
856} 869}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
index d68048b..7c8a215 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
@@ -1,55 +1,57 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35class BSHingeConstraint : BSConstraint
36{ 36{
37 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 Vector3 pivotInA, Vector3 pivotInB, 38
39 Vector3 axisInA, Vector3 axisInB, 39 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
40 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 40 Vector3 pivotInA, Vector3 pivotInB,
41 { 41 Vector3 axisInA, Vector3 axisInB,
42 m_world = world; 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 m_body1 = obj1; 43 {
44 m_body2 = obj2; 44 m_world = world;
45 m_constraint = new BulletConstraint( 45 m_body1 = obj1;
46 BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 46 m_body2 = obj2;
47 pivotInA, pivotInB, 47 m_constraint = new BulletConstraint(
48 axisInA, axisInB, 48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 49 pivotInA, pivotInB,
50 m_enabled = true; 50 axisInA, axisInB,
51 } 51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 52 m_enabled = true;
53} 53 }
54 54
55} 55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 7e784eb..4f225ae 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -36,17 +36,24 @@ public class BSLinkset
36{ 36{
37 private static string LogHeader = "[BULLETSIM LINKSET]"; 37 private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 private BSPhysObject m_linksetRoot; 39 public BSPhysObject LinksetRoot { get; protected set; }
40 public BSPhysObject LinksetRoot { get { return m_linksetRoot; } }
41 40
42 private BSScene m_physicsScene; 41 public BSScene PhysicsScene { get; private set; }
43 public BSScene PhysicsScene { get { return m_physicsScene; } }
44 42
45 static int m_nextLinksetID = 1; 43 static int m_nextLinksetID = 1;
46 public int LinksetID { get; private set; } 44 public int LinksetID { get; private set; }
47 45
48 // The children under the root in this linkset 46 // The children under the root in this linkset.
47 // There are two lists of children: the current children at runtime
48 // and the children at taint-time. For instance, if you delink a
49 // child from the linkset, the child is removed from m_children
50 // but the constraint won't be removed until taint time.
51 // Two lists lets this track the 'current' children and
52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these
54 // two lists must be the same.
49 private List<BSPhysObject> m_children; 55 private List<BSPhysObject> m_children;
56 private List<BSPhysObject> m_taintChildren;
50 57
51 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
52 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -55,9 +62,9 @@ public class BSLinkset
55 62
56 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
57 private float m_mass; 64 private float m_mass;
58 public float LinksetMass 65 public float LinksetMass
59 { 66 {
60 get 67 get
61 { 68 {
62 m_mass = ComputeLinksetMass(); 69 m_mass = ComputeLinksetMass();
63 return m_mass; 70 return m_mass;
@@ -79,22 +86,26 @@ public class BSLinkset
79 // A simple linkset of one (no children) 86 // A simple linkset of one (no children)
80 LinksetID = m_nextLinksetID++; 87 LinksetID = m_nextLinksetID++;
81 // We create LOTS of linksets. 88 // We create LOTS of linksets.
82 if (m_nextLinksetID < 0) 89 if (m_nextLinksetID <= 0)
83 m_nextLinksetID = 1; 90 m_nextLinksetID = 1;
84 m_physicsScene = scene; 91 PhysicsScene = scene;
85 m_linksetRoot = parent; 92 LinksetRoot = parent;
86 m_children = new List<BSPhysObject>(); 93 m_children = new List<BSPhysObject>();
94 m_taintChildren = new List<BSPhysObject>();
87 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
88 } 96 }
89 97
90 // Link to a linkset where the child knows the parent. 98 // Link to a linkset where the child knows the parent.
91 // Parent changing should not happen so do some sanity checking. 99 // Parent changing should not happen so do some sanity checking.
92 // We return the parent's linkset so the child can track its membership. 100 // We return the parent's linkset so the child can track its membership.
101 // Called at runtime.
93 public BSLinkset AddMeToLinkset(BSPhysObject child) 102 public BSLinkset AddMeToLinkset(BSPhysObject child)
94 { 103 {
95 lock (m_linksetActivityLock) 104 lock (m_linksetActivityLock)
96 { 105 {
97 AddChildToLinkset(child); 106 // Don't add the root to its own linkset
107 if (!IsRoot(child))
108 AddChildToLinkset(child);
98 } 109 }
99 return this; 110 return this;
100 } 111 }
@@ -102,26 +113,18 @@ public class BSLinkset
102 // Remove a child from a linkset. 113 // Remove a child from a linkset.
103 // Returns a new linkset for the child which is a linkset of one (just the 114 // Returns a new linkset for the child which is a linkset of one (just the
104 // orphened child). 115 // orphened child).
116 // Called at runtime.
105 public BSLinkset RemoveMeFromLinkset(BSPhysObject child) 117 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
106 { 118 {
107 lock (m_linksetActivityLock) 119 lock (m_linksetActivityLock)
108 { 120 {
109 if (IsRoot(child)) 121 if (IsRoot(child))
110 { 122 {
111 // if root of linkset, take the linkset apart 123 // Cannot remove the root from a linkset.
112 while (m_children.Count > 0) 124 return this;
113 {
114 // Note that we don't do a foreach because the remove routine
115 // takes it out of the list.
116 RemoveChildFromOtherLinkset(m_children[0]);
117 }
118 m_children.Clear(); // just to make sure
119 }
120 else
121 {
122 // Just removing a child from an existing linkset
123 RemoveChildFromLinkset(child);
124 } 125 }
126
127 RemoveChildFromLinkset(child);
125 } 128 }
126 129
127 // The child is down to a linkset of just itself 130 // The child is down to a linkset of just itself
@@ -131,7 +134,7 @@ public class BSLinkset
131 // Return 'true' if the passed object is the root object of this linkset 134 // Return 'true' if the passed object is the root object of this linkset
132 public bool IsRoot(BSPhysObject requestor) 135 public bool IsRoot(BSPhysObject requestor)
133 { 136 {
134 return (requestor.LocalID == m_linksetRoot.LocalID); 137 return (requestor.LocalID == LinksetRoot.LocalID);
135 } 138 }
136 139
137 public int NumberOfChildren { get { return m_children.Count; } } 140 public int NumberOfChildren { get { return m_children.Count; } }
@@ -157,51 +160,6 @@ public class BSLinkset
157 return ret; 160 return ret;
158 } 161 }
159 162
160 private float ComputeLinksetMass()
161 {
162 float mass = m_linksetRoot.MassRaw;
163 foreach (BSPhysObject bp in m_children)
164 {
165 mass += bp.MassRaw;
166 }
167 return mass;
168 }
169
170 private OMV.Vector3 ComputeLinksetCenterOfMass()
171 {
172 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw;
173 float totalMass = m_linksetRoot.MassRaw;
174
175 lock (m_linksetActivityLock)
176 {
177 foreach (BSPhysObject bp in m_children)
178 {
179 com += bp.Position * bp.MassRaw;
180 totalMass += bp.MassRaw;
181 }
182 if (totalMass != 0f)
183 com /= totalMass;
184 }
185
186 return com;
187 }
188
189 private OMV.Vector3 ComputeLinksetGeometricCenter()
190 {
191 OMV.Vector3 com = m_linksetRoot.Position;
192
193 lock (m_linksetActivityLock)
194 {
195 foreach (BSPhysObject bp in m_children)
196 {
197 com += bp.Position * bp.MassRaw;
198 }
199 com /= (m_children.Count + 1);
200 }
201
202 return com;
203 }
204
205 // The object is going dynamic (physical). Do any setup necessary 163 // The object is going dynamic (physical). Do any setup necessary
206 // for a dynamic linkset. 164 // for a dynamic linkset.
207 // Only the state of the passed object can be modified. The rest of the linkset 165 // Only the state of the passed object can be modified. The rest of the linkset
@@ -210,8 +168,8 @@ public class BSLinkset
210 // Called at taint-time! 168 // Called at taint-time!
211 public bool MakeDynamic(BSPhysObject child) 169 public bool MakeDynamic(BSPhysObject child)
212 { 170 {
213 bool ret = false; 171 // What is done for each object in BSPrim is what we want.
214 return ret; 172 return false;
215 } 173 }
216 174
217 // The object is going static (non-physical). Do any setup necessary 175 // The object is going static (non-physical). Do any setup necessary
@@ -226,6 +184,7 @@ public class BSLinkset
226 184
227 // When physical properties are changed the linkset needs to recalculate 185 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 186 // its internal properties.
187 // Called at runtime.
229 public void Refresh(BSPhysObject requestor) 188 public void Refresh(BSPhysObject requestor)
230 { 189 {
231 // If there are no children, there can't be any constraints to recompute 190 // If there are no children, there can't be any constraints to recompute
@@ -242,58 +201,125 @@ public class BSLinkset
242 } 201 }
243 } 202 }
244 203
245 // Call each of the constraints that make up this linkset and recompute the 204 // Routine used when rebuilding the body of the root of the linkset
246 // various transforms and variables. Used when objects are added or removed 205 // Destroy all the constraints have have been made to root.
247 // from a linkset to make sure the constraints know about the new mass and 206 // This is called when the root body is changing.
248 // geometry. 207 // Returns 'true' of something eas actually removed and would need restoring
249 // Must only be called at taint time!! 208 // Called at taint-time!!
250 private void RecomputeLinksetConstraintVariables() 209 public bool RemoveBodyDependencies(BSPrim child)
251 { 210 {
252 float linksetMass = LinksetMass; 211 bool ret = false;
212
253 lock (m_linksetActivityLock) 213 lock (m_linksetActivityLock)
254 { 214 {
255 bool somethingMissing = false; 215 if (IsRoot(child))
256 foreach (BSPhysObject child in m_children)
257 { 216 {
258 BSConstraint constrain; 217 // If the one with the dependency is root, must undo all children
259 if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain)) 218 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
219 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
220 foreach (BSPhysObject bpo in m_taintChildren)
260 { 221 {
261 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", 222 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
262 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); 223 ret = true;
263 constrain.RecomputeConstraintVariables(linksetMass);
264 } 224 }
265 else 225 }
226 else
227 {
228 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
229 child.LocalID,
230 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
231 child.LocalID, child.BSBody.ptr.ToString("X"));
232 // Remove the dependency on the body of this one
233 if (m_taintChildren.Contains(child))
266 { 234 {
267 // Non-fatal error that happens when children are being added to the linkset but 235 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
268 // their constraints have not been created yet. 236 ret = true;
269 // Caused by the fact that m_children is built at run time but building constraints
270 // happens at taint time.
271 somethingMissing = true;
272 break;
273 } 237 }
274 } 238 }
239 }
240 return ret;
241 }
275 242
276 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values 243 // Routine used when rebuilding the body of the root of the linkset
277 if (!somethingMissing) 244 // This is called after RemoveAllLinksToRoot() to restore all the constraints.
245 // This is called when the root body has been changed.
246 // Called at taint-time!!
247 public void RestoreBodyDependencies(BSPrim child)
248 {
249 lock (m_linksetActivityLock)
250 {
251 if (IsRoot(child))
278 { 252 {
279 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass 253 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
280 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); 254 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
281 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity); 255 foreach (BSPhysObject bpo in m_taintChildren)
282 foreach (BSPhysObject child in m_children)
283 { 256 {
284 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity); 257 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
285 } 258 }
286 /* 259 }
287 // The root prim takes on the weight of the whole linkset 260 else
288 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(LinksetRoot.BSShape.Ptr, linksetMass); 261 {
289 BulletSimAPI.SetMassProps2(LinksetRoot.BSBody.Ptr, linksetMass, inertia); 262 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
290 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); 263 LinksetRoot.LocalID,
291 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.Ptr, centerOfMass, OMV.Quaternion.Identity); 264 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
292 BulletSimAPI.UpdateInertiaTensor2(LinksetRoot.BSBody.Ptr); 265 child.LocalID, child.BSBody.ptr.ToString("X"));
293 */ 266 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
294 } 267 }
295 } 268 }
296 return; 269 }
270
271 // ================================================================
272 // Below this point is internal magic
273
274 private float ComputeLinksetMass()
275 {
276 float mass;
277 lock (m_linksetActivityLock)
278 {
279 mass = LinksetRoot.MassRaw;
280 foreach (BSPhysObject bp in m_taintChildren)
281 {
282 mass += bp.MassRaw;
283 }
284 }
285 return mass;
286 }
287
288 private OMV.Vector3 ComputeLinksetCenterOfMass()
289 {
290 OMV.Vector3 com;
291 lock (m_linksetActivityLock)
292 {
293 com = LinksetRoot.Position * LinksetRoot.MassRaw;
294 float totalMass = LinksetRoot.MassRaw;
295
296 foreach (BSPhysObject bp in m_taintChildren)
297 {
298 com += bp.Position * bp.MassRaw;
299 totalMass += bp.MassRaw;
300 }
301 if (totalMass != 0f)
302 com /= totalMass;
303 }
304
305 return com;
306 }
307
308 private OMV.Vector3 ComputeLinksetGeometricCenter()
309 {
310 OMV.Vector3 com;
311 lock (m_linksetActivityLock)
312 {
313 com = LinksetRoot.Position;
314
315 foreach (BSPhysObject bp in m_taintChildren)
316 {
317 com += bp.Position * bp.MassRaw;
318 }
319 com /= (m_taintChildren.Count + 1);
320 }
321
322 return com;
297 } 323 }
298 324
299 // I am the root of a linkset and a new child is being added 325 // I am the root of a linkset and a new child is being added
@@ -304,12 +330,22 @@ public class BSLinkset
304 { 330 {
305 m_children.Add(child); 331 m_children.Add(child);
306 332
307 BSPhysObject rootx = LinksetRoot; // capture the root as of now 333 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
334 BulletBody rootBodyx = LinksetRoot.BSBody;
308 BSPhysObject childx = child; 335 BSPhysObject childx = child;
309 m_physicsScene.TaintedObject("AddChildToLinkset", delegate() 336 BulletBody childBodyx = child.BSBody;
337
338 DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
339 rootx.LocalID,
340 rootx.LocalID, rootBodyx.ptr.ToString("X"),
341 childx.LocalID, childBodyx.ptr.ToString("X"));
342
343 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
310 { 344 {
311 DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 345 DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
312 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 346 // build the physical binding between me and the child
347 m_taintChildren.Add(childx);
348 PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
313 }); 349 });
314 } 350 }
315 return; 351 return;
@@ -319,10 +355,10 @@ public class BSLinkset
319 // This is not being called by the child so we have to make sure the child doesn't think 355 // This is not being called by the child so we have to make sure the child doesn't think
320 // it's still connected to the linkset. 356 // it's still connected to the linkset.
321 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 357 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
322 // has to be updated also (like pointer to prim's parent). 358 // also has to be updated (like pointer to prim's parent).
323 private void RemoveChildFromOtherLinkset(BSPhysObject pchild) 359 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
324 { 360 {
325 pchild.Linkset = new BSLinkset(m_physicsScene, pchild); 361 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
326 RemoveChildFromLinkset(pchild); 362 RemoveChildFromLinkset(pchild);
327 } 363 }
328 364
@@ -332,13 +368,22 @@ public class BSLinkset
332 { 368 {
333 if (m_children.Remove(child)) 369 if (m_children.Remove(child))
334 { 370 {
335 BSPhysObject rootx = LinksetRoot; // capture the root as of now 371 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
372 BulletBody rootBodyx = LinksetRoot.BSBody;
336 BSPhysObject childx = child; 373 BSPhysObject childx = child;
337 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 374 BulletBody childBodyx = child.BSBody;
375
376 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
377 childx.LocalID,
378 rootx.LocalID, rootBodyx.ptr.ToString("X"),
379 childx.LocalID, childBodyx.ptr.ToString("X"));
380
381 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
338 { 382 {
339 DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 383 if (m_taintChildren.Contains(childx))
384 m_taintChildren.Remove(childx);
340 385
341 PhysicallyUnlinkAChildFromRoot(rootx, childx); 386 PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
342 RecomputeLinksetConstraintVariables(); 387 RecomputeLinksetConstraintVariables();
343 }); 388 });
344 389
@@ -353,7 +398,8 @@ public class BSLinkset
353 398
354 // Create a constraint between me (root of linkset) and the passed prim (the child). 399 // Create a constraint between me (root of linkset) and the passed prim (the child).
355 // Called at taint time! 400 // Called at taint time!
356 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 401 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
402 BSPhysObject childPrim, BulletBody childBody)
357 { 403 {
358 // Zero motion for children so they don't interpolate 404 // Zero motion for children so they don't interpolate
359 childPrim.ZeroMotion(); 405 childPrim.ZeroMotion();
@@ -365,18 +411,36 @@ public class BSLinkset
365 // real world coordinate of midpoint between the two objects 411 // real world coordinate of midpoint between the two objects
366 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 412 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
367 413
414 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
415 rootPrim.LocalID,
416 rootPrim.LocalID, rootBody.ptr.ToString("X"),
417 childPrim.LocalID, childBody.ptr.ToString("X"),
418 rootPrim.Position, childPrim.Position, midPoint);
419
368 // create a constraint that allows no freedom of movement between the two objects 420 // create a constraint that allows no freedom of movement between the two objects
369 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 421 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
370 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", 422
371 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); 423 // There is great subtlty in these paramters. Notice the check for a ptr of zero.
424 // We pass the BulletBody structure into the taint in order to capture the pointer
425 // of the body at the time of constraint creation. This doesn't work for the very first
426 // construction because there is no body yet. The body
427 // is constructed later at taint time. Thus we use the body address at time of the
428 // taint creation but, if it is zero, use what's in the prim at the moment.
429 // There is a possible race condition since shape can change without a taint call
430 // (like changing to a mesh that is already constructed). The fix for that would be
431 // to only change BSShape at taint time thus syncronizing these operations at
432 // the cost of efficiency and lag.
372 BS6DofConstraint constrain = new BS6DofConstraint( 433 BS6DofConstraint constrain = new BS6DofConstraint(
373 m_physicsScene.World, rootPrim.BSBody, childPrim.BSBody, 434 PhysicsScene.World,
435 rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
436 childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
374 midPoint, 437 midPoint,
375 true, 438 true,
376 true 439 true
377 ); 440 );
441
378 /* NOTE: below is an attempt to build constraint with full frame computation, etc. 442 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
379 * Using the midpoint is easier since it lets the Bullet code use the transforms 443 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
380 * of the objects. 444 * of the objects.
381 * Code left as a warning to future programmers. 445 * Code left as a warning to future programmers.
382 // ================================================================================== 446 // ==================================================================================
@@ -408,7 +472,7 @@ public class BSLinkset
408 // ================================================================================== 472 // ==================================================================================
409 */ 473 */
410 474
411 m_physicsScene.Constraints.AddConstraint(constrain); 475 PhysicsScene.Constraints.AddConstraint(constrain);
412 476
413 // zero linear and angular limits makes the objects unable to move in relation to each other 477 // zero linear and angular limits makes the objects unable to move in relation to each other
414 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 478 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -429,31 +493,79 @@ public class BSLinkset
429 } 493 }
430 494
431 // Remove linkage between myself and a particular child 495 // Remove linkage between myself and a particular child
496 // The root and child bodies are passed in because we need to remove the constraint between
497 // the bodies that were at unlink time.
432 // Called at taint time! 498 // Called at taint time!
433 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) 499 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
500 BSPhysObject childPrim, BulletBody childBody)
434 { 501 {
435 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 502 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
503 rootPrim.LocalID,
504 rootPrim.LocalID, rootBody.ptr.ToString("X"),
505 childPrim.LocalID, childBody.ptr.ToString("X"));
436 506
437 // Find the constraint for this link and get rid of it from the overall collection and from my list 507 // Find the constraint for this link and get rid of it from the overall collection and from my list
438 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody); 508 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
439 509
440 // Make the child refresh its location 510 // Make the child refresh its location
441 BulletSimAPI.PushUpdate2(childPrim.BSBody.Ptr); 511 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
442 } 512 }
443 513
444 // Remove linkage between myself and any possible children I might have 514 /*
515 // Remove linkage between myself and any possible children I might have.
445 // Called at taint time! 516 // Called at taint time!
446 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) 517 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
447 { 518 {
448 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 519 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
449 520
450 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); 521 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
522 }
523 */
524
525 // Call each of the constraints that make up this linkset and recompute the
526 // various transforms and variables. Used when objects are added or removed
527 // from a linkset to make sure the constraints know about the new mass and
528 // geometry.
529 // Must only be called at taint time!!
530 private void RecomputeLinksetConstraintVariables()
531 {
532 float linksetMass = LinksetMass;
533 foreach (BSPhysObject child in m_taintChildren)
534 {
535 BSConstraint constrain;
536 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
537 {
538 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
539 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
540 constrain.RecomputeConstraintVariables(linksetMass);
541 }
542 else
543 {
544 // Non-fatal error that happens when children are being added to the linkset but
545 // their constraints have not been created yet.
546 break;
547 }
548 }
549
550 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
551 if (m_children.Count == m_taintChildren.Count)
552 {
553 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
554 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
555 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
556 foreach (BSPhysObject child in m_taintChildren)
557 {
558 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
559 }
560 }
561 return;
451 } 562 }
452 563
564
453 // Invoke the detailed logger and output something if it's enabled. 565 // Invoke the detailed logger and output something if it's enabled.
454 private void DetailLog(string msg, params Object[] args) 566 private void DetailLog(string msg, params Object[] args)
455 { 567 {
456 m_physicsScene.PhysicsLogging.Write(msg, args); 568 PhysicsScene.PhysicsLogging.Write(msg, args);
457 } 569 }
458 570
459} 571}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 3fe71e1..d9b738b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -39,26 +39,171 @@ namespace OpenSim.Region.Physics.BulletSPlugin
39// unless the difference is significant. 39// unless the difference is significant.
40public abstract class BSPhysObject : PhysicsActor 40public abstract class BSPhysObject : PhysicsActor
41{ 41{
42 public abstract BSLinkset Linkset { get; set; } 42 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName)
43 {
44 PhysicsScene = parentScene;
45 LocalID = localID;
46 PhysObjectName = name;
47 TypeName = typeName;
43 48
44 public abstract bool Collide(uint collidingWith, BSPhysObject collidee, 49 Linkset = new BSLinkset(PhysicsScene, this);
45 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
46 public abstract void SendCollisions();
47 50
48 // Return the object mass without calculating it or side effects 51 CollisionCollection = new CollisionEventUpdate();
52 SubscribedEventsMs = 0;
53 CollidingStep = 0;
54 CollidingGroundStep = 0;
55 }
56
57 public BSScene PhysicsScene { get; protected set; }
58 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
59 public string PhysObjectName { get; protected set; }
60 public string TypeName { get; protected set; }
61
62 public BSLinkset Linkset { get; set; }
63
64 // Return the object mass without calculating it or having side effects
49 public abstract float MassRaw { get; } 65 public abstract float MassRaw { get; }
50 66
51 // Reference to the physical body (btCollisionObject) of this object 67 // Reference to the physical body (btCollisionObject) of this object
52 public abstract BulletBody BSBody { get; set; } 68 public BulletBody BSBody;
53 // Reference to the physical shape (btCollisionShape) of this object 69 // Reference to the physical shape (btCollisionShape) of this object
54 public abstract BulletShape BSShape { get; set; } 70 public BulletShape BSShape;
55 71
72 // Stop all physical motion.
56 public abstract void ZeroMotion(); 73 public abstract void ZeroMotion();
57 74
75 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
58 public virtual void StepVehicle(float timeStep) { } 76 public virtual void StepVehicle(float timeStep) { }
59 77
78 // Update the physical location and motion of the object. Called with data from Bullet.
60 public abstract void UpdateProperties(EntityProperties entprop); 79 public abstract void UpdateProperties(EntityProperties entprop);
61 80
81 // Tell the object to clean up.
62 public abstract void Destroy(); 82 public abstract void Destroy();
83
84 #region Collisions
85
86 // Requested number of milliseconds between collision events. Zero means disabled.
87 protected int SubscribedEventsMs { get; set; }
88 // Given subscription, the time that a collision may be passed up
89 protected int NextCollisionOkTime { get; set; }
90 // The simulation step that last had a collision
91 protected long CollidingStep { get; set; }
92 // The simulation step that last had a collision with the ground
93 protected long CollidingGroundStep { get; set; }
94 // The collision flags we think are set in Bullet
95 protected CollisionFlags CurrentCollisionFlags { get; set; }
96
97 // The collisions that have been collected this tick
98 protected CollisionEventUpdate CollisionCollection;
99
100 // The simulation step is telling this object about a collision.
101 // Return 'true' if a collision was processed and should be sent up.
102 // Called at taint time from within the Step() function
103 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
104 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
105 {
106 bool ret = false;
107
108 // The following lines make IsColliding() and IsCollidingGround() work
109 CollidingStep = PhysicsScene.SimulationStep;
110 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
111 {
112 CollidingGroundStep = PhysicsScene.SimulationStep;
113 }
114
115 // prims in the same linkset cannot collide with each other
116 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
117 {
118 return ret;
119 }
120
121 // if someone has subscribed for collision events....
122 if (SubscribedEvents()) {
123 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
124 // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
125 // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
126
127 ret = true;
128 }
129 return ret;
130 }
131
132 // Routine to send the collected collisions into the simulator.
133 // Also handles removal of this from the collection of objects with collisions if
134 // there are no collisions from this object. Mechanism is create one last
135 // collision event to make collision_end work.
136 // Called at taint time from within the Step() function thus no locking problems
137 // with CollisionCollection and ObjectsWithNoMoreCollisions.
138 // Return 'true' if there were some actual collisions passed up
139 public virtual bool SendCollisions()
140 {
141 bool ret = true;
142
143 // throttle the collisions to the number of milliseconds specified in the subscription
144 int nowTime = PhysicsScene.SimulationNowTime;
145 if (nowTime >= NextCollisionOkTime)
146 {
147 NextCollisionOkTime = nowTime + SubscribedEventsMs;
148
149 // We are called if we previously had collisions. If there are no collisions
150 // this time, send up one last empty event so OpenSim can sense collision end.
151 if (CollisionCollection.Count == 0)
152 {
153 // If I have no collisions this time, remove me from the list of objects with collisions.
154 ret = false;
155 }
156
157 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
158 base.SendCollisionUpdate(CollisionCollection);
159
160 // The collisionCollection structure is passed around in the simulator.
161 // Make sure we don't have a handle to that one and that a new one is used for next time.
162 CollisionCollection = new CollisionEventUpdate();
163 }
164 return ret;
165 }
166
167 // Subscribe for collision events.
168 // Parameter is the millisecond rate the caller wishes collision events to occur.
169 public override void SubscribeEvents(int ms) {
170 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
171 SubscribedEventsMs = ms;
172 if (ms > 0)
173 {
174 // make sure first collision happens
175 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
176
177 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
178 {
179 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
180 });
181 }
182 else
183 {
184 // Subscribing for zero or less is the same as unsubscribing
185 UnSubscribeEvents();
186 }
187 }
188 public override void UnSubscribeEvents() {
189 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
190 SubscribedEventsMs = 0;
191 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
192 {
193 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
194 });
195 }
196 // Return 'true' if the simulator wants collision events
197 public override bool SubscribedEvents() {
198 return (SubscribedEventsMs > 0);
199 }
200
201 #endregion // Collisions
202
203 // High performance detailed logging routine used by the physical objects.
204 protected void DetailLog(string msg, params Object[] args)
205 {
206 PhysicsScene.PhysicsLogging.Write(msg, args);
207 }
63} 208}
64} 209}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 0f027b8..20f5180 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. 36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the 37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine. 38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. 39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin
62 if (Util.IsWindows()) 62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the 64 // If not Windows, loading is performed by the
65 // Mono loader as specified in 65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". 66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67 67
68 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 26a581f..a0e627e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -24,6 +24,9 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
28// Uncomment this it enable code to do all shape an body memory management
29// in the C# code.
27using System; 30using System;
28using System.Reflection; 31using System.Reflection;
29using System.Collections.Generic; 32using System.Collections.Generic;
@@ -36,6 +39,7 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36 39
37namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
38{ 41{
42
39 [Serializable] 43 [Serializable]
40public sealed class BSPrim : BSPhysObject 44public sealed class BSPrim : BSPhysObject
41{ 45{
@@ -49,11 +53,6 @@ public sealed class BSPrim : BSPhysObject
49 private ulong _hullKey; 53 private ulong _hullKey;
50 private List<ConvexResult> _hulls; 54 private List<ConvexResult> _hulls;
51 55
52 private BSScene _scene;
53 public BSScene Scene { get { return _scene; } }
54 private String _avName;
55 private uint _localID = 0;
56
57 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. 56 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
58 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. 57 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
59 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 58 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
@@ -87,18 +86,6 @@ public sealed class BSPrim : BSPhysObject
87 private bool _kinematic; 86 private bool _kinematic;
88 private float _buoyancy; 87 private float _buoyancy;
89 88
90 // Membership in a linkset is controlled by this class.
91 public override BSLinkset Linkset { get; set; }
92
93 private int _subscribedEventsMs = 0;
94 private int _nextCollisionOkTime = 0;
95 long _collidingStep;
96 long _collidingGroundStep;
97 CollisionFlags m_currentCollisionFlags = 0;
98
99 public override BulletBody BSBody { get; set; }
100 public override BulletShape BSShape { get; set; }
101
102 private BSDynamics _vehicle; 89 private BSDynamics _vehicle;
103 90
104 private OMV.Vector3 _PIDTarget; 91 private OMV.Vector3 _PIDTarget;
@@ -113,10 +100,8 @@ public sealed class BSPrim : BSPhysObject
113 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 100 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
114 { 101 {
115 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 102 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
116 _localID = localID; 103 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
117 _avName = primName;
118 _physicsActorType = (int)ActorTypes.Prim; 104 _physicsActorType = (int)ActorTypes.Prim;
119 _scene = parent_scene;
120 _position = pos; 105 _position = pos;
121 _size = size; 106 _size = size;
122 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 107 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
@@ -129,25 +114,23 @@ public sealed class BSPrim : BSPhysObject
129 _pbs = pbs; 114 _pbs = pbs;
130 _isPhysical = pisPhysical; 115 _isPhysical = pisPhysical;
131 _isVolumeDetect = false; 116 _isVolumeDetect = false;
132 _subscribedEventsMs = 0; 117 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
133 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 118 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
134 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 119 _restitution = PhysicsScene.Params.defaultRestitution;
135 _restitution = _scene.Params.defaultRestitution; 120 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
136 Linkset = new BSLinkset(Scene, this); // a linkset of one
137 _vehicle = new BSDynamics(Scene, this); // add vehicleness
138 _mass = CalculateMass(); 121 _mass = CalculateMass();
122
123 // No body or shape yet
124 BSBody = new BulletBody(LocalID, IntPtr.Zero);
125 BSShape = new BulletShape(IntPtr.Zero);
126
139 DetailLog("{0},BSPrim.constructor,call", LocalID); 127 DetailLog("{0},BSPrim.constructor,call", LocalID);
140 // do the actual object creation at taint time 128 // do the actual object creation at taint time
141 _scene.TaintedObject("BSPrim.create", delegate() 129 PhysicsScene.TaintedObject("BSPrim.create", delegate()
142 { 130 {
143 CreateGeomAndObject(true); 131 CreateGeomAndObject(true);
144 132
145 // Get the pointer to the physical body for this object. 133 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr);
146 // At the moment, we're still letting BulletSim manage the creation and destruction
147 // of the object. Someday we'll move that into the C# code.
148 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
149 BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
150 m_currentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.Ptr);
151 }); 134 });
152 } 135 }
153 136
@@ -168,57 +151,62 @@ public sealed class BSPrim : BSPhysObject
168 // Undo any vehicle properties 151 // Undo any vehicle properties
169 this.VehicleType = (int)Vehicle.TYPE_NONE; 152 this.VehicleType = (int)Vehicle.TYPE_NONE;
170 153
171 _scene.TaintedObject("BSPrim.destroy", delegate() 154 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
172 { 155 {
173 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 156 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
174 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 157 // If there are physical body and shape, release my use of same.
175 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 158 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
159 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
176 }); 160 });
177 } 161 }
178 162
179 public override bool Stopped { 163 public override bool Stopped {
180 get { return _stopped; } 164 get { return _stopped; }
181 } 165 }
182 public override OMV.Vector3 Size { 166 public override OMV.Vector3 Size {
183 get { return _size; } 167 get { return _size; }
184 set { 168 set {
185 _size = value; 169 _size = value;
186 _scene.TaintedObject("BSPrim.setSize", delegate() 170 PhysicsScene.TaintedObject("BSPrim.setSize", delegate()
187 { 171 {
188 _mass = CalculateMass(); // changing size changes the mass 172 _mass = CalculateMass(); // changing size changes the mass
189 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct 173 // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct
190 // scale and margins are set. 174 // scale and margins are set.
191 CreateGeomAndObject(true); 175 CreateGeomAndObject(true);
192 DetailLog("{0}: BSPrim.setSize: size={1}, scale={2}, mass={3}, physical={4}", LocalID, _size, _scale, _mass, IsPhysical); 176 // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical);
193 }); 177 });
194 } 178 }
195 } 179 }
196 public override PrimitiveBaseShape Shape { 180 // Scale is what we set in the physics engine. It is different than 'size' in that
181 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
182 public OMV.Vector3 Scale
183 {
184 get { return _scale; }
185 set { _scale = value; }
186 }
187 public override PrimitiveBaseShape Shape {
197 set { 188 set {
198 _pbs = value; 189 _pbs = value;
199 _scene.TaintedObject("BSPrim.setShape", delegate() 190 PhysicsScene.TaintedObject("BSPrim.setShape", delegate()
200 { 191 {
201 _mass = CalculateMass(); // changing the shape changes the mass 192 _mass = CalculateMass(); // changing the shape changes the mass
202 CreateGeomAndObject(false); 193 CreateGeomAndObject(true);
203 }); 194 });
204 } 195 }
205 }
206 public override uint LocalID {
207 set { _localID = value; }
208 get { return _localID; }
209 } 196 }
210 public override bool Grabbed { 197 public override bool Grabbed {
211 set { _grabbed = value; 198 set { _grabbed = value;
212 } 199 }
213 } 200 }
214 public override bool Selected { 201 public override bool Selected {
215 set { 202 set {
216 _isSelected = value; 203 _isSelected = value;
217 _scene.TaintedObject("BSPrim.setSelected", delegate() 204 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
218 { 205 {
219 SetObjectDynamic(); 206 // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
207 SetObjectDynamic(false);
220 }); 208 });
221 } 209 }
222 } 210 }
223 public override void CrossingFailure() { return; } 211 public override void CrossingFailure() { return; }
224 212
@@ -232,10 +220,10 @@ public sealed class BSPrim : BSPhysObject
232 220
233 Linkset = parent.Linkset.AddMeToLinkset(this); 221 Linkset = parent.Linkset.AddMeToLinkset(this);
234 222
235 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 223 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
236 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 224 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
237 } 225 }
238 return; 226 return;
239 } 227 }
240 228
241 // delink me from my linkset 229 // delink me from my linkset
@@ -245,12 +233,12 @@ public sealed class BSPrim : BSPhysObject
245 233
246 BSPhysObject parentBefore = Linkset.LinksetRoot; 234 BSPhysObject parentBefore = Linkset.LinksetRoot;
247 int childrenBefore = Linkset.NumberOfChildren; 235 int childrenBefore = Linkset.NumberOfChildren;
248 236
249 Linkset = Linkset.RemoveMeFromLinkset(this); 237 Linkset = Linkset.RemoveMeFromLinkset(this);
250 238
251 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 239 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
252 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); 240 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
253 return; 241 return;
254 } 242 }
255 243
256 // Set motion values to zero. 244 // Set motion values to zero.
@@ -264,43 +252,40 @@ public sealed class BSPrim : BSPhysObject
264 _rotationalVelocity = OMV.Vector3.Zero; 252 _rotationalVelocity = OMV.Vector3.Zero;
265 253
266 // Zero some other properties directly into the physics engine 254 // Zero some other properties directly into the physics engine
267 BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero); 255 BulletSimAPI.ClearForces2(BSBody.ptr);
268 BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
269 BulletSimAPI.SetInterpolationVelocity2(BSBody.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
270 BulletSimAPI.ClearForces2(BSBody.Ptr);
271 } 256 }
272 257
273 public override void LockAngularMotion(OMV.Vector3 axis) 258 public override void LockAngularMotion(OMV.Vector3 axis)
274 { 259 {
275 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 260 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
276 return; 261 return;
277 } 262 }
278 263
279 public override OMV.Vector3 Position { 264 public override OMV.Vector3 Position {
280 get { 265 get {
281 if (!Linkset.IsRoot(this)) 266 if (!Linkset.IsRoot(this))
282 // child prims move around based on their parent. Need to get the latest location 267 // child prims move around based on their parent. Need to get the latest location
283 _position = BulletSimAPI.GetPosition2(BSBody.Ptr); 268 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
284 269
285 // don't do the GetObjectPosition for root elements because this function is called a zillion times 270 // don't do the GetObjectPosition for root elements because this function is called a zillion times
286 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 271 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
287 return _position; 272 return _position;
288 } 273 }
289 set { 274 set {
290 _position = value; 275 _position = value;
291 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 276 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
292 _scene.TaintedObject("BSPrim.setPosition", delegate() 277 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
293 { 278 {
294 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 279 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
295 BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation); 280 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
296 }); 281 });
297 } 282 }
298 } 283 }
299 284
300 // Return the effective mass of the object. 285 // Return the effective mass of the object.
301 // If there are multiple items in the linkset, add them together for the root 286 // If there are multiple items in the linkset, add them together for the root
302 public override float Mass 287 public override float Mass
303 { 288 {
304 get 289 get
305 { 290 {
306 // return Linkset.LinksetMass; 291 // return Linkset.LinksetMass;
@@ -323,59 +308,59 @@ public sealed class BSPrim : BSPhysObject
323 get { return Linkset.GeometricCenter; } 308 get { return Linkset.GeometricCenter; }
324 } 309 }
325 310
326 public override OMV.Vector3 Force { 311 public override OMV.Vector3 Force {
327 get { return _force; } 312 get { return _force; }
328 set { 313 set {
329 _force = value; 314 _force = value;
330 _scene.TaintedObject("BSPrim.setForce", delegate() 315 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
331 { 316 {
332 DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 317 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
333 BulletSimAPI.SetObjectForce2(BSBody.Ptr, _force); 318 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
334 }); 319 });
335 } 320 }
336 } 321 }
337 322
338 public override int VehicleType { 323 public override int VehicleType {
339 get { 324 get {
340 return (int)_vehicle.Type; // if we are a vehicle, return that type 325 return (int)_vehicle.Type; // if we are a vehicle, return that type
341 } 326 }
342 set { 327 set {
343 Vehicle type = (Vehicle)value; 328 Vehicle type = (Vehicle)value;
344 BSPrim vehiclePrim = this; 329 BSPrim vehiclePrim = this;
345 _scene.TaintedObject("setVehicleType", delegate() 330 PhysicsScene.TaintedObject("setVehicleType", delegate()
346 { 331 {
347 // Done at taint time so we're sure the physics engine is not using the variables 332 // Done at taint time so we're sure the physics engine is not using the variables
348 // Vehicle code changes the parameters for this vehicle type. 333 // Vehicle code changes the parameters for this vehicle type.
349 _vehicle.ProcessTypeChange(type); 334 _vehicle.ProcessTypeChange(type);
350 // Tell the scene about the vehicle so it will get processing each frame. 335 // Tell the scene about the vehicle so it will get processing each frame.
351 _scene.VehicleInSceneTypeChanged(this, type); 336 PhysicsScene.VehicleInSceneTypeChanged(this, type);
352 }); 337 });
353 } 338 }
354 } 339 }
355 public override void VehicleFloatParam(int param, float value) 340 public override void VehicleFloatParam(int param, float value)
356 { 341 {
357 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 342 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
358 { 343 {
359 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 344 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
360 }); 345 });
361 } 346 }
362 public override void VehicleVectorParam(int param, OMV.Vector3 value) 347 public override void VehicleVectorParam(int param, OMV.Vector3 value)
363 { 348 {
364 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 349 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
365 { 350 {
366 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 351 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
367 }); 352 });
368 } 353 }
369 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 354 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
370 { 355 {
371 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 356 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
372 { 357 {
373 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 358 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
374 }); 359 });
375 } 360 }
376 public override void VehicleFlags(int param, bool remove) 361 public override void VehicleFlags(int param, bool remove)
377 { 362 {
378 _scene.TaintedObject("BSPrim.VehicleFlags", delegate() 363 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
379 { 364 {
380 _vehicle.ProcessVehicleFlags(param, remove); 365 _vehicle.ProcessVehicleFlags(param, remove);
381 }); 366 });
@@ -392,73 +377,81 @@ public sealed class BSPrim : BSPhysObject
392 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 377 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
393 public override void SetVolumeDetect(int param) { 378 public override void SetVolumeDetect(int param) {
394 bool newValue = (param != 0); 379 bool newValue = (param != 0);
395 _isVolumeDetect = newValue; 380 if (_isVolumeDetect != newValue)
396 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
397 { 381 {
398 SetObjectDynamic(); 382 _isVolumeDetect = newValue;
399 }); 383 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
400 return; 384 {
385 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
386 SetObjectDynamic(true);
387 });
388 }
389 return;
401 } 390 }
402 391
403 public override OMV.Vector3 Velocity { 392 public override OMV.Vector3 Velocity {
404 get { return _velocity; } 393 get { return _velocity; }
405 set { 394 set {
406 _velocity = value; 395 _velocity = value;
407 _scene.TaintedObject("BSPrim.setVelocity", delegate() 396 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
408 { 397 {
409 DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 398 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
410 BulletSimAPI.SetLinearVelocity2(BSBody.Ptr, _velocity); 399 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
411 }); 400 });
412 } 401 }
413 } 402 }
414 public override OMV.Vector3 Torque { 403 public override OMV.Vector3 Torque {
415 get { return _torque; } 404 get { return _torque; }
416 set { _torque = value; 405 set { _torque = value;
417 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 406 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
418 } 407 }
419 } 408 }
420 public override float CollisionScore { 409 public override float CollisionScore {
421 get { return _collisionScore; } 410 get { return _collisionScore; }
422 set { _collisionScore = value; 411 set { _collisionScore = value;
423 } 412 }
424 } 413 }
425 public override OMV.Vector3 Acceleration { 414 public override OMV.Vector3 Acceleration {
426 get { return _acceleration; } 415 get { return _acceleration; }
427 set { _acceleration = value; } 416 set { _acceleration = value; }
428 } 417 }
429 public override OMV.Quaternion Orientation { 418 public override OMV.Quaternion Orientation {
430 get { 419 get {
431 if (!Linkset.IsRoot(this)) 420 if (!Linkset.IsRoot(this))
432 { 421 {
433 // Children move around because tied to parent. Get a fresh value. 422 // Children move around because tied to parent. Get a fresh value.
434 _orientation = BulletSimAPI.GetOrientation2(BSBody.Ptr); 423 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
435 } 424 }
436 return _orientation; 425 return _orientation;
437 } 426 }
438 set { 427 set {
439 _orientation = value; 428 _orientation = value;
440 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 429 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
441 _scene.TaintedObject("BSPrim.setOrientation", delegate() 430 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
442 { 431 {
443 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 432 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
444 DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 433 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
445 BulletSimAPI.SetTranslation2(BSBody.Ptr, _position, _orientation); 434 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
446 }); 435 });
447 } 436 }
448 } 437 }
449 public override int PhysicsActorType { 438 public override int PhysicsActorType {
450 get { return _physicsActorType; } 439 get { return _physicsActorType; }
451 set { _physicsActorType = value; } 440 set { _physicsActorType = value; }
452 } 441 }
453 public override bool IsPhysical { 442 public override bool IsPhysical {
454 get { return _isPhysical; } 443 get { return _isPhysical; }
455 set { 444 set {
456 _isPhysical = value; 445 if (_isPhysical != value)
457 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
458 { 446 {
459 SetObjectDynamic(); 447 _isPhysical = value;
460 }); 448 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
461 } 449 {
450 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
451 SetObjectDynamic(true);
452 });
453 }
454 }
462 } 455 }
463 456
464 // An object is static (does not move) if selected or not physical 457 // An object is static (does not move) if selected or not physical
@@ -468,53 +461,64 @@ public sealed class BSPrim : BSPhysObject
468 } 461 }
469 462
470 // An object is solid if it's not phantom and if it's not doing VolumeDetect 463 // An object is solid if it's not phantom and if it's not doing VolumeDetect
471 private bool IsSolid 464 public bool IsSolid
472 { 465 {
473 get { return !IsPhantom && !_isVolumeDetect; } 466 get { return !IsPhantom && !_isVolumeDetect; }
474 } 467 }
475 468
476 // Make gravity work if the object is physical and not selected 469 // Make gravity work if the object is physical and not selected
477 // No locking here because only called when it is safe 470 // Called at taint-time!!
471 private void SetObjectDynamic(bool forceRebuild)
472 {
473 // Recreate the physical object if necessary
474 CreateGeomAndObject(forceRebuild);
475 }
476
477 // Convert the simulator's physical properties into settings on BulletSim objects.
478 // There are four flags we're interested in: 478 // There are four flags we're interested in:
479 // IsStatic: Object does not move, otherwise the object has mass and moves 479 // IsStatic: Object does not move, otherwise the object has mass and moves
480 // isSolid: other objects bounce off of this object 480 // isSolid: other objects bounce off of this object
481 // isVolumeDetect: other objects pass through but can generate collisions 481 // isVolumeDetect: other objects pass through but can generate collisions
482 // collisionEvents: whether this object returns collision events 482 // collisionEvents: whether this object returns collision events
483 private void SetObjectDynamic()
484 {
485 // If it's becoming dynamic, it will need hullness
486 VerifyCorrectPhysicalShape();
487 UpdatePhysicalParameters();
488 }
489
490 private void UpdatePhysicalParameters() 483 private void UpdatePhysicalParameters()
491 { 484 {
492 /* 485 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
493 // Bullet wants static objects to have a mass of zero 486
494 float mass = IsStatic ? 0f : _mass; 487 // Mangling all the physical properties requires the object not be in the physical world.
488 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
489 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
495 490
496 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
497 */
498 BulletSimAPI.RemoveObjectFromWorld2(Scene.World.Ptr, BSBody.Ptr);
499 491
500 // Set up the object physicalness (does gravity and collisions move this object) 492 // Set up the object physicalness (does gravity and collisions move this object)
501 MakeDynamic(IsStatic); 493 MakeDynamic(IsStatic);
502 494
503 // Make solid or not (do things bounce off or pass through this object) 495 // Do any vehicle stuff
504 MakeSolid(IsSolid); 496 _vehicle.Refresh();
505 497
506 // Arrange for collisions events if the simulator wants them 498 // Arrange for collision events if the simulator wants them
507 EnableCollisions(SubscribedEvents()); 499 EnableCollisions(SubscribedEvents());
508 500
509 BulletSimAPI.AddObjectToWorld2(Scene.World.Ptr, BSBody.Ptr); 501 // Make solid or not (do things bounce off or pass through this object).
502 MakeSolid(IsSolid);
503
504 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
505
506 // Rebuild its shape
507 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
508
509 // Collision filter can be set only when the object is in the world
510 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
511 {
512 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
513 }
510 514
511 // Recompute any linkset parameters. 515 // Recompute any linkset parameters.
512 // When going from non-physical to physical, this re-enables the constraints that 516 // When going from non-physical to physical, this re-enables the constraints that
513 // had been automatically disabled when the mass was set to zero. 517 // had been automatically disabled when the mass was set to zero.
514 Linkset.Refresh(this); 518 Linkset.Refresh(this);
515 519
516 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,static={1},solid={2},mass={3}, cf={4}", 520 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
517 LocalID, IsStatic, IsSolid, _mass, m_currentCollisionFlags); 521 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
518 } 522 }
519 523
520 // "Making dynamic" means changing to and from static. 524 // "Making dynamic" means changing to and from static.
@@ -527,65 +531,86 @@ public sealed class BSPrim : BSPhysObject
527 if (makeStatic) 531 if (makeStatic)
528 { 532 {
529 // Become a Bullet 'static' object type 533 // Become a Bullet 'static' object type
530 m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); 534 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
531 // Stop all movement 535 // Stop all movement
532 BulletSimAPI.ClearAllForces2(BSBody.Ptr); 536 BulletSimAPI.ClearAllForces2(BSBody.ptr);
533 // Center of mass is at the center of the object 537 // Center of mass is at the center of the object
534 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.Ptr, _position, _orientation); 538 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
535 // Mass is zero which disables a bunch of physics stuff in Bullet 539 // Mass is zero which disables a bunch of physics stuff in Bullet
536 BulletSimAPI.SetMassProps2(BSBody.Ptr, 0f, OMV.Vector3.Zero); 540 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
537 // There is no inertia in a static object 541 // There is no inertia in a static object
538 BulletSimAPI.UpdateInertiaTensor2(BSBody.Ptr); 542 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
539 // There can be special things needed for implementing linksets 543 // There can be special things needed for implementing linksets
540 Linkset.MakeStatic(this); 544 Linkset.MakeStatic(this);
541 // The activation state is 'sleeping' so Bullet will not try to act on it 545 // The activation state is 'disabled' so Bullet will not try to act on it
542 BulletSimAPI.ForceActivationState2(BSBody.Ptr, ActivationState.ISLAND_SLEEPING); 546 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
547
548 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
549 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
543 } 550 }
544 else 551 else
545 { 552 {
546 // Not a Bullet static object 553 // Not a Bullet static object
547 m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); 554 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
555
556 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
557 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
558 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
548 559
549 // Set various physical properties so internal things will get computed correctly as they are set
550 BulletSimAPI.SetFriction2(BSBody.Ptr, Scene.Params.defaultFriction);
551 BulletSimAPI.SetRestitution2(BSBody.Ptr, Scene.Params.defaultRestitution);
552 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 560 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
553 BulletSimAPI.SetInterpolationLinearVelocity2(BSBody.Ptr, OMV.Vector3.Zero); 561 BulletSimAPI.ClearAllForces2(BSBody.ptr);
554 BulletSimAPI.SetInterpolationAngularVelocity2(BSBody.Ptr, OMV.Vector3.Zero);
555 BulletSimAPI.SetInterpolationVelocity2(BSBody.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
556 562
557 // A dynamic object has mass 563 // A dynamic object has mass
558 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.Ptr); 564 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
559 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Linkset.LinksetMass); 565 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
560 BulletSimAPI.SetMassProps2(BSBody.Ptr, _mass, inertia); 566 // OMV.Vector3 inertia = OMV.Vector3.Zero;
561 // Inertia is based on our new mass 567 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
562 BulletSimAPI.UpdateInertiaTensor2(BSBody.Ptr); 568 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
563 569
564 // Various values for simulation limits 570 // Various values for simulation limits
565 BulletSimAPI.SetDamping2(BSBody.Ptr, Scene.Params.linearDamping, Scene.Params.angularDamping); 571 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
566 BulletSimAPI.SetDeactivationTime2(BSBody.Ptr, Scene.Params.deactivationTime); 572 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
567 BulletSimAPI.SetSleepingThresholds2(BSBody.Ptr, Scene.Params.linearSleepingThreshold, Scene.Params.angularSleepingThreshold); 573 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
568 BulletSimAPI.SetContactProcessingThreshold2(BSBody.Ptr, Scene.Params.contactProcessingThreshold); 574 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
569 575
570 // There can be special things needed for implementing linksets 576 // There can be special things needed for implementing linksets.
571 Linkset.MakeDynamic(this); 577 Linkset.MakeDynamic(this);
572 578
573 // Force activation of the object so Bullet will act on it. 579 // Force activation of the object so Bullet will act on it.
574 BulletSimAPI.Activate2(BSBody.Ptr, true); 580 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
581 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
582 BulletSimAPI.Activate2(BSBody.ptr, true);
583
584 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
585 BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
575 } 586 }
576 } 587 }
577 588
578 // "Making solid" means that other object will not pass through this object. 589 // "Making solid" means that other object will not pass through this object.
590 // To make transparent, we create a Bullet ghost object.
591 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
592 // the functions after this one set up the state of a possibly newly created collision body.
579 private void MakeSolid(bool makeSolid) 593 private void MakeSolid(bool makeSolid)
580 { 594 {
595 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
581 if (makeSolid) 596 if (makeSolid)
582 { 597 {
583 // Easy in Bullet -- just remove the object flag that controls collision response 598 // Verify the previous code created the correct shape for this type of thing.
584 m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 599 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
600 {
601 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
602 }
603 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
585 } 604 }
586 else 605 else
587 { 606 {
588 m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 607 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
608 {
609 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
610 }
611 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
612 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
613 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
589 } 614 }
590 } 615 }
591 616
@@ -594,40 +619,40 @@ public sealed class BSPrim : BSPhysObject
594 { 619 {
595 if (wantsCollisionEvents) 620 if (wantsCollisionEvents)
596 { 621 {
597 m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 622 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
598 } 623 }
599 else 624 else
600 { 625 {
601 m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 626 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
602 } 627 }
603 } 628 }
604 629
605 // prims don't fly 630 // prims don't fly
606 public override bool Flying { 631 public override bool Flying {
607 get { return _flying; } 632 get { return _flying; }
608 set { 633 set {
609 _flying = value; 634 _flying = value;
610 } 635 }
611 } 636 }
612 public override bool SetAlwaysRun { 637 public override bool SetAlwaysRun {
613 get { return _setAlwaysRun; } 638 get { return _setAlwaysRun; }
614 set { _setAlwaysRun = value; } 639 set { _setAlwaysRun = value; }
615 } 640 }
616 public override bool ThrottleUpdates { 641 public override bool ThrottleUpdates {
617 get { return _throttleUpdates; } 642 get { return _throttleUpdates; }
618 set { _throttleUpdates = value; } 643 set { _throttleUpdates = value; }
619 } 644 }
620 public override bool IsColliding { 645 public override bool IsColliding {
621 get { return (_collidingStep == _scene.SimulationStep); } 646 get { return (CollidingStep == PhysicsScene.SimulationStep); }
622 set { _isColliding = value; } 647 set { _isColliding = value; }
623 } 648 }
624 public override bool CollidingGround { 649 public override bool CollidingGround {
625 get { return (_collidingGroundStep == _scene.SimulationStep); } 650 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
626 set { _collidingGround = value; } 651 set { _collidingGround = value; }
627 } 652 }
628 public override bool CollidingObj { 653 public override bool CollidingObj {
629 get { return _collidingObj; } 654 get { return _collidingObj; }
630 set { _collidingObj = value; } 655 set { _collidingObj = value; }
631 } 656 }
632 public bool IsPhantom { 657 public bool IsPhantom {
633 get { 658 get {
@@ -637,10 +662,10 @@ public sealed class BSPrim : BSPhysObject
637 return false; 662 return false;
638 } 663 }
639 } 664 }
640 public override bool FloatOnWater { 665 public override bool FloatOnWater {
641 set { _floatOnWater = value; } 666 set { _floatOnWater = value; }
642 } 667 }
643 public override OMV.Vector3 RotationalVelocity { 668 public override OMV.Vector3 RotationalVelocity {
644 get { 669 get {
645 /* 670 /*
646 OMV.Vector3 pv = OMV.Vector3.Zero; 671 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -652,61 +677,60 @@ public sealed class BSPrim : BSPhysObject
652 */ 677 */
653 678
654 return _rotationalVelocity; 679 return _rotationalVelocity;
655 } 680 }
656 set { 681 set {
657 _rotationalVelocity = value; 682 _rotationalVelocity = value;
658 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 683 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
659 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 684 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
660 { 685 {
661 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 686 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
662 BulletSimAPI.SetAngularVelocity2(BSBody.Ptr, _rotationalVelocity); 687 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
663 }); 688 });
664 } 689 }
665 } 690 }
666 public override bool Kinematic { 691 public override bool Kinematic {
667 get { return _kinematic; } 692 get { return _kinematic; }
668 set { _kinematic = value; 693 set { _kinematic = value;
669 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 694 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
670 } 695 }
671 } 696 }
672 public override float Buoyancy { 697 public override float Buoyancy {
673 get { return _buoyancy; } 698 get { return _buoyancy; }
674 set { 699 set {
675 _buoyancy = value; 700 _buoyancy = value;
676 _scene.TaintedObject("BSPrim.setBuoyancy", delegate() 701 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
677 { 702 {
678 DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 703 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
679 // Buoyancy is faked by changing the gravity applied to the object 704 // Buoyancy is faked by changing the gravity applied to the object
680 float grav = Scene.Params.gravity * (1f - _buoyancy); 705 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
681 BulletSimAPI.SetGravity2(BSBody.Ptr, new OMV.Vector3(0f, 0f, grav)); 706 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
682 // BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
683 }); 707 });
684 } 708 }
685 } 709 }
686 710
687 // Used for MoveTo 711 // Used for MoveTo
688 public override OMV.Vector3 PIDTarget { 712 public override OMV.Vector3 PIDTarget {
689 set { _PIDTarget = value; } 713 set { _PIDTarget = value; }
690 } 714 }
691 public override bool PIDActive { 715 public override bool PIDActive {
692 set { _usePID = value; } 716 set { _usePID = value; }
693 } 717 }
694 public override float PIDTau { 718 public override float PIDTau {
695 set { _PIDTau = value; } 719 set { _PIDTau = value; }
696 } 720 }
697 721
698 // Used for llSetHoverHeight and maybe vehicle height 722 // Used for llSetHoverHeight and maybe vehicle height
699 // Hover Height will override MoveTo target's Z 723 // Hover Height will override MoveTo target's Z
700 public override bool PIDHoverActive { 724 public override bool PIDHoverActive {
701 set { _useHoverPID = value; } 725 set { _useHoverPID = value; }
702 } 726 }
703 public override float PIDHoverHeight { 727 public override float PIDHoverHeight {
704 set { _PIDHoverHeight = value; } 728 set { _PIDHoverHeight = value; }
705 } 729 }
706 public override PIDHoverType PIDHoverType { 730 public override PIDHoverType PIDHoverType {
707 set { _PIDHoverType = value; } 731 set { _PIDHoverType = value; }
708 } 732 }
709 public override float PIDHoverTau { 733 public override float PIDHoverTau {
710 set { _PIDHoverTao = value; } 734 set { _PIDHoverTao = value; }
711 } 735 }
712 736
@@ -730,7 +754,7 @@ public sealed class BSPrim : BSPhysObject
730 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 754 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
731 return; 755 return;
732 } 756 }
733 _scene.TaintedObject("BSPrim.AddForce", delegate() 757 PhysicsScene.TaintedObject("BSPrim.AddForce", delegate()
734 { 758 {
735 OMV.Vector3 fSum = OMV.Vector3.Zero; 759 OMV.Vector3 fSum = OMV.Vector3.Zero;
736 lock (m_accumulatedForces) 760 lock (m_accumulatedForces)
@@ -741,43 +765,19 @@ public sealed class BSPrim : BSPhysObject
741 } 765 }
742 m_accumulatedForces.Clear(); 766 m_accumulatedForces.Clear();
743 } 767 }
744 DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); 768 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
745 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. 769 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
746 BulletSimAPI.ApplyCentralForce2(BSBody.Ptr, fSum); 770 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
747 }); 771 });
748 } 772 }
749 773
750 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 774 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
751 DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 775 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
752 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 776 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
753 } 777 }
754 public override void SetMomentum(OMV.Vector3 momentum) { 778 public override void SetMomentum(OMV.Vector3 momentum) {
755 DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 779 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
756 } 780 }
757 public override void SubscribeEvents(int ms) {
758 _subscribedEventsMs = ms;
759 if (ms > 0)
760 {
761 // make sure first collision happens
762 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
763
764 Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
765 {
766 m_currentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
767 });
768 }
769 }
770 public override void UnSubscribeEvents() {
771 _subscribedEventsMs = 0;
772 Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
773 {
774 m_currentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
775 });
776 }
777 public override bool SubscribedEvents() {
778 return (_subscribedEventsMs > 0);
779 }
780
781 #region Mass Calculation 781 #region Mass Calculation
782 782
783 private float CalculateMass() 783 private float CalculateMass()
@@ -787,8 +787,8 @@ public sealed class BSPrim : BSPhysObject
787 787
788 float returnMass = 0; 788 float returnMass = 0;
789 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 789 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
790 float hollowVolume = hollowAmount * hollowAmount; 790 float hollowVolume = hollowAmount * hollowAmount;
791 791
792 switch (_pbs.ProfileShape) 792 switch (_pbs.ProfileShape)
793 { 793 {
794 case ProfileShape.Square: 794 case ProfileShape.Square:
@@ -824,16 +824,16 @@ public sealed class BSPrim : BSPhysObject
824 824
825 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 825 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
826 { 826 {
827 //a tube 827 //a tube
828 828
829 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 829 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
830 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 830 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
831 volume -= volume*tmp*tmp; 831 volume -= volume*tmp*tmp;
832 832
833 if (hollowAmount > 0.0) 833 if (hollowAmount > 0.0)
834 { 834 {
835 hollowVolume *= hollowAmount; 835 hollowVolume *= hollowAmount;
836 836
837 switch (_pbs.HollowShape) 837 switch (_pbs.HollowShape)
838 { 838 {
839 case HollowShape.Square: 839 case HollowShape.Square:
@@ -892,7 +892,7 @@ public sealed class BSPrim : BSPhysObject
892 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 892 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
893 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 893 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
894 volume *= (1.0f - tmp * tmp); 894 volume *= (1.0f - tmp * tmp);
895 895
896 if (hollowAmount > 0.0) 896 if (hollowAmount > 0.0)
897 { 897 {
898 898
@@ -1071,302 +1071,17 @@ public sealed class BSPrim : BSPhysObject
1071 if (returnMass <= 0) 1071 if (returnMass <= 0)
1072 returnMass = 0.0001f; 1072 returnMass = 0.0001f;
1073 1073
1074 if (returnMass > _scene.MaximumObjectMass) 1074 if (returnMass > PhysicsScene.MaximumObjectMass)
1075 returnMass = _scene.MaximumObjectMass; 1075 returnMass = PhysicsScene.MaximumObjectMass;
1076 1076
1077 return returnMass; 1077 return returnMass;
1078 }// end CalculateMass 1078 }// end CalculateMass
1079 #endregion Mass Calculation 1079 #endregion Mass Calculation
1080 1080
1081 // Create the geometry information in Bullet for later use.
1082 // The objects needs a hull if it's physical otherwise a mesh is enough.
1083 // No locking here because this is done when we know physics is not simulating.
1084 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
1085 // Returns 'true' if the geometry was rebuilt.
1086 // Called at taint-time!
1087 private bool CreateGeom(bool forceRebuild)
1088 {
1089 bool ret = false;
1090 bool haveShape = false;
1091
1092 // If the prim attributes are simple, this could be a simple Bullet native shape
1093 if ((_pbs.SculptEntry && !Scene.ShouldMeshSculptedPrim)
1094 || (_pbs.ProfileBegin == 0 && _pbs.ProfileEnd == 0
1095 && _pbs.ProfileHollow == 0
1096 && _pbs.PathTwist == 0 && _pbs.PathTwistBegin == 0
1097 && _pbs.PathBegin == 0 && _pbs.PathEnd == 0
1098 && _pbs.PathTaperX == 0 && _pbs.PathTaperY == 0
1099 && _pbs.PathScaleX == 100 && _pbs.PathScaleY == 100
1100 && _pbs.PathShearX == 0 && _pbs.PathShearY == 0) )
1101 {
1102 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
1103 {
1104 haveShape = true;
1105 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
1106 {
1107 DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
1108 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
1109 // Bullet native objects are scaled by the Bullet engine so pass the size in
1110 _scale = _size;
1111 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1112 ret = true;
1113 }
1114 }
1115 else
1116 {
1117 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
1118 haveShape = true;
1119 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
1120 {
1121 DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
1122 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
1123 _scale = _size;
1124 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1125 ret = true;
1126 }
1127 }
1128 }
1129 // If a simple shape isn't happening, create a mesh and possibly a hull
1130 if (!haveShape)
1131 {
1132 if (IsPhysical)
1133 {
1134 if (forceRebuild || _hullKey == 0)
1135 {
1136 // physical objects require a hull for interaction.
1137 // This also creates the mesh if it doesn't already exist
1138 ret = CreateGeomHull();
1139 }
1140 }
1141 else
1142 {
1143 if (forceRebuild || _meshKey == 0)
1144 {
1145 // Static (non-physical) objects only need a mesh for bumping into
1146 ret = CreateGeomMesh();
1147 }
1148 }
1149 }
1150 return ret;
1151 }
1152
1153 // No locking here because this is done when we know physics is not simulating
1154 // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs).
1155 // Called at taint-time!
1156 private bool CreateGeomMesh()
1157 {
1158 // level of detail based on size and type of the object
1159 float lod = _scene.MeshLOD;
1160 if (_pbs.SculptEntry)
1161 lod = _scene.SculptLOD;
1162 float maxAxis = Math.Max(_size.X, Math.Max(_size.Y, _size.Z));
1163 if (maxAxis > _scene.MeshMegaPrimThreshold)
1164 lod = _scene.MeshMegaPrimLOD;
1165
1166 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
1167 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
1168
1169 // if this new shape is the same as last time, don't recreate the mesh
1170 if (_meshKey == newMeshKey) return false;
1171
1172 DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey);
1173 // Since we're recreating new, get rid of any previously generated shape
1174 if (_meshKey != 0)
1175 {
1176 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1177 DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
1178 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1179 _mesh = null;
1180 _meshKey = 0;
1181 }
1182
1183 _meshKey = newMeshKey;
1184 // always pass false for physicalness as this creates some sort of bounding box which we don't need
1185 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
1186
1187 int[] indices = _mesh.getIndexListAsInt();
1188 List<OMV.Vector3> vertices = _mesh.getVertexList();
1189
1190 float[] verticesAsFloats = new float[vertices.Count * 3];
1191 int vi = 0;
1192 foreach (OMV.Vector3 vv in vertices)
1193 {
1194 verticesAsFloats[vi++] = vv.X;
1195 verticesAsFloats[vi++] = vv.Y;
1196 verticesAsFloats[vi++] = vv.Z;
1197 }
1198
1199 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
1200 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
1201 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
1202 vertices.Count, verticesAsFloats);
1203
1204 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1205 // meshes are already scaled by the meshmerizer
1206 _scale = new OMV.Vector3(1f, 1f, 1f);
1207 return true;
1208 }
1209
1210 // No locking here because this is done when we know physics is not simulating
1211 // Returns 'true' of a mesh was actually rebuild (we could also have one of these specs).
1212 private bool CreateGeomHull()
1213 {
1214 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1215 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod);
1216 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey);
1217
1218 // if the hull hasn't changed, don't rebuild it
1219 if (newHullKey == _hullKey) return false;
1220
1221 DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey);
1222
1223 // Since we're recreating new, get rid of any previously generated shape
1224 if (_hullKey != 0)
1225 {
1226 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1227 DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey);
1228 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1229 _hullKey = 0;
1230 }
1231
1232 _hullKey = newHullKey;
1233
1234 // Make sure the underlying mesh exists and is correct
1235 CreateGeomMesh();
1236
1237 int[] indices = _mesh.getIndexListAsInt();
1238 List<OMV.Vector3> vertices = _mesh.getVertexList();
1239
1240 //format conversion from IMesh format to DecompDesc format
1241 List<int> convIndices = new List<int>();
1242 List<float3> convVertices = new List<float3>();
1243 for (int ii = 0; ii < indices.GetLength(0); ii++)
1244 {
1245 convIndices.Add(indices[ii]);
1246 }
1247 foreach (OMV.Vector3 vv in vertices)
1248 {
1249 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
1250 }
1251
1252 // setup and do convex hull conversion
1253 _hulls = new List<ConvexResult>();
1254 DecompDesc dcomp = new DecompDesc();
1255 dcomp.mIndices = convIndices;
1256 dcomp.mVertices = convVertices;
1257 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1258 // create the hull into the _hulls variable
1259 convexBuilder.process(dcomp);
1260
1261 // Convert the vertices and indices for passing to unmanaged.
1262 // The hull information is passed as a large floating point array.
1263 // The format is:
1264 // convHulls[0] = number of hulls
1265 // convHulls[1] = number of vertices in first hull
1266 // convHulls[2] = hull centroid X coordinate
1267 // convHulls[3] = hull centroid Y coordinate
1268 // convHulls[4] = hull centroid Z coordinate
1269 // convHulls[5] = first hull vertex X
1270 // convHulls[6] = first hull vertex Y
1271 // convHulls[7] = first hull vertex Z
1272 // convHulls[8] = second hull vertex X
1273 // ...
1274 // convHulls[n] = number of vertices in second hull
1275 // convHulls[n+1] = second hull centroid X coordinate
1276 // ...
1277 //
1278 // TODO: is is very inefficient. Someday change the convex hull generator to return
1279 // data structures that do not need to be converted in order to pass to Bullet.
1280 // And maybe put the values directly into pinned memory rather than marshaling.
1281 int hullCount = _hulls.Count;
1282 int totalVertices = 1; // include one for the count of the hulls
1283 foreach (ConvexResult cr in _hulls)
1284 {
1285 totalVertices += 4; // add four for the vertex count and centroid
1286 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
1287 }
1288 float[] convHulls = new float[totalVertices];
1289
1290 convHulls[0] = (float)hullCount;
1291 int jj = 1;
1292 foreach (ConvexResult cr in _hulls)
1293 {
1294 // copy vertices for index access
1295 float3[] verts = new float3[cr.HullVertices.Count];
1296 int kk = 0;
1297 foreach (float3 ff in cr.HullVertices)
1298 {
1299 verts[kk++] = ff;
1300 }
1301
1302 // add to the array one hull's worth of data
1303 convHulls[jj++] = cr.HullIndices.Count;
1304 convHulls[jj++] = 0f; // centroid x,y,z
1305 convHulls[jj++] = 0f;
1306 convHulls[jj++] = 0f;
1307 foreach (int ind in cr.HullIndices)
1308 {
1309 convHulls[jj++] = verts[ind].x;
1310 convHulls[jj++] = verts[ind].y;
1311 convHulls[jj++] = verts[ind].z;
1312 }
1313 }
1314
1315 // create the hull definition in Bullet
1316 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1317 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1318 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1319 // meshes are already scaled by the meshmerizer
1320 _scale = new OMV.Vector3(1f, 1f, 1f);
1321 DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID);
1322 return true;
1323 }
1324
1325 // Callback from convex hull creater with a newly created hull.
1326 // Just add it to the collection of hulls for this shape.
1327 private void HullReturn(ConvexResult result)
1328 {
1329 _hulls.Add(result);
1330 return;
1331 }
1332
1333 private void VerifyCorrectPhysicalShape()
1334 {
1335 if (!IsStatic)
1336 {
1337 // if not static, it will need a hull to efficiently collide with things
1338 if (_hullKey == 0)
1339 {
1340 CreateGeomAndObject(false);
1341 }
1342
1343 }
1344 }
1345
1346 // Create an object in Bullet if it has not already been created
1347 // No locking here because this is done when the physics engine is not simulating
1348 // Returns 'true' if an object was actually created.
1349 private bool CreateObject()
1350 {
1351 // this routine is called when objects are rebuilt.
1352
1353 // the mesh or hull must have already been created in Bullet
1354 ShapeData shape;
1355 FillShapeInfo(out shape);
1356 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1357 bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
1358
1359 // the CreateObject() may have recreated the rigid body. Make sure we have the latest address.
1360 BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
1361 BSShape = new BulletShape(BulletSimAPI.GetCollisionShape2(BSBody.Ptr));
1362
1363 return ret;
1364 }
1365
1366 // Copy prim's info into the BulletSim shape description structure 1081 // Copy prim's info into the BulletSim shape description structure
1367 public void FillShapeInfo(out ShapeData shape) 1082 public void FillShapeInfo(out ShapeData shape)
1368 { 1083 {
1369 shape.ID = _localID; 1084 shape.ID = LocalID;
1370 shape.Type = _shapeType; 1085 shape.Type = _shapeType;
1371 shape.Position = _position; 1086 shape.Position = _position;
1372 shape.Rotation = _orientation; 1087 shape.Rotation = _orientation;
@@ -1380,22 +1095,39 @@ public sealed class BSPrim : BSPhysObject
1380 shape.Restitution = _restitution; 1095 shape.Restitution = _restitution;
1381 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; 1096 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1382 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; 1097 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1098 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1099 shape.Size = _size;
1383 } 1100 }
1384
1385 // Rebuild the geometry and object. 1101 // Rebuild the geometry and object.
1386 // This is called when the shape changes so we need to recreate the mesh/hull. 1102 // This is called when the shape changes so we need to recreate the mesh/hull.
1387 // No locking here because this is done when the physics engine is not simulating 1103 // Called at taint-time!!!
1388 private void CreateGeomAndObject(bool forceRebuild) 1104 private void CreateGeomAndObject(bool forceRebuild)
1389 { 1105 {
1390 // m_log.DebugFormat("{0}: CreateGeomAndObject. lID={1}, force={2}", LogHeader, _localID, forceRebuild); 1106 ShapeData shapeData;
1391 // Create the geometry that will make up the object 1107 FillShapeInfo(out shapeData);
1392 if (CreateGeom(forceRebuild)) 1108
1109 // If this prim is part of a linkset, we must remove and restore the physical
1110 // links of the body is rebuilt.
1111 bool needToRestoreLinkset = false;
1112
1113 // Create the correct physical representation for this type of object.
1114 // Updates BSBody and BSShape with the new information.
1115 PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs,
1116 null, delegate(BulletBody dBody)
1117 {
1118 // Called if the current prim body is about to be destroyed.
1119 // Remove all the physical dependencies on the old body.
1120 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1121 });
1122
1123 if (needToRestoreLinkset)
1393 { 1124 {
1394 // Create the object and place it into the world 1125 // If physical body dependencies were removed, restore them
1395 CreateObject(); 1126 Linkset.RestoreBodyDependencies(this);
1396 // Make sure the properties are set on the new object
1397 UpdatePhysicalParameters();
1398 } 1127 }
1128
1129 // Make sure the properties are set on the new object
1130 UpdatePhysicalParameters();
1399 return; 1131 return;
1400 } 1132 }
1401 1133
@@ -1485,66 +1217,10 @@ public sealed class BSPrim : BSPhysObject
1485 { 1217 {
1486 // For debugging, we can also report the movement of children 1218 // For debugging, we can also report the movement of children
1487 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1219 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1488 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1220 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1489 entprop.Acceleration, entprop.RotationalVelocity); 1221 entprop.Acceleration, entprop.RotationalVelocity);
1490 } 1222 }
1491 */ 1223 */
1492 } 1224 }
1493
1494 // I've collided with something
1495 // Called at taint time from within the Step() function
1496 CollisionEventUpdate collisionCollection;
1497 public override bool Collide(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1498 {
1499 bool ret = false;
1500
1501 // The following lines make IsColliding() and IsCollidingGround() work
1502 _collidingStep = Scene.SimulationStep;
1503 if (collidingWith <= Scene.TerrainManager.HighestTerrainID)
1504 {
1505 _collidingGroundStep = Scene.SimulationStep;
1506 }
1507
1508 // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
1509
1510 // prims in the same linkset cannot collide with each other
1511 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
1512 {
1513 return ret;
1514 }
1515
1516 // if someone has subscribed for collision events....
1517 if (SubscribedEvents()) {
1518 // throttle the collisions to the number of milliseconds specified in the subscription
1519 int nowTime = Scene.SimulationNowTime;
1520 if (nowTime >= _nextCollisionOkTime) {
1521 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
1522
1523 if (collisionCollection == null)
1524 collisionCollection = new CollisionEventUpdate();
1525 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1526 ret = true;
1527 }
1528 }
1529 return ret;
1530 }
1531
1532 // The scene is telling us it's time to pass our collected collisions into the simulator
1533 public override void SendCollisions()
1534 {
1535 if (collisionCollection != null && collisionCollection.Count > 0)
1536 {
1537 base.SendCollisionUpdate(collisionCollection);
1538 // The collisionCollection structure is passed around in the simulator.
1539 // Make sure we don't have a handle to that one and that a new one is used next time.
1540 collisionCollection = null;
1541 }
1542 }
1543
1544 // Invoke the detailed logger and output something if it's enabled.
1545 private void DetailLog(string msg, params Object[] args)
1546 {
1547 Scene.PhysicsLogging.Write(msg, args);
1548 }
1549} 1225}
1550} 1226}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 52997dd..0cf8c91 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,20 +39,20 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight) 42// Move all logic out of the C++ code and into the C# code for easier future modifications.
43// Test sculpties 43// Test sculpties (verified that they don't work)
44// Compute physics FPS reasonably 44// Compute physics FPS reasonably
45// Based on material, set density and friction 45// Based on material, set density and friction
46// More efficient memory usage when passing hull information from BSPrim to BulletSim 46// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
47// Move all logic out of the C++ code and into the C# code for easier future modifications.
48// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 47// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
49// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 48// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
50// At the moment, physical and phantom causes object to drop through the terrain 49// At the moment, physical and phantom causes object to drop through the terrain
51// Physical phantom objects and related typing (collision options ) 50// Physical phantom objects and related typing (collision options )
52// Use collision masks for collision with terrain and phantom objects
53// Check out llVolumeDetect. Must do something for that. 51// Check out llVolumeDetect. Must do something for that.
52// Use collision masks for collision with terrain and phantom objects
53// More efficient memory usage when passing hull information from BSPrim to BulletSim
54// Should prim.link() and prim.delink() membership checking happen at taint time? 54// Should prim.link() and prim.delink() membership checking happen at taint time?
55// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once 55// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
56// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 56// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
57// Implement LockAngularMotion 57// Implement LockAngularMotion
58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 58// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
@@ -60,7 +60,7 @@ using OpenMetaverse;
60// Add PID movement operations. What does ScenePresence.MoveToTarget do? 60// Add PID movement operations. What does ScenePresence.MoveToTarget do?
61// Check terrain size. 128 or 127? 61// Check terrain size. 128 or 127?
62// Raycast 62// Raycast
63// 63//
64namespace OpenSim.Region.Physics.BulletSPlugin 64namespace OpenSim.Region.Physics.BulletSPlugin
65{ 65{
66public class BSScene : PhysicsScene, IPhysicsParameters 66public class BSScene : PhysicsScene, IPhysicsParameters
@@ -73,12 +73,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
73 73
74 public string BulletSimVersion = "?"; 74 public string BulletSimVersion = "?";
75 75
76 public Dictionary<uint, BSPhysObject> PhysObjects = new Dictionary<uint, BSPhysObject>(); 76 public Dictionary<uint, BSPhysObject> PhysObjects;
77 public BSShapeCollection Shapes;
77 78
78 private HashSet<BSPhysObject> m_objectsWithCollisions = new HashSet<BSPhysObject>(); 79 // Keeping track of the objects with collisions so we can report begin and end of a collision
79 // Following is a kludge and can be removed when avatar animation updating is 80 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
80 // moved to a better place. 81 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
81 private HashSet<BSPhysObject> m_avatarsWithCollisions = new HashSet<BSPhysObject>(); 82 // Keep track of all the avatars so we can send them a collision event
83 // every tick so OpenSim will update its animation.
84 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
82 85
83 // List of all the objects that have vehicle properties and should be called 86 // List of all the objects that have vehicle properties and should be called
84 // to update each physics step. 87 // to update each physics step.
@@ -202,6 +205,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
202 205
203 public override void Initialise(IMesher meshmerizer, IConfigSource config) 206 public override void Initialise(IMesher meshmerizer, IConfigSource config)
204 { 207 {
208 mesher = meshmerizer;
209 _taintedObjects = new List<TaintCallbackEntry>();
210 PhysObjects = new Dictionary<uint, BSPhysObject>();
211 Shapes = new BSShapeCollection(this);
212
205 // Allocate pinned memory to pass parameters. 213 // Allocate pinned memory to pass parameters.
206 m_params = new ConfigurationParameters[1]; 214 m_params = new ConfigurationParameters[1];
207 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 215 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,12 +223,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 223 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
216 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); 224 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
217 225
218 mesher = meshmerizer;
219 _taintedObjects = new List<TaintCallbackEntry>();
220
221 // Enable very detailed logging. 226 // Enable very detailed logging.
222 // By creating an empty logger when not logging, the log message invocation code 227 // By creating an empty logger when not logging, the log message invocation code
223 // can be left in and every call doesn't have to check for null. 228 // can be left in and every call doesn't have to check for null.
224 if (m_physicsLoggingEnabled) 229 if (m_physicsLoggingEnabled)
225 { 230 {
226 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 231 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -251,7 +256,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
251 // a child in a mega-region. 256 // a child in a mega-region.
252 // Turns out that Bullet really doesn't care about the extents of the simulated 257 // Turns out that Bullet really doesn't care about the extents of the simulated
253 // area. It tracks active objects no matter where they are. 258 // area. It tracks active objects no matter where they are.
254 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 259 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
255 260
256 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 261 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
257 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 262 WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
@@ -322,7 +327,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
322 { 327 {
323 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 328 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
324 } 329 }
325 330
326 // Called directly from unmanaged code so don't do much 331 // Called directly from unmanaged code so don't do much
327 private void BulletLoggerPhysLog(string msg) 332 private void BulletLoggerPhysLog(string msg)
328 { 333 {
@@ -351,6 +356,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
351 Constraints = null; 356 Constraints = null;
352 } 357 }
353 358
359 if (Shapes != null)
360 {
361 Shapes.Dispose();
362 Shapes = null;
363 }
364
354 // Anything left in the unmanaged code should be cleaned out 365 // Anything left in the unmanaged code should be cleaned out
355 BulletSimAPI.Shutdown(WorldID); 366 BulletSimAPI.Shutdown(WorldID);
356 367
@@ -379,7 +390,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
379 // TODO: Remove kludge someday. 390 // TODO: Remove kludge someday.
380 // We must generate a collision for avatars whether they collide or not. 391 // We must generate a collision for avatars whether they collide or not.
381 // This is required by OpenSim to update avatar animations, etc. 392 // This is required by OpenSim to update avatar animations, etc.
382 lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Add(actor); 393 lock (m_avatars) m_avatars.Add(actor);
383 394
384 return actor; 395 return actor;
385 } 396 }
@@ -397,7 +408,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
397 { 408 {
398 lock (PhysObjects) PhysObjects.Remove(actor.LocalID); 409 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
399 // Remove kludge someday 410 // Remove kludge someday
400 lock (m_avatarsWithCollisions) m_avatarsWithCollisions.Remove(bsactor); 411 lock (m_avatars) m_avatars.Remove(bsactor);
401 } 412 }
402 catch (Exception e) 413 catch (Exception e)
403 { 414 {
@@ -449,7 +460,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
449 } 460 }
450 461
451 // This is a call from the simulator saying that some physical property has been updated. 462 // This is a call from the simulator saying that some physical property has been updated.
452 // The BulletSim driver senses the changing of relevant properties so this taint 463 // The BulletSim driver senses the changing of relevant properties so this taint
453 // information call is not needed. 464 // information call is not needed.
454 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 465 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
455 466
@@ -464,6 +475,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
464 int collidersCount = 0; 475 int collidersCount = 0;
465 IntPtr collidersPtr; 476 IntPtr collidersPtr;
466 477
478 int beforeTime = 0;
479 int simTime = 0;
480
467 // prevent simulation until we've been initialized 481 // prevent simulation until we've been initialized
468 if (!m_initialized) return 5.0f; 482 if (!m_initialized) return 5.0f;
469 483
@@ -481,16 +495,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
481 int numSubSteps = 0; 495 int numSubSteps = 0;
482 try 496 try
483 { 497 {
498 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
499
484 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 500 numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep,
485 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 501 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
486 DetailLog("{0},Simulate,call, nTaints= {1}, substeps={2}, updates={3}, colliders={4}", 502
487 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); 503 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
504 DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}",
505 DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
488 } 506 }
489 catch (Exception e) 507 catch (Exception e)
490 { 508 {
491 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}", 509 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
492 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e); 510 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
493 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}", 511 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
494 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount); 512 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
495 updatedEntityCount = 0; 513 updatedEntityCount = 0;
496 collidersCount = 0; 514 collidersCount = 0;
@@ -502,12 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
502 // Get a value for 'now' so all the collision and update routines don't have to get their own 520 // Get a value for 'now' so all the collision and update routines don't have to get their own
503 SimulationNowTime = Util.EnvironmentTickCount(); 521 SimulationNowTime = Util.EnvironmentTickCount();
504 522
505 // This is a kludge to get avatar movement updates.
506 // ODE sends collisions for avatars even if there are have been no collisions. This updates
507 // avatar animations and stuff.
508 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
509 m_objectsWithCollisions = new HashSet<BSPhysObject>(m_avatarsWithCollisions);
510
511 // If there were collisions, process them by sending the event to the prim. 523 // If there were collisions, process them by sending the event to the prim.
512 // Collisions must be processed before updates. 524 // Collisions must be processed before updates.
513 if (collidersCount > 0) 525 if (collidersCount > 0)
@@ -523,11 +535,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
523 } 535 }
524 } 536 }
525 537
538 // This is a kludge to get avatar movement updates.
539 // ODE sends collisions for avatars even if there are have been no collisions. This updates
540 // avatar animations and stuff.
541 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
542 foreach (BSPhysObject bsp in m_avatars)
543 bsp.SendCollisions();
544
526 // The above SendCollision's batch up the collisions on the objects. 545 // The above SendCollision's batch up the collisions on the objects.
527 // Now push the collisions into the simulator. 546 // Now push the collisions into the simulator.
528 foreach (BSPhysObject bsp in m_objectsWithCollisions) 547 if (ObjectsWithCollisions.Count > 0)
529 bsp.SendCollisions(); 548 {
530 m_objectsWithCollisions.Clear(); 549 foreach (BSPhysObject bsp in ObjectsWithCollisions)
550 if (!m_avatars.Contains(bsp)) // don't call avatars twice
551 if (!bsp.SendCollisions())
552 {
553 // If the object is done colliding, see that it's removed from the colliding list
554 ObjectsWithNoMoreCollisions.Add(bsp);
555 }
556 }
557
558 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
559 // This can't be done by SendCollisions because it is inside an iteration of ObjectWithCollisions.
560 if (ObjectsWithNoMoreCollisions.Count > 0)
561 {
562 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
563 ObjectsWithCollisions.Remove(po);
564 ObjectsWithNoMoreCollisions.Clear();
565 }
531 566
532 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 567 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
533 if (updatedEntityCount > 0) 568 if (updatedEntityCount > 0)
@@ -555,7 +590,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
555 // The physics engine returns the number of milliseconds it simulated this call. 590 // The physics engine returns the number of milliseconds it simulated this call.
556 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 591 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
557 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. 592 // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS.
558 return numSubSteps * m_fixedTimeStep; 593 return numSubSteps * m_fixedTimeStep * 1000;
559 } 594 }
560 595
561 // Something has collided 596 // Something has collided
@@ -570,20 +605,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
570 if (!PhysObjects.TryGetValue(localID, out collider)) 605 if (!PhysObjects.TryGetValue(localID, out collider))
571 { 606 {
572 // If the object that is colliding cannot be found, just ignore the collision. 607 // If the object that is colliding cannot be found, just ignore the collision.
608 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
573 return; 609 return;
574 } 610 }
575 611
576 // The terrain is not in the physical object list so 'collidee' 612 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
577 // can be null when Collide() is called.
578 BSPhysObject collidee = null; 613 BSPhysObject collidee = null;
579 PhysObjects.TryGetValue(collidingWith, out collidee); 614 PhysObjects.TryGetValue(collidingWith, out collidee);
580 615
581 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); 616 DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
582 617
583 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) 618 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
584 { 619 {
585 // If a collision was posted, remember to send it to the simulator 620 // If a collision was posted, remember to send it to the simulator
586 m_objectsWithCollisions.Add(collider); 621 ObjectsWithCollisions.Add(collider);
587 } 622 }
588 623
589 return; 624 return;
@@ -599,7 +634,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
599 TerrainManager.SetTerrain(heightMap); 634 TerrainManager.SetTerrain(heightMap);
600 } 635 }
601 636
602 public override void SetWaterLevel(float baseheight) 637 public override void SetWaterLevel(float baseheight)
603 { 638 {
604 m_waterLevel = baseheight; 639 m_waterLevel = baseheight;
605 } 640 }
@@ -609,7 +644,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
609 return m_waterLevel; 644 return m_waterLevel;
610 } 645 }
611 646
612 public override void DeleteTerrain() 647 public override void DeleteTerrain()
613 { 648 {
614 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 649 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
615 } 650 }
@@ -771,7 +806,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
771 // getters and setters. 806 // getters and setters.
772 // It is easiest to find an existing definition and copy it. 807 // It is easiest to find an existing definition and copy it.
773 // Parameter values are floats. Booleans are converted to a floating value. 808 // Parameter values are floats. Booleans are converted to a floating value.
774 // 809 //
775 // A ParameterDefn() takes the following parameters: 810 // A ParameterDefn() takes the following parameters:
776 // -- the text name of the parameter. This is used for console input and ini file. 811 // -- the text name of the parameter. This is used for console input and ini file.
777 // -- a short text description of the parameter. This shows up in the console listing. 812 // -- a short text description of the parameter. This shows up in the console listing.
@@ -998,7 +1033,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
998 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1033 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
999 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1034 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1000 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1035 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1001 ConfigurationParameters.numericFalse, 1036 ConfigurationParameters.numericTrue,
1002 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1037 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1003 (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, 1038 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1004 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1039 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1193,7 +1228,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1193 } 1228 }
1194 }); 1229 });
1195 break; 1230 break;
1196 default: 1231 default:
1197 // setting only one localID 1232 // setting only one localID
1198 TaintedUpdateParameter(parm, localID, val); 1233 TaintedUpdateParameter(parm, localID, val);
1199 break; 1234 break;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
new file mode 100755
index 0000000..dee6243
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -0,0 +1,735 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public class BSShapeCollection : IDisposable
38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 protected BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public IntPtr ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 }
52
53 // Description of a hull.
54 // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects
55 private struct HullDesc
56 {
57 public IntPtr ptr;
58 public int referenceCount;
59 public DateTime lastReferenced;
60 }
61
62 private struct BodyDesc
63 {
64 public IntPtr ptr;
65 // Bodies are only used once so reference count is always either one or zero
66 public int referenceCount;
67 public DateTime lastReferenced;
68 }
69
70 private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>();
71 private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>();
72 private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>();
73
74 public BSShapeCollection(BSScene physScene)
75 {
76 PhysicsScene = physScene;
77 }
78
79 public void Dispose()
80 {
81 // TODO!!!!!!!!!
82 }
83
84 // Callbacks called just before either the body or shape is destroyed.
85 // Mostly used for changing bodies out from under Linksets.
86 // Useful for other cases where parameters need saving.
87 // Passing 'null' says no callback.
88 public delegate void ShapeDestructionCallback(BulletShape shape);
89 public delegate void BodyDestructionCallback(BulletBody body);
90
91 // Called to update/change the body and shape for an object.
92 // First checks the shape and updates that if necessary then makes
93 // sure the body is of the right type.
94 // Return 'true' if either the body or the shape changed.
95 // Called at taint-time!!
96 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim,
97 ShapeData shapeData, PrimitiveBaseShape pbs,
98 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
99 {
100 bool ret = false;
101
102 // This lock could probably be pushed down lower but building shouldn't take long
103 lock (m_collectionActivityLock)
104 {
105 // Do we have the correct geometry for this type of object?
106 // Updates prim.BSShape with information/pointers to requested shape
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback);
108 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body
111 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, prim.BSShape, shapeData, bodyCallback);
112 ret = newGeom || newBody;
113 }
114 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}",
115 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape);
116
117 return ret;
118 }
119
120 // Track another user of a body
121 // We presume the caller has allocated the body.
122 // Bodies only have one user so the reference count is either 1 or 0.
123 public void ReferenceBody(BulletBody body, bool atTaintTime)
124 {
125 lock (m_collectionActivityLock)
126 {
127 BodyDesc bodyDesc;
128 if (Bodies.TryGetValue(body.ID, out bodyDesc))
129 {
130 bodyDesc.referenceCount++;
131 DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount);
132 }
133 else
134 {
135 // New entry
136 bodyDesc.ptr = body.ptr;
137 bodyDesc.referenceCount = 1;
138 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
139 }
140 bodyDesc.lastReferenced = System.DateTime.Now;
141 Bodies[body.ID] = bodyDesc;
142 }
143}
144
145 // Release the usage of a body.
146 // Called when releasing use of a BSBody. BSShape is handled separately.
147 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
148 {
149 if (body.ptr == IntPtr.Zero)
150 return;
151
152 lock (m_collectionActivityLock)
153 {
154 BodyDesc bodyDesc;
155 if (Bodies.TryGetValue(body.ID, out bodyDesc))
156 {
157 bodyDesc.referenceCount--;
158 bodyDesc.lastReferenced = System.DateTime.Now;
159 Bodies[body.ID] = bodyDesc;
160 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
161
162 // If body is no longer being used, free it -- bodies are never shared.
163 if (bodyDesc.referenceCount == 0)
164 {
165 Bodies.Remove(body.ID);
166 BSScene.TaintCallback removeOperation = delegate()
167 {
168 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
169 body.ID, body.ptr.ToString("X"));
170 // If the caller needs to know, pass the event up.
171 if (bodyCallback != null) bodyCallback(body);
172
173 // Zero any reference to the shape so it is not freed when the body is deleted.
174 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
175 // It may have already been removed from the world in which case the next is a NOOP.
176 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
177 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
178 };
179 // If already in taint-time, do the operations now. Otherwise queue for later.
180 if (inTaintTime)
181 removeOperation();
182 else
183 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
184 }
185 }
186 else
187 {
188 DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount);
189 }
190 }
191 }
192
193 // Track the datastructures and use count for a shape.
194 // When creating a hull, this is called first to reference the mesh
195 // and then again to reference the hull.
196 // Meshes and hulls for the same shape have the same hash key.
197 // NOTE that native shapes are not added to the mesh list or removed.
198 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
199 private bool ReferenceShape(BulletShape shape)
200 {
201 bool ret = false;
202 switch (shape.type)
203 {
204 case ShapeData.PhysicsShapeType.SHAPE_MESH:
205 MeshDesc meshDesc;
206 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
207 {
208 // There is an existing instance of this mesh.
209 meshDesc.referenceCount++;
210 DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
212 }
213 else
214 {
215 // This is a new reference to a mesh
216 meshDesc.ptr = shape.ptr;
217 // We keep a reference to the underlying IMesh data so a hull can be built
218 meshDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
221 ret = true;
222 }
223 meshDesc.lastReferenced = System.DateTime.Now;
224 Meshes[shape.shapeKey] = meshDesc;
225 break;
226 case ShapeData.PhysicsShapeType.SHAPE_HULL:
227 HullDesc hullDesc;
228 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
229 {
230 // There is an existing instance of this hull.
231 hullDesc.referenceCount++;
232 DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
233 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
234 }
235 else
236 {
237 // This is a new reference to a hull
238 hullDesc.ptr = shape.ptr;
239 hullDesc.referenceCount = 1;
240 DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
241 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
242 ret = true;
243
244 }
245 hullDesc.lastReferenced = System.DateTime.Now;
246 Hulls[shape.shapeKey] = hullDesc;
247 break;
248 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
249 break;
250 default:
251 // Native shapes are not tracked and they don't go into any list
252 break;
253 }
254 return ret;
255 }
256
257 // Release the usage of a shape.
258 // The collisionObject is released since it is a copy of the real collision shape.
259 public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback)
260 {
261 if (shape.ptr == IntPtr.Zero)
262 return;
263
264 BSScene.TaintCallback dereferenceOperation = delegate()
265 {
266 switch (shape.type)
267 {
268 case ShapeData.PhysicsShapeType.SHAPE_HULL:
269 DereferenceHull(shape, shapeCallback);
270 break;
271 case ShapeData.PhysicsShapeType.SHAPE_MESH:
272 DereferenceMesh(shape, shapeCallback);
273 break;
274 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN:
275 break;
276 default:
277 // Native shapes are not tracked and are released immediately
278 if (shape.ptr != IntPtr.Zero & shape.isNativeShape)
279 {
280 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
281 BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime);
282 if (shapeCallback != null) shapeCallback(shape);
283 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
284 }
285 break;
286 }
287 };
288 if (atTaintTime)
289 {
290 lock (m_collectionActivityLock)
291 {
292 dereferenceOperation();
293 }
294 }
295 else
296 {
297 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
298 }
299 }
300
301 // Count down the reference count for a mesh shape
302 // Called at taint-time.
303 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
304 {
305 MeshDesc meshDesc;
306 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
307 {
308 meshDesc.referenceCount--;
309 // TODO: release the Bullet storage
310 if (shapeCallback != null) shapeCallback(shape);
311 meshDesc.lastReferenced = System.DateTime.Now;
312 Meshes[shape.shapeKey] = meshDesc;
313 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}",
314 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
315
316 }
317 }
318
319 // Count down the reference count for a hull shape
320 // Called at taint-time.
321 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 {
323 HullDesc hullDesc;
324 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
325 {
326 hullDesc.referenceCount--;
327 // TODO: release the Bullet storage (aging old entries?)
328 if (shapeCallback != null) shapeCallback(shape);
329 hullDesc.lastReferenced = System.DateTime.Now;
330 Hulls[shape.shapeKey] = hullDesc;
331 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}",
332 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
333 }
334 }
335
336 // Create the geometry information in Bullet for later use.
337 // The objects needs a hull if it's physical otherwise a mesh is enough.
338 // No locking here because this is done when we know physics is not simulating.
339 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used.
340 // Returns 'true' if the geometry was rebuilt.
341 // Called at taint-time!
342 private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData,
343 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
344 {
345 bool ret = false;
346 bool haveShape = false;
347 bool nativeShapePossible = true;
348
349 // If the prim attributes are simple, this could be a simple Bullet native shape
350 if (nativeShapePossible
351 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
352 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
353 && pbs.ProfileHollow == 0
354 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
355 && pbs.PathBegin == 0 && pbs.PathEnd == 0
356 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
357 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
358 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
359 {
360 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
361 {
362 haveShape = true;
363 if (forceRebuild
364 || prim.Scale != shapeData.Size
365 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE
366 )
367 {
368 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE,
369 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback);
370 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
371 prim.LocalID, forceRebuild, prim.BSShape);
372 }
373 }
374 else
375 {
376 haveShape = true;
377 if (forceRebuild
378 || prim.Scale != shapeData.Size
379 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX
380 )
381 {
382 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX,
383 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback);
384 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
385 prim.LocalID, forceRebuild, prim.BSShape);
386 }
387 }
388 }
389 // If a simple shape is not happening, create a mesh and possibly a hull.
390 // Note that if it's a native shape, the check for physical/non-physical is not
391 // made. Native shapes are best used in either case.
392 if (!haveShape)
393 {
394 if (prim.IsPhysical)
395 {
396 // Update prim.BSShape to reference a hull of this shape.
397 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback);
398 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
399 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
400 }
401 else
402 {
403 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback);
404 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
405 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X"));
406 }
407 }
408 return ret;
409 }
410
411 // Creates a native shape and assignes it to prim.BSShape
412 private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData,
413 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey,
414 ShapeDestructionCallback shapeCallback)
415 {
416 BulletShape newShape;
417
418 shapeData.Type = shapeType;
419 // Bullet native objects are scaled by the Bullet engine so pass the size in
420 prim.Scale = shapeData.Size;
421 shapeData.Scale = shapeData.Size;
422
423 // release any previous shape
424 DereferenceShape(prim.BSShape, true, shapeCallback);
425
426 // Native shapes are always built independently.
427 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType);
428 newShape.shapeKey = (ulong)shapeKey;
429 newShape.isNativeShape = true;
430
431 // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked.
432 // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape);
433
434 prim.BSShape = newShape;
435 return true;
436 }
437
438 // Builds a mesh shape in the physical world and updates prim.BSShape.
439 // Dereferences previous shape in BSShape and adds a reference for this new shape.
440 // Returns 'true' of a mesh was actually built. Otherwise .
441 // Called at taint-time!
442 private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
443 ShapeDestructionCallback shapeCallback)
444 {
445 BulletShape newShape = new BulletShape(IntPtr.Zero);
446
447 float lod;
448 ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod);
449
450 // if this new shape is the same as last time, don't recreate the mesh
451 if (prim.BSShape.shapeKey == newMeshKey) return false;
452
453 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}",
454 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
455
456 // Since we're recreating new, get rid of the reference to the previous shape
457 DereferenceShape(prim.BSShape, true, shapeCallback);
458
459 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod);
460
461 ReferenceShape(newShape);
462
463 // meshes are already scaled by the meshmerizer
464 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
465 prim.BSShape = newShape;
466
467 return true; // 'true' means a new shape has been added to this prim
468 }
469
470 private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
471 {
472 IMesh meshData = null;
473 IntPtr meshPtr;
474 MeshDesc meshDesc;
475 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
476 {
477 // If the mesh has already been built just use it.
478 meshPtr = meshDesc.ptr;
479 }
480 else
481 {
482 // Pass false for physicalness as this creates some sort of bounding box which we don't need
483 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
484
485 int[] indices = meshData.getIndexListAsInt();
486 List<OMV.Vector3> vertices = meshData.getVertexList();
487
488 float[] verticesAsFloats = new float[vertices.Count * 3];
489 int vi = 0;
490 foreach (OMV.Vector3 vv in vertices)
491 {
492 verticesAsFloats[vi++] = vv.X;
493 verticesAsFloats[vi++] = vv.Y;
494 verticesAsFloats[vi++] = vv.Z;
495 }
496
497 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
498 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
499
500 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
501 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
502 }
503 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH);
504 newShape.shapeKey = newMeshKey;
505
506 return newShape;
507 }
508
509 // See that hull shape exists in the physical world and update prim.BSShape.
510 // We could be creating the hull because scale changed or whatever.
511 private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs,
512 ShapeDestructionCallback shapeCallback)
513 {
514 BulletShape newShape;
515
516 float lod;
517 ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
518
519 // if the hull hasn't changed, don't rebuild it
520 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
521 return false;
522
523 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
524 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
525
526 // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
527 DereferenceShape(prim.BSShape, true, shapeCallback);
528
529 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
530
531 ReferenceShape(newShape);
532
533 // hulls are already scaled by the meshmerizer
534 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
535 prim.BSShape = newShape;
536 return true; // 'true' means a new shape has been added to this prim
537 }
538
539 List<ConvexResult> m_hulls;
540 private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
541 {
542
543 IntPtr hullPtr;
544 HullDesc hullDesc;
545 if (Hulls.TryGetValue(newHullKey, out hullDesc))
546 {
547 // If the hull shape already is created, just use it.
548 hullPtr = hullDesc.ptr;
549 }
550 else
551 {
552 // Build a new hull in the physical world
553 // Pass false for physicalness as this creates some sort of bounding box which we don't need
554 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
555
556 int[] indices = meshData.getIndexListAsInt();
557 List<OMV.Vector3> vertices = meshData.getVertexList();
558
559 //format conversion from IMesh format to DecompDesc format
560 List<int> convIndices = new List<int>();
561 List<float3> convVertices = new List<float3>();
562 for (int ii = 0; ii < indices.GetLength(0); ii++)
563 {
564 convIndices.Add(indices[ii]);
565 }
566 foreach (OMV.Vector3 vv in vertices)
567 {
568 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
569 }
570
571 // setup and do convex hull conversion
572 m_hulls = new List<ConvexResult>();
573 DecompDesc dcomp = new DecompDesc();
574 dcomp.mIndices = convIndices;
575 dcomp.mVertices = convVertices;
576 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
577 // create the hull into the _hulls variable
578 convexBuilder.process(dcomp);
579
580 // Convert the vertices and indices for passing to unmanaged.
581 // The hull information is passed as a large floating point array.
582 // The format is:
583 // convHulls[0] = number of hulls
584 // convHulls[1] = number of vertices in first hull
585 // convHulls[2] = hull centroid X coordinate
586 // convHulls[3] = hull centroid Y coordinate
587 // convHulls[4] = hull centroid Z coordinate
588 // convHulls[5] = first hull vertex X
589 // convHulls[6] = first hull vertex Y
590 // convHulls[7] = first hull vertex Z
591 // convHulls[8] = second hull vertex X
592 // ...
593 // convHulls[n] = number of vertices in second hull
594 // convHulls[n+1] = second hull centroid X coordinate
595 // ...
596 //
597 // TODO: is is very inefficient. Someday change the convex hull generator to return
598 // data structures that do not need to be converted in order to pass to Bullet.
599 // And maybe put the values directly into pinned memory rather than marshaling.
600 int hullCount = m_hulls.Count;
601 int totalVertices = 1; // include one for the count of the hulls
602 foreach (ConvexResult cr in m_hulls)
603 {
604 totalVertices += 4; // add four for the vertex count and centroid
605 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
606 }
607 float[] convHulls = new float[totalVertices];
608
609 convHulls[0] = (float)hullCount;
610 int jj = 1;
611 foreach (ConvexResult cr in m_hulls)
612 {
613 // copy vertices for index access
614 float3[] verts = new float3[cr.HullVertices.Count];
615 int kk = 0;
616 foreach (float3 ff in cr.HullVertices)
617 {
618 verts[kk++] = ff;
619 }
620
621 // add to the array one hull's worth of data
622 convHulls[jj++] = cr.HullIndices.Count;
623 convHulls[jj++] = 0f; // centroid x,y,z
624 convHulls[jj++] = 0f;
625 convHulls[jj++] = 0f;
626 foreach (int ind in cr.HullIndices)
627 {
628 convHulls[jj++] = verts[ind].x;
629 convHulls[jj++] = verts[ind].y;
630 convHulls[jj++] = verts[ind].z;
631 }
632 }
633 // create the hull data structure in Bullet
634 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
635 }
636
637 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL);
638 newShape.shapeKey = newHullKey;
639
640 return newShape; // 'true' means a new shape has been added to this prim
641 }
642
643 // Callback from convex hull creater with a newly created hull.
644 // Just add it to our collection of hulls for this shape.
645 private void HullReturn(ConvexResult result)
646 {
647 m_hulls.Add(result);
648 return;
649 }
650
651 // Create a hash of all the shape parameters to be used as a key
652 // for this particular shape.
653 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod)
654 {
655 // level of detail based on size and type of the object
656 float lod = PhysicsScene.MeshLOD;
657 if (pbs.SculptEntry)
658 lod = PhysicsScene.SculptLOD;
659
660 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
661 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
662 lod = PhysicsScene.MeshMegaPrimLOD;
663
664 retLod = lod;
665 return (ulong)pbs.GetMeshKey(shapeData.Size, lod);
666 }
667 // For those who don't want the LOD
668 private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs)
669 {
670 float lod;
671 return ComputeShapeKey(shapeData, pbs, out lod);
672 }
673
674 // Create a body object in Bullet.
675 // Updates prim.BSBody with the information about the new body if one is created.
676 // Returns 'true' if an object was actually created.
677 // Called at taint-time.
678 private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape,
679 ShapeData shapeData, BodyDestructionCallback bodyCallback)
680 {
681 bool ret = false;
682
683 // the mesh, hull or native shape must have already been created in Bullet
684 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero);
685
686 // If there is an existing body, verify it's of an acceptable type.
687 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
688 if (!mustRebuild)
689 {
690 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr);
691 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
692 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
693 {
694 // If the collisionObject is not the correct type for solidness, rebuild what's there
695 mustRebuild = true;
696 }
697
698 }
699
700 if (mustRebuild || forceRebuild)
701 {
702 DereferenceBody(prim.BSBody, true, bodyCallback);
703
704 BulletBody aBody;
705 IntPtr bodyPtr = IntPtr.Zero;
706 if (prim.IsSolid)
707 {
708 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
709 shapeData.ID, shapeData.Position, shapeData.Rotation);
710 // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
711 }
712 else
713 {
714 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
715 shapeData.ID, shapeData.Position, shapeData.Rotation);
716 // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
717 }
718 aBody = new BulletBody(shapeData.ID, bodyPtr);
719
720 ReferenceBody(aBody, true);
721
722 prim.BSBody = aBody;
723
724 ret = true;
725 }
726
727 return ret;
728 }
729
730 private void DetailLog(string msg, params Object[] args)
731 {
732 PhysicsScene.PhysicsLogging.Write(msg, args);
733 }
734}
735}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index d48462e..70aa429 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -57,14 +57,14 @@ public class BSTerrainManager
57 public const float TERRAIN_COLLISION_MARGIN = 0.0f; 57 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
58 58
59 // Until the whole simulator is changed to pass us the region size, we rely on constants. 59 // Until the whole simulator is changed to pass us the region size, we rely on constants.
60 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, 0f); 60 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
61 61
62 // The scene that I am part of 62 // The scene that I am part of
63 private BSScene m_physicsScene; 63 private BSScene PhysicsScene { get; set; }
64 64
65 // The ground plane created to keep thing from falling to infinity. 65 // The ground plane created to keep thing from falling to infinity.
66 private BulletBody m_groundPlane; 66 private BulletBody m_groundPlane;
67 67
68 // If doing mega-regions, if we're region zero we will be managing multiple 68 // If doing mega-regions, if we're region zero we will be managing multiple
69 // region terrains since region zero does the physics for the whole mega-region. 69 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; 70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps;
@@ -84,18 +84,18 @@ public class BSTerrainManager
84 // If the parent region (region 0), this is the extent of the combined regions 84 // If the parent region (region 0), this is the extent of the combined regions
85 // relative to the origin of region zero 85 // relative to the origin of region zero
86 private Vector3 m_worldMax; 86 private Vector3 m_worldMax;
87 private PhysicsScene m_parentScene; 87 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
88 88
89 public BSTerrainManager(BSScene physicsScene) 89 public BSTerrainManager(BSScene physicsScene)
90 { 90 {
91 m_physicsScene = physicsScene; 91 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); 92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>();
93 m_terrainModified = false; 93 m_terrainModified = false;
94 94
95 // Assume one region of default size 95 // Assume one region of default size
96 m_worldOffset = Vector3.Zero; 96 m_worldOffset = Vector3.Zero;
97 m_worldMax = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, 4096f); 97 m_worldMax = new Vector3(DefaultRegionSize);
98 m_parentScene = null; 98 MegaRegionParentPhysicsScene = null;
99 } 99 }
100 100
101 // Create the initial instance of terrain and the underlying ground plane. 101 // Create the initial instance of terrain and the underlying ground plane.
@@ -107,10 +107,16 @@ public class BSTerrainManager
107 public void CreateInitialGroundPlaneAndTerrain() 107 public void CreateInitialGroundPlaneAndTerrain()
108 { 108 {
109 // The ground plane is here to catch things that are trying to drop to negative infinity 109 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape(BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN)); 110 BulletShape groundPlaneShape = new BulletShape(
111 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
112 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.Ptr, Vector3.Zero, Quaternion.Identity)); 112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE);
113 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); 113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity));
116 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
117 // Everything collides with the ground plane.
118 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
119 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
114 120
115 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); 121 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE);
116 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); 122 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION);
@@ -126,13 +132,13 @@ public class BSTerrainManager
126 // Release all the terrain structures we might have allocated 132 // Release all the terrain structures we might have allocated
127 public void ReleaseGroundPlaneAndTerrain() 133 public void ReleaseGroundPlaneAndTerrain()
128 { 134 {
129 if (m_groundPlane.Ptr != IntPtr.Zero) 135 if (m_groundPlane.ptr != IntPtr.Zero)
130 { 136 {
131 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, m_groundPlane.Ptr)) 137 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
132 { 138 {
133 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, m_groundPlane.Ptr); 139 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
134 } 140 }
135 m_groundPlane.Ptr = IntPtr.Zero; 141 m_groundPlane.ptr = IntPtr.Zero;
136 } 142 }
137 143
138 ReleaseTerrain(); 144 ReleaseTerrain();
@@ -143,9 +149,9 @@ public class BSTerrainManager
143 { 149 {
144 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) 150 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps)
145 { 151 {
146 if (BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr)) 152 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr))
147 { 153 {
148 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, kvp.Value.terrainBody.Ptr); 154 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
149 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr); 155 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
150 } 156 }
151 } 157 }
@@ -155,19 +161,19 @@ public class BSTerrainManager
155 // The simulator wants to set a new heightmap for the terrain. 161 // The simulator wants to set a new heightmap for the terrain.
156 public void SetTerrain(float[] heightMap) { 162 public void SetTerrain(float[] heightMap) {
157 float[] localHeightMap = heightMap; 163 float[] localHeightMap = heightMap;
158 m_physicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 164 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
159 { 165 {
160 if (m_worldOffset != Vector3.Zero && m_parentScene != null) 166 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
161 { 167 {
162 // If a child of a mega-region, we shouldn't have any terrain allocated for us 168 // If a child of a mega-region, we shouldn't have any terrain allocated for us
163 ReleaseGroundPlaneAndTerrain(); 169 ReleaseGroundPlaneAndTerrain();
164 // If doing the mega-prim stuff and we are the child of the zero region, 170 // If doing the mega-prim stuff and we are the child of the zero region,
165 // the terrain is added to our parent 171 // the terrain is added to our parent
166 if (m_parentScene is BSScene) 172 if (MegaRegionParentPhysicsScene is BSScene)
167 { 173 {
168 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 174 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
169 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 175 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
170 ((BSScene)m_parentScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, 176 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID,
171 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); 177 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true);
172 } 178 }
173 } 179 }
@@ -176,7 +182,8 @@ public class BSTerrainManager
176 // If not doing the mega-prim thing, just change the terrain 182 // If not doing the mega-prim thing, just change the terrain
177 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 183 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
178 184
179 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); 185 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap,
186 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
180 } 187 }
181 }); 188 });
182 } 189 }
@@ -194,10 +201,10 @@ public class BSTerrainManager
194 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 201 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when
195 // calling this routine from initialization or taint-time routines) or whether to delay 202 // calling this routine from initialization or taint-time routines) or whether to delay
196 // all the unmanaged activities to taint-time. 203 // all the unmanaged activities to taint-time.
197 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool doNow) 204 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime)
198 { 205 {
199 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},doNow={3}", 206 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}",
200 BSScene.DetailLogZero, minCoords, maxCoords, doNow); 207 BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime);
201 208
202 float minZ = float.MaxValue; 209 float minZ = float.MaxValue;
203 float maxZ = float.MinValue; 210 float maxZ = float.MinValue;
@@ -227,12 +234,12 @@ public class BSTerrainManager
227 mapInfo.maxZ = maxZ; 234 mapInfo.maxZ = maxZ;
228 mapInfo.sizeX = maxCoords.X - minCoords.X; 235 mapInfo.sizeX = maxCoords.X - minCoords.X;
229 mapInfo.sizeY = maxCoords.Y - minCoords.Y; 236 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
230 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", 237 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
231 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); 238 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
232 239
233 BSScene.TaintCallback rebuildOperation = delegate() 240 BSScene.TaintCallback rebuildOperation = delegate()
234 { 241 {
235 if (m_parentScene != null) 242 if (MegaRegionParentPhysicsScene != null)
236 { 243 {
237 // It's possible that Combine() was called after this code was queued. 244 // It's possible that Combine() was called after this code was queued.
238 // If we are a child of combined regions, we don't create any terrain for us. 245 // If we are a child of combined regions, we don't create any terrain for us.
@@ -245,17 +252,17 @@ public class BSTerrainManager
245 return; 252 return;
246 } 253 }
247 254
248 if (mapInfo.terrainBody.Ptr != IntPtr.Zero) 255 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
249 { 256 {
250 // Updating an existing terrain. 257 // Updating an existing terrain.
251 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", 258 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
252 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); 259 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
253 260
254 // Remove from the dynamics world because we're going to mangle this object 261 // Remove from the dynamics world because we're going to mangle this object
255 BulletSimAPI.RemoveObjectFromWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); 262 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
256 263
257 // Get rid of the old terrain 264 // Get rid of the old terrain
258 BulletSimAPI.DestroyObject2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); 265 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
259 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr); 266 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
260 mapInfo.Ptr = IntPtr.Zero; 267 mapInfo.Ptr = IntPtr.Zero;
261 268
@@ -282,11 +289,11 @@ public class BSTerrainManager
282 // else 289 // else
283 { 290 {
284 // Creating a new terrain. 291 // Creating a new terrain.
285 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}", 292 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
286 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ); 293 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
287 294
288 mapInfo.ID = id; 295 mapInfo.ID = id;
289 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.ID, 296 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
290 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); 297 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
291 298
292 // The terrain object initial position is at the center of the object 299 // The terrain object initial position is at the center of the object
@@ -296,43 +303,49 @@ public class BSTerrainManager
296 centerPos.Z = minZ + ((maxZ - minZ) / 2f); 303 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
297 304
298 // Create the terrain shape from the mapInfo 305 // Create the terrain shape from the mapInfo
299 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr)); 306 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
307 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
300 308
301 mapInfo.terrainBody = new BulletBody(mapInfo.ID, 309 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
302 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.Ptr, 310 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
303 centerPos, Quaternion.Identity)); 311 id, centerPos, Quaternion.Identity));
304 } 312 }
305 313
306 // Make sure the entry is in the heightmap table 314 // Make sure the entry is in the heightmap table
307 m_heightMaps[terrainRegionBase] = mapInfo; 315 m_heightMaps[terrainRegionBase] = mapInfo;
308 316
309 // Set current terrain attributes 317 // Set current terrain attributes
310 BulletSimAPI.SetFriction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainFriction); 318 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
311 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainHitFraction); 319 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
312 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.Ptr, m_physicsScene.Params.terrainRestitution); 320 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
313 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.Ptr, CollisionFlags.CF_STATIC_OBJECT); 321 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
314 322
315 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.Ptr, 0f, Vector3.Zero); 323 BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero);
316 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.Ptr); 324 BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr);
317 325
318 // Return the new terrain to the world of physical objects 326 // Return the new terrain to the world of physical objects
319 BulletSimAPI.AddObjectToWorld2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); 327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
320 328
321 // redo its bounding box now that it is in the world 329 // redo its bounding box now that it is in the world
322 BulletSimAPI.UpdateSingleAabb2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr); 330 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
331
332 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
333 (uint)CollisionFilterGroups.TerrainFilter,
334 (uint)CollisionFilterGroups.TerrainMask);
323 335
324 // Make sure the new shape is processed. 336 // Make sure the new shape is processed.
325 BulletSimAPI.Activate2(mapInfo.terrainBody.Ptr, true); 337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
326 339
327 m_terrainModified = true; 340 m_terrainModified = true;
328 }; 341 };
329 342
330 // There is the option to do the changes now (we're already in 'taint time'), or 343 // There is the option to do the changes now (we're already in 'taint time'), or
331 // to do the Bullet operations later. 344 // to do the Bullet operations later.
332 if (doNow) 345 if (atTaintTime)
333 rebuildOperation(); 346 rebuildOperation();
334 else 347 else
335 m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); 348 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
336 } 349 }
337 else 350 else
338 { 351 {
@@ -348,7 +361,7 @@ public class BSTerrainManager
348 Vector3 minCoordsX = minCoords; 361 Vector3 minCoordsX = minCoords;
349 Vector3 maxCoordsX = maxCoords; 362 Vector3 maxCoordsX = maxCoords;
350 363
351 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 364 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
352 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 365 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
353 366
354 // Code that must happen at taint-time 367 // Code that must happen at taint-time
@@ -357,7 +370,7 @@ public class BSTerrainManager
357 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); 370 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y);
358 // Create a new mapInfo that will be filled with the new info 371 // Create a new mapInfo that will be filled with the new info
359 mapInfo = new BulletHeightMapInfo(id, heightMapX, 372 mapInfo = new BulletHeightMapInfo(id, heightMapX,
360 BulletSimAPI.CreateHeightMapInfo2(m_physicsScene.World.Ptr, newTerrainID, 373 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID,
361 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN)); 374 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
362 // Put the unfilled heightmap info into the collection of same 375 // Put the unfilled heightmap info into the collection of same
363 m_heightMaps.Add(terrainRegionBase, mapInfo); 376 m_heightMaps.Add(terrainRegionBase, mapInfo);
@@ -368,10 +381,10 @@ public class BSTerrainManager
368 }; 381 };
369 382
370 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. 383 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
371 if (doNow) 384 if (atTaintTime)
372 createOperation(); 385 createOperation();
373 else 386 else
374 m_physicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); 387 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
375 } 388 }
376 } 389 }
377 390
@@ -419,7 +432,7 @@ public class BSTerrainManager
419 catch 432 catch
420 { 433 {
421 // Sometimes they give us wonky values of X and Y. Give a warning and return something. 434 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
422 m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}", 435 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
423 LogHeader, terrainBaseXY, regionX, regionY); 436 LogHeader, terrainBaseXY, regionX, regionY);
424 ret = HEIGHT_GETHEIGHT_RET; 437 ret = HEIGHT_GETHEIGHT_RET;
425 } 438 }
@@ -428,8 +441,8 @@ public class BSTerrainManager
428 } 441 }
429 else 442 else
430 { 443 {
431 m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 444 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
432 LogHeader, m_physicsScene.RegionName, tX, tY); 445 LogHeader, PhysicsScene.RegionName, tX, tY);
433 } 446 }
434 m_terrainModified = false; 447 m_terrainModified = false;
435 lastHeight = ret; 448 lastHeight = ret;
@@ -441,7 +454,7 @@ public class BSTerrainManager
441 { 454 {
442 return true; 455 return true;
443 } 456 }
444 457
445 // This routine is called two ways: 458 // This routine is called two ways:
446 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum 459 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
447 // extent of the combined regions. This is to inform the parent of the size 460 // extent of the combined regions. This is to inform the parent of the size
@@ -453,14 +466,14 @@ public class BSTerrainManager
453 { 466 {
454 m_worldOffset = offset; 467 m_worldOffset = offset;
455 m_worldMax = extents; 468 m_worldMax = extents;
456 m_parentScene = pScene; 469 MegaRegionParentPhysicsScene = pScene;
457 if (pScene != null) 470 if (pScene != null)
458 { 471 {
459 // We are a child. 472 // We are a child.
460 // We want m_worldMax to be the highest coordinate of our piece of terrain. 473 // We want m_worldMax to be the highest coordinate of our piece of terrain.
461 m_worldMax = offset + DefaultRegionSize; 474 m_worldMax = offset + DefaultRegionSize;
462 } 475 }
463 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", 476 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
464 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); 477 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
465 } 478 }
466 479
@@ -474,7 +487,7 @@ public class BSTerrainManager
474 487
475 private void DetailLog(string msg, params Object[] args) 488 private void DetailLog(string msg, params Object[] args)
476 { 489 {
477 m_physicsScene.PhysicsLogging.Write(msg, args); 490 PhysicsScene.PhysicsLogging.Write(msg, args);
478 } 491 }
479} 492}
480} 493}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 9221cdb..1125d7e 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -38,35 +38,112 @@ namespace OpenSim.Region.Physics.BulletSPlugin {
38// The physics engine controller class created at initialization 38// The physics engine controller class created at initialization
39public struct BulletSim 39public struct BulletSim
40{ 40{
41 public BulletSim(uint worldId, BSScene bss, IntPtr xx) { worldID = worldId; scene = bss; Ptr = xx; } 41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
42 public uint worldID; 48 public uint worldID;
43 // The scene is only in here so very low level routines have a handle to print debug/error messages 49 // The scene is only in here so very low level routines have a handle to print debug/error messages
44 public BSScene scene; 50 public BSScene physicsScene;
45 public IntPtr Ptr; 51}
52
53// An allocated Bullet btRigidBody
54public struct BulletBody
55{
56 public BulletBody(uint id, IntPtr xx)
57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 && collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
46} 84}
47 85
48public struct BulletShape 86public struct BulletShape
49{ 87{
50 public BulletShape(IntPtr xx) { Ptr = xx; } 88 public BulletShape(IntPtr xx)
51 public IntPtr Ptr; 89 {
90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type;
104 public ulong shapeKey;
105 public bool isNativeShape;
106 // Hulls have an underlying mesh. A pointer to it is hidden here.
107 public override string ToString()
108 {
109 StringBuilder buff = new StringBuilder();
110 buff.Append("<p=");
111 buff.Append(ptr.ToString("X"));
112 buff.Append(",s=");
113 buff.Append(type.ToString());
114 buff.Append(",k=");
115 buff.Append(shapeKey.ToString("X"));
116 buff.Append(",n=");
117 buff.Append(isNativeShape.ToString());
118 buff.Append(">");
119 return buff.ToString();
120 }
52} 121}
53 122
54// An allocated Bullet btRigidBody 123 // Constraint type values as defined by Bullet
55public struct BulletBody 124public enum ConstraintType : int
56{ 125{
57 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } 126 POINT2POINT_CONSTRAINT_TYPE = 3,
58 public IntPtr Ptr; 127 HINGE_CONSTRAINT_TYPE,
59 public uint ID; 128 CONETWIST_CONSTRAINT_TYPE,
129 D6_CONSTRAINT_TYPE,
130 SLIDER_CONSTRAINT_TYPE,
131 CONTACT_CONSTRAINT_TYPE,
132 D6_SPRING_CONSTRAINT_TYPE,
133 MAX_CONSTRAINT_TYPE
60} 134}
61 135
62// An allocated Bullet btConstraint 136// An allocated Bullet btConstraint
63public struct BulletConstraint 137public struct BulletConstraint
64{ 138{
65 public BulletConstraint(IntPtr xx) { Ptr = xx; } 139 public BulletConstraint(IntPtr xx)
66 public IntPtr Ptr; 140 {
141 ptr = xx;
142 }
143 public IntPtr ptr;
67} 144}
68 145
69// An allocated HeightMapThing which hold various heightmap info 146// An allocated HeightMapThing which holds various heightmap info.
70// Made a class rather than a struct so there would be only one 147// Made a class rather than a struct so there would be only one
71// instance of this and C# will pass around pointers rather 148// instance of this and C# will pass around pointers rather
72// than making copies. 149// than making copies.
@@ -96,14 +173,14 @@ public class BulletHeightMapInfo
96 173
97// =============================================================================== 174// ===============================================================================
98[StructLayout(LayoutKind.Sequential)] 175[StructLayout(LayoutKind.Sequential)]
99public struct ConvexHull 176public struct ConvexHull
100{ 177{
101 Vector3 Offset; 178 Vector3 Offset;
102 int VertexCount; 179 int VertexCount;
103 Vector3[] Vertices; 180 Vector3[] Vertices;
104} 181}
105[StructLayout(LayoutKind.Sequential)] 182[StructLayout(LayoutKind.Sequential)]
106public struct ShapeData 183public struct ShapeData
107{ 184{
108 public enum PhysicsShapeType 185 public enum PhysicsShapeType
109 { 186 {
@@ -114,7 +191,9 @@ public struct ShapeData
114 SHAPE_CYLINDER = 4, 191 SHAPE_CYLINDER = 4,
115 SHAPE_SPHERE = 5, 192 SHAPE_SPHERE = 5,
116 SHAPE_MESH = 6, 193 SHAPE_MESH = 6,
117 SHAPE_HULL = 7 194 SHAPE_HULL = 7,
195 SHAPE_GROUNDPLANE = 8,
196 SHAPE_TERRAIN = 9,
118 }; 197 };
119 public uint ID; 198 public uint ID;
120 public PhysicsShapeType Type; 199 public PhysicsShapeType Type;
@@ -130,13 +209,24 @@ public struct ShapeData
130 public float Restitution; 209 public float Restitution;
131 public float Collidable; // true of things bump into this 210 public float Collidable; // true of things bump into this
132 public float Static; // true if a static object. Otherwise gravity, etc. 211 public float Static; // true if a static object. Otherwise gravity, etc.
212 public float Solid; // true if object cannot be passed through
213 public Vector3 Size;
133 214
134 // note that bools are passed as floats since bool size changes by language and architecture 215 // note that bools are passed as floats since bool size changes by language and architecture
135 public const float numericTrue = 1f; 216 public const float numericTrue = 1f;
136 public const float numericFalse = 0f; 217 public const float numericFalse = 0f;
218
219 // The native shapes have predefined shape hash keys
220 public enum FixedShapeKey : ulong
221 {
222 KEY_BOX = 1,
223 KEY_SPHERE = 2,
224 KEY_CONE = 3,
225 KEY_CYLINDER = 4,
226 }
137} 227}
138[StructLayout(LayoutKind.Sequential)] 228[StructLayout(LayoutKind.Sequential)]
139public struct SweepHit 229public struct SweepHit
140{ 230{
141 public uint ID; 231 public uint ID;
142 public float Fraction; 232 public float Fraction;
@@ -227,7 +317,17 @@ public enum ActivationState : uint
227 ISLAND_SLEEPING, 317 ISLAND_SLEEPING,
228 WANTS_DEACTIVATION, 318 WANTS_DEACTIVATION,
229 DISABLE_DEACTIVATION, 319 DISABLE_DEACTIVATION,
230 DISABLE_SIMULATION 320 DISABLE_SIMULATION,
321}
322
323public enum CollisionObjectTypes : int
324{
325 CO_COLLISION_OBJECT = 1 << 0,
326 CO_RIGID_BODY = 1 << 1,
327 CO_GHOST_OBJECT = 1 << 2,
328 CO_SOFT_BODY = 1 << 3,
329 CO_HF_FLUID = 1 << 4,
330 CO_USER_TYPE = 1 << 5,
231} 331}
232 332
233// Values used by Bullet and BulletSim to control object properties. 333// Values used by Bullet and BulletSim to control object properties.
@@ -244,77 +344,60 @@ public enum CollisionFlags : uint
244 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 344 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
245 // Following used by BulletSim to control collisions 345 // Following used by BulletSim to control collisions
246 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 346 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
247 BS_VOLUME_DETECT_OBJECT = 1 << 11, 347 // BS_VOLUME_DETECT_OBJECT = 1 << 11,
248 BS_PHANTOM_OBJECT = 1 << 12, 348 // BS_PHANTOM_OBJECT = 1 << 12,
249 BS_PHYSICAL_OBJECT = 1 << 13, 349 // BS_PHYSICAL_OBJECT = 1 << 13,
250 BS_TERRAIN_OBJECT = 1 << 14, 350 // BS_TERRAIN_OBJECT = 1 << 14,
251 BS_NONE = 0, 351 BS_NONE = 0,
252 BS_ALL = 0xFFFFFFFF 352 BS_ALL = 0xFFFFFFFF,
353
354 // These are the collision flags switched depending on physical state.
355 // The other flags are used for other things and should not be fooled with.
356 BS_ACTIVE = CF_STATIC_OBJECT
357 | CF_KINEMATIC_OBJECT
358 | CF_NO_CONTACT_RESPONSE
359 // | BS_VOLUME_DETECT_OBJECT
360 // | BS_PHANTOM_OBJECT
361 // | BS_PHYSICAL_OBJECT,
253}; 362};
254 363
255// Values for collisions groups and masks 364// Values for collisions groups and masks
256public enum CollisionFilterGroups : uint 365public enum CollisionFilterGroups : uint
257{ 366{
258 NoneFilter = 0, 367 // Don't use the bit definitions!! Define the use in a
259 DefaultFilter = 1 << 0, 368 // filter/mask definition below. This way collision interactions
260 StaticFilter = 1 << 1, 369 // are more easily debugged.
261 KinematicFilter = 1 << 2, 370 BNoneFilter = 0,
262 DebrisFilter = 1 << 3, 371 BDefaultFilter = 1 << 0,
263 SensorTrigger = 1 << 4, 372 BStaticFilter = 1 << 1,
264 CharacterFilter = 1 << 5, 373 BKinematicFilter = 1 << 2,
265 AllFilter = 0xFFFFFFFF, 374 BDebrisFilter = 1 << 3,
375 BSensorTrigger = 1 << 4,
376 BCharacterFilter = 1 << 5,
377 BAllFilter = 0xFFFFFFFF,
266 // Filter groups defined by BulletSim 378 // Filter groups defined by BulletSim
267 GroundPlaneFilter = 1 << 10, 379 BGroundPlaneFilter = 1 << 10,
268 TerrainFilter = 1 << 11, 380 BTerrainFilter = 1 << 11,
269 RaycastFilter = 1 << 12, 381 BRaycastFilter = 1 << 12,
270 SolidFilter = 1 << 13, 382 BSolidFilter = 1 << 13,
271}; 383
384 // The collsion filters and masked are defined in one place -- don't want them scattered
385 AvatarFilter = BCharacterFilter,
386 AvatarMask = BAllFilter,
387 ObjectFilter = BSolidFilter,
388 ObjectMask = BAllFilter,
389 StaticObjectFilter = BStaticFilter,
390 StaticObjectMask = BAllFilter,
391 VolumeDetectFilter = BSensorTrigger,
392 VolumeDetectMask = ~BSensorTrigger,
393 TerrainFilter = BTerrainFilter,
394 TerrainMask = BAllFilter & ~BStaticFilter,
395 GroundPlaneFilter = BAllFilter,
396 GroundPlaneMask = BAllFilter
272 397
273 // For each type, we first clear and then set the collision flags 398};
274public enum ClearCollisionFlag : uint
275{
276 Terrain = CollisionFlags.BS_ALL,
277 Phantom = CollisionFlags.BS_ALL,
278 VolumeDetect = CollisionFlags.BS_ALL,
279 PhysicalObject = CollisionFlags.BS_ALL,
280 StaticObject = CollisionFlags.BS_ALL
281}
282 399
283public enum SetCollisionFlag : uint
284{
285 Terrain = CollisionFlags.CF_STATIC_OBJECT
286 | CollisionFlags.BS_TERRAIN_OBJECT,
287 Phantom = CollisionFlags.CF_STATIC_OBJECT
288 | CollisionFlags.BS_PHANTOM_OBJECT
289 | CollisionFlags.CF_NO_CONTACT_RESPONSE,
290 VolumeDetect = CollisionFlags.CF_STATIC_OBJECT
291 | CollisionFlags.BS_VOLUME_DETECT_OBJECT
292 | CollisionFlags.CF_NO_CONTACT_RESPONSE,
293 PhysicalObject = CollisionFlags.BS_PHYSICAL_OBJECT,
294 StaticObject = CollisionFlags.CF_STATIC_OBJECT,
295}
296 400
297// Collision filters used for different types of objects
298public enum SetCollisionFilter : uint
299{
300 Terrain = CollisionFilterGroups.AllFilter,
301 Phantom = CollisionFilterGroups.GroundPlaneFilter
302 | CollisionFilterGroups.TerrainFilter,
303 VolumeDetect = CollisionFilterGroups.AllFilter,
304 PhysicalObject = CollisionFilterGroups.AllFilter,
305 StaticObject = CollisionFilterGroups.AllFilter,
306}
307
308// Collision masks used for different types of objects
309public enum SetCollisionMask : uint
310{
311 Terrain = CollisionFilterGroups.AllFilter,
312 Phantom = CollisionFilterGroups.GroundPlaneFilter
313 | CollisionFilterGroups.TerrainFilter,
314 VolumeDetect = CollisionFilterGroups.AllFilter,
315 PhysicalObject = CollisionFilterGroups.AllFilter,
316 StaticObject = CollisionFilterGroups.AllFilter
317}
318 401
319// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 402// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
320// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. 403// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
@@ -350,8 +433,8 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg
350public static extern string GetVersion(); 433public static extern string GetVersion();
351 434
352[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
353public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 436public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
354 int maxCollisions, IntPtr collisionArray, 437 int maxCollisions, IntPtr collisionArray,
355 int maxUpdates, IntPtr updateArray, 438 int maxUpdates, IntPtr updateArray,
356 DebugLogCallback logRoutine); 439 DebugLogCallback logRoutine);
357 440
@@ -370,19 +453,19 @@ public static extern bool UpdateParameter(uint worldID, uint localID,
370 453
371// =============================================================================== 454// ===============================================================================
372[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 455[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
373public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 456public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
374 out int updatedEntityCount, 457 out int updatedEntityCount,
375 out IntPtr updatedEntitiesPtr, 458 out IntPtr updatedEntitiesPtr,
376 out int collidersCount, 459 out int collidersCount,
377 out IntPtr collidersPtr); 460 out IntPtr collidersPtr);
378 461
379[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 462[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
380public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 463public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
381 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls 464 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
382 ); 465 );
383 466
384[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 467[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
385public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 468public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
386 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 469 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
387 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices 470 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
388 ); 471 );
@@ -496,7 +579,7 @@ public static extern void Shutdown2(IntPtr sim);
496 579
497[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 580[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
498public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 581public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
499 out int updatedEntityCount, 582 out int updatedEntityCount,
500 out IntPtr updatedEntitiesPtr, 583 out IntPtr updatedEntitiesPtr,
501 out int collidersCount, 584 out int collidersCount,
502 out IntPtr collidersPtr); 585 out IntPtr collidersPtr);
@@ -507,8 +590,8 @@ public static extern bool PushUpdate2(IntPtr obj);
507// ===================================================================================== 590// =====================================================================================
508// Mesh, hull, shape and body creation helper routines 591// Mesh, hull, shape and body creation helper routines
509[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
510public static extern IntPtr CreateMeshShape2(IntPtr world, 593public static extern IntPtr CreateMeshShape2(IntPtr world,
511 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 594 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
512 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); 595 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
513 596
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 597[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -516,11 +599,10 @@ public static extern IntPtr CreateHullShape2(IntPtr world,
516 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); 599 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
517 600
518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
519public static extern IntPtr BuildHullShape2(IntPtr world, IntPtr meshShape); 602public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
520 603
521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
522public static extern IntPtr BuildNativeShape2(IntPtr world, 605public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
523 float shapeType, float collisionMargin, Vector3 scale);
524 606
525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
526public static extern bool IsNativeShape2(IntPtr shape); 608public static extern bool IsNativeShape2(IntPtr shape);
@@ -535,16 +617,25 @@ public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShap
535public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 617public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
536 618
537[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
538public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, IntPtr constructionInfo); 620public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
621
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
539 624
540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
541public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); 626public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
542 627
543[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
544public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, Vector3 pos, Quaternion rot); 629public static extern int GetBodyType2(IntPtr obj);
630
631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
632public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
545 633
546[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
547public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, Vector3 pos, Quaternion rot); 635public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
636
637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
638public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
548 639
549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
550public static extern IntPtr AllocateBodyInfo2(IntPtr obj); 641public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
@@ -558,11 +649,11 @@ public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
558// ===================================================================================== 649// =====================================================================================
559// Terrain creation and helper routines 650// Terrain creation and helper routines
560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
561public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords, 652public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
562 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); 653 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
563 654
564[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
565public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords, 656public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
566 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin); 657 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
567 658
568[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 659[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -600,7 +691,7 @@ public static extern void SetConstraintEnable2(IntPtr constrain, float numericTr
600public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 691public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
601 692
602[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
603public static extern bool SetFrames2(IntPtr constrain, 694public static extern bool SetFrames2(IntPtr constrain,
604 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); 695 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
605 696
606[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 697[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -963,6 +1054,9 @@ public static extern Vector3 GetPushVelocity2(IntPtr obj);
963[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1054[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
964public static extern Vector3 GetTurnVelocity2(IntPtr obj); 1055public static extern Vector3 GetTurnVelocity2(IntPtr obj);
965 1056
1057[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1058public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
1059
966// ===================================================================================== 1060// =====================================================================================
967// btCollisionShape entries 1061// btCollisionShape entries
968 1062
@@ -1014,9 +1108,6 @@ public static extern void SetMargin2(IntPtr shape, float val);
1014[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1108[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1015public static extern float GetMargin2(IntPtr shape); 1109public static extern float GetMargin2(IntPtr shape);
1016 1110
1017[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1018public static extern void SetCollisionFilterMask(IntPtr shape, uint filter, uint mask);
1019
1020// ===================================================================================== 1111// =====================================================================================
1021// Debugging 1112// Debugging
1022[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1113[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]