aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs206
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs18
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs)13
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs)4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs733
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs474
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs275
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs327
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs104
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs53
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs445
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs244
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs497
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs208
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs170
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs321
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs256
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs242
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs33
20 files changed, 3146 insertions, 1481 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 623ac8f..4c195e1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -34,7 +34,7 @@ using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : BSPhysObject 37public sealed class BSCharacter : BSPhysObject
38{ 38{
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]";
@@ -78,11 +78,17 @@ public class BSCharacter : BSPhysObject
78 private float _PIDHoverTao; 78 private float _PIDHoverTao;
79 79
80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
81 : base(parent_scene, localID, avName, "BSCharacter")
81 { 82 {
82 base.BaseInitialize(parent_scene, localID, avName, "BSCharacter");
83 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 84 _position = pos;
85
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
85 _size = size; 88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
86 _flying = isFlying; 92 _flying = isFlying;
87 _orientation = OMV.Quaternion.Identity; 93 _orientation = OMV.Quaternion.Identity;
88 _velocity = OMV.Vector3.Zero; 94 _velocity = OMV.Vector3.Zero;
@@ -97,28 +103,14 @@ public class BSCharacter : BSPhysObject
97 // set _avatarVolume and _mass based on capsule size, _density and Scale 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
98 ComputeAvatarVolumeAndMass(); 104 ComputeAvatarVolumeAndMass();
99 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
100 LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw); 106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
101
102 ShapeData shapeData = new ShapeData();
103 shapeData.ID = LocalID;
104 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
105 shapeData.Position = _position;
106 shapeData.Rotation = _orientation;
107 shapeData.Velocity = _velocity;
108 shapeData.Size = Scale;
109 shapeData.Scale = Scale;
110 shapeData.Mass = _mass;
111 shapeData.Buoyancy = _buoyancy;
112 shapeData.Static = ShapeData.numericFalse;
113 shapeData.Friction = PhysicsScene.Params.avatarStandingFriction;
114 shapeData.Restitution = PhysicsScene.Params.avatarRestitution;
115 107
116 // do actual create at taint time 108 // do actual create at taint time
117 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 109 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
118 { 110 {
119 DetailLog("{0},BSCharacter.create,taint", LocalID); 111 DetailLog("{0},BSCharacter.create,taint", LocalID);
120 // New body and shape into BSBody and BSShape 112 // New body and shape into PhysBody and PhysShape
121 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null); 113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
122 114
123 SetPhysicalProperties(); 115 SetPhysicalProperties();
124 }); 116 });
@@ -131,41 +123,50 @@ public class BSCharacter : BSPhysObject
131 DetailLog("{0},BSCharacter.Destroy", LocalID); 123 DetailLog("{0},BSCharacter.Destroy", LocalID);
132 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
133 { 125 {
134 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); 126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
135 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); 127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
136 }); 128 });
137 } 129 }
138 130
139 private void SetPhysicalProperties() 131 private void SetPhysicalProperties()
140 { 132 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); 133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
142 134
143 ZeroMotion(); 135 ZeroMotion(true);
144 ForcePosition = _position; 136 ForcePosition = _position;
145 // Set the velocity and compute the proper friction 137 // Set the velocity and compute the proper friction
146 ForceVelocity = _velocity; 138 ForceVelocity = _velocity;
147 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); 139
148 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); 140 // This will enable or disable the flying buoyancy of the avatar.
149 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying;
143
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
150 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 148 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
151 { 149 {
152 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
153 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
154 } 152 }
155 153
156 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); 154 UpdatePhysicalMassProperties(RawMass);
157 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); 155
156 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
158 158
159 BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160 160
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); 161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
162 162
163 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); 164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
165 166
166 // Do this after the object has been added to the world 167 // Do this after the object has been added to the world
167 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, 168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
168 (uint)CollisionFilterGroups.AvatarFilter, 169 (uint)CollisionFilterGroups.AvatarFilter,
169 (uint)CollisionFilterGroups.AvatarMask); 170 (uint)CollisionFilterGroups.AvatarMask);
170 } 171 }
171 172
@@ -175,6 +176,7 @@ public class BSCharacter : BSPhysObject
175 } 176 }
176 // No one calls this method so I don't know what it could possibly mean 177 // No one calls this method so I don't know what it could possibly mean
177 public override bool Stopped { get { return false; } } 178 public override bool Stopped { get { return false; } }
179
178 public override OMV.Vector3 Size { 180 public override OMV.Vector3 Size {
179 get 181 get
180 { 182 {
@@ -187,23 +189,29 @@ public class BSCharacter : BSPhysObject
187 _size = value; 189 _size = value;
188 ComputeAvatarScale(_size); 190 ComputeAvatarScale(_size);
189 ComputeAvatarVolumeAndMass(); 191 ComputeAvatarVolumeAndMass();
190 DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", 192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
191 LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw); 193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
192 194
193 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
194 { 196 {
195 BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); 197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
196 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); 198 UpdatePhysicalMassProperties(RawMass);
197 BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia);
198 }); 199 });
199 200
200 } 201 }
201 } 202 }
203
202 public override OMV.Vector3 Scale { get; set; } 204 public override OMV.Vector3 Scale { get; set; }
205
203 public override PrimitiveBaseShape Shape 206 public override PrimitiveBaseShape Shape
204 { 207 {
205 set { BaseShape = value; } 208 set { BaseShape = value; }
206 } 209 }
210 // I want the physics engine to make an avatar capsule
211 public override BSPhysicsShapeType PreferredPhysicalShape
212 {
213 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
214 }
207 215
208 public override bool Grabbed { 216 public override bool Grabbed {
209 set { _grabbed = value; } 217 set { _grabbed = value; }
@@ -219,23 +227,42 @@ public class BSCharacter : BSPhysObject
219 // Do it to the properties so the values get set in the physics engine. 227 // Do it to the properties so the values get set in the physics engine.
220 // Push the setting of the values to the viewer. 228 // Push the setting of the values to the viewer.
221 // Called at taint time! 229 // Called at taint time!
222 public override void ZeroMotion() 230 public override void ZeroMotion(bool inTaintTime)
223 { 231 {
224 _velocity = OMV.Vector3.Zero; 232 _velocity = OMV.Vector3.Zero;
225 _acceleration = OMV.Vector3.Zero; 233 _acceleration = OMV.Vector3.Zero;
226 _rotationalVelocity = OMV.Vector3.Zero; 234 _rotationalVelocity = OMV.Vector3.Zero;
227 235
228 // Zero some other properties directly into the physics engine 236 // Zero some other properties directly into the physics engine
229 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero); 237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
230 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero); 238 {
231 BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); 239 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
232 BulletSimAPI.ClearForces2(BSBody.ptr); 240 });
233 } 241 }
242 public override void ZeroAngularMotion(bool inTaintTime)
243 {
244 _rotationalVelocity = OMV.Vector3.Zero;
245
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
250 // The next also get rid of applied linear force but the linear velocity is untouched.
251 BulletSimAPI.ClearForces2(PhysBody.ptr);
252 });
253 }
254
234 255
235 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 256 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
236 257
258 public override OMV.Vector3 RawPosition
259 {
260 get { return _position; }
261 set { _position = value; }
262 }
237 public override OMV.Vector3 Position { 263 public override OMV.Vector3 Position {
238 get { 264 get {
265 // Don't refetch the position because this function is called a zillion times
239 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
240 return _position; 267 return _position;
241 } 268 }
@@ -246,30 +273,30 @@ public class BSCharacter : BSPhysObject
246 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
247 { 274 {
248 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
249 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
250 }); 277 });
251 } 278 }
252 } 279 }
253 public override OMV.Vector3 ForcePosition { 280 public override OMV.Vector3 ForcePosition {
254 get { 281 get {
255 _position = BulletSimAPI.GetPosition2(BSBody.ptr); 282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
256 return _position; 283 return _position;
257 } 284 }
258 set { 285 set {
259 _position = value; 286 _position = value;
260 PositionSanityCheck(); 287 PositionSanityCheck();
261 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
262 } 289 }
263 } 290 }
264 291
265 292
266 // Check that the current position is sane and, if not, modify the position to make it so. 293 // Check that the current position is sane and, if not, modify the position to make it so.
267 // Check for being below terrain and being out of bounds. 294 // Check for being below terrain or on water.
268 // Returns 'true' of the position was made sane by some action. 295 // Returns 'true' of the position was made sane by some action.
269 private bool PositionSanityCheck() 296 private bool PositionSanityCheck()
270 { 297 {
271 bool ret = false; 298 bool ret = false;
272 299
273 // If below the ground, move the avatar up 300 // If below the ground, move the avatar up
274 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
275 if (Position.Z < terrainHeight) 302 if (Position.Z < terrainHeight)
@@ -302,15 +329,11 @@ public class BSCharacter : BSPhysObject
302 { 329 {
303 // The new position value must be pushed into the physics engine but we can't 330 // The new position value must be pushed into the physics engine but we can't
304 // just assign to "Position" because of potential call loops. 331 // just assign to "Position" because of potential call loops.
305 BSScene.TaintCallback sanityOperation = delegate() 332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
306 { 333 {
307 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
308 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
309 }; 336 });
310 if (inTaintTime)
311 sanityOperation();
312 else
313 PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation);
314 ret = true; 337 ret = true;
315 } 338 }
316 return ret; 339 return ret;
@@ -319,7 +342,14 @@ public class BSCharacter : BSPhysObject
319 public override float Mass { get { return _mass; } } 342 public override float Mass { get { return _mass; } }
320 343
321 // used when we only want this prim's mass and not the linkset thing 344 // used when we only want this prim's mass and not the linkset thing
322 public override float MassRaw { get {return _mass; } } 345 public override float RawMass {
346 get {return _mass; }
347 }
348 public override void UpdatePhysicalMassProperties(float physMass)
349 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
352 }
323 353
324 public override OMV.Vector3 Force { 354 public override OMV.Vector3 Force {
325 get { return _force; } 355 get { return _force; }
@@ -329,13 +359,13 @@ public class BSCharacter : BSPhysObject
329 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
330 { 360 {
331 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
332 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
333 }); 363 });
334 } 364 }
335 } 365 }
336 366
337 // Avatars don't do vehicles 367 // Avatars don't do vehicles
338 public override int VehicleType { get { return 0; } set { return; } } 368 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
339 public override void VehicleFloatParam(int param, float value) { } 369 public override void VehicleFloatParam(int param, float value) { }
340 public override void VehicleVectorParam(int param, OMV.Vector3 value) {} 370 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
341 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } 371 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
@@ -368,7 +398,7 @@ public class BSCharacter : BSPhysObject
368 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
369 { 399 {
370 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 400 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
371 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); 401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
372 } 402 }
373 } 403 }
374 else 404 else
@@ -376,15 +406,15 @@ public class BSCharacter : BSPhysObject
376 if (_currentFriction != PhysicsScene.Params.avatarFriction) 406 if (_currentFriction != PhysicsScene.Params.avatarFriction)
377 { 407 {
378 _currentFriction = PhysicsScene.Params.avatarFriction; 408 _currentFriction = PhysicsScene.Params.avatarFriction;
379 BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); 409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
380 } 410 }
381 } 411 }
382 _velocity = value; 412 _velocity = value;
383 // Remember the set velocity so we can suppress the reduction by friction, ... 413 // Remember the set velocity so we can suppress the reduction by friction, ...
384 _appliedVelocity = value; 414 _appliedVelocity = value;
385 415
386 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
387 BulletSimAPI.Activate2(BSBody.ptr, true); 417 BulletSimAPI.Activate2(PhysBody.ptr, true);
388 } 418 }
389 } 419 }
390 public override OMV.Vector3 Torque { 420 public override OMV.Vector3 Torque {
@@ -401,6 +431,11 @@ public class BSCharacter : BSPhysObject
401 get { return _acceleration; } 431 get { return _acceleration; }
402 set { _acceleration = value; } 432 set { _acceleration = value; }
403 } 433 }
434 public override OMV.Quaternion RawOrientation
435 {
436 get { return _orientation; }
437 set { _orientation = value; }
438 }
404 public override OMV.Quaternion Orientation { 439 public override OMV.Quaternion Orientation {
405 get { return _orientation; } 440 get { return _orientation; }
406 set { 441 set {
@@ -409,22 +444,22 @@ public class BSCharacter : BSPhysObject
409 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
410 { 445 {
411 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
412 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
413 }); 448 });
414 } 449 }
415 } 450 }
416 // Go directly to Bullet to get/set the value. 451 // Go directly to Bullet to get/set the value.
417 public override OMV.Quaternion ForceOrientation 452 public override OMV.Quaternion ForceOrientation
418 { 453 {
419 get 454 get
420 { 455 {
421 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); 456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
422 return _orientation; 457 return _orientation;
423 } 458 }
424 set 459 set
425 { 460 {
426 _orientation = value; 461 _orientation = value;
427 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
428 } 463 }
429 } 464 }
430 public override int PhysicsActorType { 465 public override int PhysicsActorType {
@@ -478,14 +513,14 @@ public class BSCharacter : BSPhysObject
478 set { _collidingObj = value; } 513 set { _collidingObj = value; }
479 } 514 }
480 public override bool FloatOnWater { 515 public override bool FloatOnWater {
481 set { 516 set {
482 _floatOnWater = value; 517 _floatOnWater = value;
483 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
484 { 519 {
485 if (_floatOnWater) 520 if (_floatOnWater)
486 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
487 else 522 else
488 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
489 }); 524 });
490 } 525 }
491 } 526 }
@@ -518,7 +553,7 @@ public class BSCharacter : BSPhysObject
518 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
519 // Buoyancy is faked by changing the gravity applied to the object 554 // Buoyancy is faked by changing the gravity applied to the object
520 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
521 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); 556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
522 } 557 }
523 } 558 }
524 559
@@ -564,7 +599,7 @@ public class BSCharacter : BSPhysObject
564 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() 599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
565 { 600 {
566 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
567 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
568 }); 603 });
569 } 604 }
570 else 605 else
@@ -584,14 +619,19 @@ public class BSCharacter : BSPhysObject
584 // The 'size' given by the simulator is the mid-point of the avatar 619 // The 'size' given by the simulator is the mid-point of the avatar
585 // and X and Y are unspecified. 620 // and X and Y are unspecified.
586 621
587 OMV.Vector3 newScale = OMV.Vector3.Zero; 622 OMV.Vector3 newScale = size;
588 newScale.X = PhysicsScene.Params.avatarCapsuleRadius; 623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
589 newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; 624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
625
626 // From the total height, remove the capsule half spheres that are at each end
627 // The 1.15f came from ODE. Not sure what this factors in.
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
629
630 // The total scale height is the central cylindar plus the caps on the two ends.
631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
590 632
591 // From the total height, remote the capsule half spheres that are at each end 633 // Convert diameters to radii and height to half height -- the way Bullet expects it.
592 newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y); 634 Scale = newScale / 2f;
593 // newScale.Z = (size.Z * 2f);
594 Scale = newScale;
595 } 635 }
596 636
597 // set _avatarVolume and _mass based on capsule size, _density and Scale 637 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -633,10 +673,10 @@ public class BSCharacter : BSPhysObject
633 // That's just the way they are defined. 673 // That's just the way they are defined.
634 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); 674 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
635 _velocity = avVel; 675 _velocity = avVel;
636 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); 676 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
637 } 677 }
638 678
639 // Tell the linkset about this 679 // Tell the linkset about value changes
640 Linkset.UpdateProperties(this); 680 Linkset.UpdateProperties(this);
641 681
642 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index a20be3a..65fac00 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,12 +34,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
37 protected BulletSim m_world; 39 protected BulletSim m_world;
38 protected BulletBody m_body1; 40 protected BulletBody m_body1;
39 protected BulletBody m_body2; 41 protected BulletBody m_body2;
40 protected BulletConstraint m_constraint; 42 protected BulletConstraint m_constraint;
41 protected bool m_enabled = false; 43 protected bool m_enabled = false;
42 44
45 public BulletBody Body1 { get { return m_body1; } }
46 public BulletBody Body2 { get { return m_body2; } }
47 public BulletConstraint Constraint { get { return m_constraint; } }
48 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } }
50
43 public BSConstraint() 51 public BSConstraint()
44 { 52 {
45 } 53 }
@@ -53,7 +61,7 @@ public abstract class BSConstraint : IDisposable
53 { 61 {
54 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
55 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
56 BSScene.DetailLogZero, 64 BSScene.DetailLogZero,
57 m_body1.ID, m_body1.ptr.ToString("X"), 65 m_body1.ID, m_body1.ptr.ToString("X"),
58 m_body2.ID, m_body2.ptr.ToString("X"), 66 m_body2.ID, m_body2.ptr.ToString("X"),
59 success); 67 success);
@@ -62,12 +70,6 @@ public abstract class BSConstraint : IDisposable
62 } 70 }
63 } 71 }
64 72
65 public BulletBody Body1 { get { return m_body1; } }
66 public BulletBody Body2 { get { return m_body2; } }
67 public BulletConstraint Constraint { get { return m_constraint; } }
68 public abstract ConstraintType Type { get; }
69
70
71 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
72 { 74 {
73 bool ret = false; 75 bool ret = false;
@@ -124,7 +126,7 @@ public abstract class BSConstraint : IDisposable
124 } 126 }
125 else 127 else
126 { 128 {
127 m_world.physicsScene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
128 } 130 }
129 } 131 }
130 return ret; 132 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 3306a97..23ef052 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -32,14 +32,14 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public class BS6DofConstraint : BSConstraint 35public sealed class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38 38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
42 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@@ -58,7 +58,7 @@ public class BS6DofConstraint : BSConstraint
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
59 } 59 }
60 60
61 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 62 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
64 { 64 {
@@ -71,8 +71,7 @@ public class BS6DofConstraint : BSConstraint
71 BSScene.DetailLogZero, world.worldID, 71 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 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}", 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, 74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
75 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
76 m_enabled = false; 75 m_enabled = false;
77 } 76 }
78 else 77 else
@@ -135,7 +134,11 @@ public class BS6DofConstraint : BSConstraint
135 bool ret = false; 134 bool ret = false;
136 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
137 if (m_enabled) 136 if (m_enabled)
137 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 }
139 return ret; 142 return ret;
140 } 143 }
141 144
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index 22ea367..a9fd826 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36public class BSConstraintCollection : IDisposable 36public sealed class BSConstraintCollection : IDisposable
37{ 37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; 39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
@@ -143,8 +143,6 @@ public class BSConstraintCollection : IDisposable
143 // Return 'true' if any constraints were destroyed. 143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1) 144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 { 145 {
146 // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
147
148 List<BSConstraint> toRemove = new List<BSConstraint>(); 146 List<BSConstraint> toRemove = new List<BSConstraint>();
149 uint lookingID = body1.ID; 147 uint lookingID = body1.ID;
150 lock (m_constraints) 148 lock (m_constraints)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index 7c8a215..ed3ffa7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -32,11 +32,11 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 38
39 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 56342b8..dbc9039 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 *
27 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -52,12 +52,17 @@ using OpenSim.Region.Physics.Manager;
52 52
53namespace OpenSim.Region.Physics.BulletSPlugin 53namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public sealed class BSDynamics
56 { 56 {
57 private static string LogHeader = "[BULLETSIM VEHICLE]";
58
57 private BSScene PhysicsScene { get; set; } 59 private BSScene PhysicsScene { get; set; }
58 // the prim this dynamic controller belongs to 60 // the prim this dynamic controller belongs to
59 private BSPrim Prim { get; set; } 61 private BSPrim Prim { get; set; }
60 62
63 // mass of the vehicle fetched each time we're calles
64 private float m_vehicleMass;
65
61 // Vehicle properties 66 // Vehicle properties
62 public Vehicle Type { get; set; } 67 public Vehicle Type { get; set; }
63 68
@@ -72,8 +77,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
72 // LIMIT_ROLL_ONLY 77 // LIMIT_ROLL_ONLY
73 private Vector3 m_BlockingEndPoint = Vector3.Zero; 78 private Vector3 m_BlockingEndPoint = Vector3.Zero;
74 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 79 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
80 private Quaternion m_referenceFrame = Quaternion.Identity;
81
75 // Linear properties 82 // Linear properties
76 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
77 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
78 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body 86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
79 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 87 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
@@ -86,7 +94,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
86 94
87 //Angular properties 95 //Angular properties
88 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
89 private int m_angularMotorApply = 0; // application frame counter 97 // private int m_angularMotorApply = 0; // application frame counter
90 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
91 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
92 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
@@ -95,19 +103,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
95 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
96 104
97 //Deflection properties 105 //Deflection properties
98 // private float m_angularDeflectionEfficiency = 0; 106 private float m_angularDeflectionEfficiency = 0;
99 // private float m_angularDeflectionTimescale = 0; 107 private float m_angularDeflectionTimescale = 0;
100 // private float m_linearDeflectionEfficiency = 0; 108 private float m_linearDeflectionEfficiency = 0;
101 // private float m_linearDeflectionTimescale = 0; 109 private float m_linearDeflectionTimescale = 0;
102 110
103 //Banking properties 111 //Banking properties
104 // private float m_bankingEfficiency = 0; 112 private float m_bankingEfficiency = 0;
105 // private float m_bankingMix = 0; 113 private float m_bankingMix = 0;
106 // private float m_bankingTimescale = 0; 114 private float m_bankingTimescale = 0;
107 115
108 //Hover and Buoyancy properties 116 //Hover and Buoyancy properties
109 private float m_VhoverHeight = 0f; 117 private float m_VhoverHeight = 0f;
110// private float m_VhoverEfficiency = 0f; 118 private float m_VhoverEfficiency = 0f;
111 private float m_VhoverTimescale = 0f; 119 private float m_VhoverTimescale = 0f;
112 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
113 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 121 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
@@ -138,10 +146,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
138 switch (pParam) 146 switch (pParam)
139 { 147 {
140 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 148 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
141 // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); 149 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
142 break; 150 break;
143 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 151 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
144 // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
145 break; 153 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -150,20 +158,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
150 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 158 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
151 break; 159 break;
152 case Vehicle.BANKING_EFFICIENCY: 160 case Vehicle.BANKING_EFFICIENCY:
153 // m_bankingEfficiency = Math.Max(pValue, 0.01f); 161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
154 break; 162 break;
155 case Vehicle.BANKING_MIX: 163 case Vehicle.BANKING_MIX:
156 // m_bankingMix = Math.Max(pValue, 0.01f); 164 m_bankingMix = Math.Max(pValue, 0.01f);
157 break; 165 break;
158 case Vehicle.BANKING_TIMESCALE: 166 case Vehicle.BANKING_TIMESCALE:
159 // m_bankingTimescale = Math.Max(pValue, 0.01f); 167 m_bankingTimescale = Math.Max(pValue, 0.01f);
160 break; 168 break;
161 case Vehicle.BUOYANCY: 169 case Vehicle.BUOYANCY:
162 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
163 break; 171 break;
164// case Vehicle.HOVER_EFFICIENCY: 172 case Vehicle.HOVER_EFFICIENCY:
165// m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
166// break; 174 break;
167 case Vehicle.HOVER_HEIGHT: 175 case Vehicle.HOVER_HEIGHT:
168 m_VhoverHeight = pValue; 176 m_VhoverHeight = pValue;
169 break; 177 break;
@@ -171,10 +179,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
171 m_VhoverTimescale = Math.Max(pValue, 0.01f); 179 m_VhoverTimescale = Math.Max(pValue, 0.01f);
172 break; 180 break;
173 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 181 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
174 // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); 182 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
175 break; 183 break;
176 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 184 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
177 // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
178 break; 186 break;
179 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
180 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
@@ -196,7 +204,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
196 break; 204 break;
197 case Vehicle.ANGULAR_MOTOR_DIRECTION: 205 case Vehicle.ANGULAR_MOTOR_DIRECTION:
198 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
199 m_angularMotorApply = 10; 207 // m_angularMotorApply = 100;
200 break; 208 break;
201 case Vehicle.LINEAR_FRICTION_TIMESCALE: 209 case Vehicle.LINEAR_FRICTION_TIMESCALE:
202 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
@@ -206,7 +214,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
206 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
207 break; 215 break;
208 case Vehicle.LINEAR_MOTOR_OFFSET: 216 case Vehicle.LINEAR_MOTOR_OFFSET:
209 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
210 break; 218 break;
211 219
212 } 220 }
@@ -221,15 +229,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
221 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
222 break; 230 break;
223 case Vehicle.ANGULAR_MOTOR_DIRECTION: 231 case Vehicle.ANGULAR_MOTOR_DIRECTION:
224 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
225 // Limit requested angular speed to 2 rps= 4 pi rads/sec 232 // Limit requested angular speed to 2 rps= 4 pi rads/sec
226 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; 233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f));
227 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; 234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
228 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; 235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
229 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; 236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
230 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; 237 // m_angularMotorApply = 100;
231 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
232 m_angularMotorApply = 10;
233 break; 238 break;
234 case Vehicle.LINEAR_FRICTION_TIMESCALE: 239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
235 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -239,7 +244,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
239 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
240 break; 245 break;
241 case Vehicle.LINEAR_MOTOR_OFFSET: 246 case Vehicle.LINEAR_MOTOR_OFFSET:
242 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
243 break; 248 break;
244 case Vehicle.BLOCK_EXIT: 249 case Vehicle.BLOCK_EXIT:
245 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 250 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -253,7 +258,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
253 switch (pParam) 258 switch (pParam)
254 { 259 {
255 case Vehicle.REFERENCE_FRAME: 260 case Vehicle.REFERENCE_FRAME:
256 // m_referenceFrame = pValue; 261 m_referenceFrame = pValue;
257 break; 262 break;
258 case Vehicle.ROLL_FRAME: 263 case Vehicle.ROLL_FRAME:
259 m_RollreferenceFrame = pValue; 264 m_RollreferenceFrame = pValue;
@@ -265,21 +270,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
265 { 270 {
266 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 271 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
267 VehicleFlag parm = (VehicleFlag)pParam; 272 VehicleFlag parm = (VehicleFlag)pParam;
268 if (remove) 273 if (pParam == -1)
274 m_flags = (VehicleFlag)0;
275 else
269 { 276 {
270 if (pParam == -1) 277 if (remove)
271 {
272 m_flags = (VehicleFlag)0;
273 }
274 else
275 {
276 m_flags &= ~parm; 278 m_flags &= ~parm;
277 } 279 else
278 } 280 m_flags |= parm;
279 else {
280 m_flags |= parm;
281 } 281 }
282 }//end ProcessVehicleFlags 282 }
283 283
284 internal void ProcessTypeChange(Vehicle pType) 284 internal void ProcessTypeChange(Vehicle pType)
285 { 285 {
@@ -288,101 +288,144 @@ namespace OpenSim.Region.Physics.BulletSPlugin
288 Type = pType; 288 Type = pType;
289 switch (pType) 289 switch (pType)
290 { 290 {
291 case Vehicle.TYPE_NONE: 291 case Vehicle.TYPE_NONE:
292 m_linearFrictionTimescale = new Vector3(0, 0, 0);
293 m_angularFrictionTimescale = new Vector3(0, 0, 0);
294 m_linearMotorDirection = Vector3.Zero; 292 m_linearMotorDirection = Vector3.Zero;
295 m_linearMotorTimescale = 0; 293 m_linearMotorTimescale = 0;
296 m_linearMotorDecayTimescale = 0; 294 m_linearMotorDecayTimescale = 0;
295 m_linearFrictionTimescale = new Vector3(0, 0, 0);
296
297 m_angularMotorDirection = Vector3.Zero; 297 m_angularMotorDirection = Vector3.Zero;
298 m_angularMotorTimescale = 0;
299 m_angularMotorDecayTimescale = 0; 298 m_angularMotorDecayTimescale = 0;
299 m_angularMotorTimescale = 0;
300 m_angularFrictionTimescale = new Vector3(0, 0, 0);
301
300 m_VhoverHeight = 0; 302 m_VhoverHeight = 0;
303 m_VhoverEfficiency = 0;
301 m_VhoverTimescale = 0; 304 m_VhoverTimescale = 0;
302 m_VehicleBuoyancy = 0; 305 m_VehicleBuoyancy = 0;
306
307 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1;
309
310 m_angularDeflectionEfficiency = 0;
311 m_angularDeflectionTimescale = 1000;
312
313 m_verticalAttractionEfficiency = 0;
314 m_verticalAttractionTimescale = 0;
315
316 m_bankingEfficiency = 0;
317 m_bankingTimescale = 1000;
318 m_bankingMix = 1;
319
320 m_referenceFrame = Quaternion.Identity;
303 m_flags = (VehicleFlag)0; 321 m_flags = (VehicleFlag)0;
304 break; 322 break;
305 323
306 case Vehicle.TYPE_SLED: 324 case Vehicle.TYPE_SLED:
307 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
308 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
309 m_linearMotorDirection = Vector3.Zero; 325 m_linearMotorDirection = Vector3.Zero;
310 m_linearMotorTimescale = 1000; 326 m_linearMotorTimescale = 1000;
311 m_linearMotorDecayTimescale = 120; 327 m_linearMotorDecayTimescale = 120;
328 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
329
312 m_angularMotorDirection = Vector3.Zero; 330 m_angularMotorDirection = Vector3.Zero;
313 m_angularMotorTimescale = 1000; 331 m_angularMotorTimescale = 1000;
314 m_angularMotorDecayTimescale = 120; 332 m_angularMotorDecayTimescale = 120;
333 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
334
315 m_VhoverHeight = 0; 335 m_VhoverHeight = 0;
316// m_VhoverEfficiency = 1; 336 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
317 m_VhoverTimescale = 10; 337 m_VhoverTimescale = 10;
318 m_VehicleBuoyancy = 0; 338 m_VehicleBuoyancy = 0;
319 // m_linearDeflectionEfficiency = 1; 339
320 // m_linearDeflectionTimescale = 1; 340 m_linearDeflectionEfficiency = 1;
321 // m_angularDeflectionEfficiency = 1; 341 m_linearDeflectionTimescale = 1;
322 // m_angularDeflectionTimescale = 1000; 342
323 // m_bankingEfficiency = 0; 343 m_angularDeflectionEfficiency = 1;
324 // m_bankingMix = 1; 344 m_angularDeflectionTimescale = 1000;
325 // m_bankingTimescale = 10; 345
326 // m_referenceFrame = Quaternion.Identity; 346 m_verticalAttractionEfficiency = 0;
347 m_verticalAttractionTimescale = 0;
348
349 m_bankingEfficiency = 0;
350 m_bankingTimescale = 10;
351 m_bankingMix = 1;
352
353 m_referenceFrame = Quaternion.Identity;
327 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
328 m_flags &= 355 m_flags &=
329 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
330 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
331 break; 358 break;
332 case Vehicle.TYPE_CAR: 359 case Vehicle.TYPE_CAR:
333 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
334 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
335 m_linearMotorDirection = Vector3.Zero; 360 m_linearMotorDirection = Vector3.Zero;
336 m_linearMotorTimescale = 1; 361 m_linearMotorTimescale = 1;
337 m_linearMotorDecayTimescale = 60; 362 m_linearMotorDecayTimescale = 60;
363 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
364
338 m_angularMotorDirection = Vector3.Zero; 365 m_angularMotorDirection = Vector3.Zero;
339 m_angularMotorTimescale = 1; 366 m_angularMotorTimescale = 1;
340 m_angularMotorDecayTimescale = 0.8f; 367 m_angularMotorDecayTimescale = 0.8f;
368 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
369
341 m_VhoverHeight = 0; 370 m_VhoverHeight = 0;
342// m_VhoverEfficiency = 0; 371 m_VhoverEfficiency = 0;
343 m_VhoverTimescale = 1000; 372 m_VhoverTimescale = 1000;
344 m_VehicleBuoyancy = 0; 373 m_VehicleBuoyancy = 0;
345 // // m_linearDeflectionEfficiency = 1; 374
346 // // m_linearDeflectionTimescale = 2; 375 m_linearDeflectionEfficiency = 1;
347 // // m_angularDeflectionEfficiency = 0; 376 m_linearDeflectionTimescale = 2;
348 // m_angularDeflectionTimescale = 10; 377
378 m_angularDeflectionEfficiency = 0;
379 m_angularDeflectionTimescale = 10;
380
349 m_verticalAttractionEfficiency = 1f; 381 m_verticalAttractionEfficiency = 1f;
350 m_verticalAttractionTimescale = 10f; 382 m_verticalAttractionTimescale = 10f;
351 // m_bankingEfficiency = -0.2f; 383
352 // m_bankingMix = 1; 384 m_bankingEfficiency = -0.2f;
353 // m_bankingTimescale = 1; 385 m_bankingMix = 1;
354 // m_referenceFrame = Quaternion.Identity; 386 m_bankingTimescale = 1;
355 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 387
388 m_referenceFrame = Quaternion.Identity;
389 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
390 | VehicleFlag.HOVER_TERRAIN_ONLY
391 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
392 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
356 | VehicleFlag.LIMIT_ROLL_ONLY 393 | VehicleFlag.LIMIT_ROLL_ONLY
357 | VehicleFlag.LIMIT_MOTOR_UP); 394 | VehicleFlag.LIMIT_MOTOR_UP
358 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 395 | VehicleFlag.HOVER_UP_ONLY);
359 m_flags |= (VehicleFlag.HOVER_UP_ONLY);
360 break; 396 break;
361 case Vehicle.TYPE_BOAT: 397 case Vehicle.TYPE_BOAT:
362 m_linearFrictionTimescale = new Vector3(10, 3, 2);
363 m_angularFrictionTimescale = new Vector3(10,10,10);
364 m_linearMotorDirection = Vector3.Zero; 398 m_linearMotorDirection = Vector3.Zero;
365 m_linearMotorTimescale = 5; 399 m_linearMotorTimescale = 5;
366 m_linearMotorDecayTimescale = 60; 400 m_linearMotorDecayTimescale = 60;
401 m_linearFrictionTimescale = new Vector3(10, 3, 2);
402
367 m_angularMotorDirection = Vector3.Zero; 403 m_angularMotorDirection = Vector3.Zero;
368 m_angularMotorTimescale = 4; 404 m_angularMotorTimescale = 4;
369 m_angularMotorDecayTimescale = 4; 405 m_angularMotorDecayTimescale = 4;
406 m_angularFrictionTimescale = new Vector3(10,10,10);
407
370 m_VhoverHeight = 0; 408 m_VhoverHeight = 0;
371// m_VhoverEfficiency = 0.5f; 409 m_VhoverEfficiency = 0.5f;
372 m_VhoverTimescale = 2; 410 m_VhoverTimescale = 2;
373 m_VehicleBuoyancy = 1; 411 m_VehicleBuoyancy = 1;
374 // m_linearDeflectionEfficiency = 0.5f; 412
375 // m_linearDeflectionTimescale = 3; 413 m_linearDeflectionEfficiency = 0.5f;
376 // m_angularDeflectionEfficiency = 0.5f; 414 m_linearDeflectionTimescale = 3;
377 // m_angularDeflectionTimescale = 5; 415
416 m_angularDeflectionEfficiency = 0.5f;
417 m_angularDeflectionTimescale = 5;
418
378 m_verticalAttractionEfficiency = 0.5f; 419 m_verticalAttractionEfficiency = 0.5f;
379 m_verticalAttractionTimescale = 5f; 420 m_verticalAttractionTimescale = 5f;
380 // m_bankingEfficiency = -0.3f; 421
381 // m_bankingMix = 0.8f; 422 m_bankingEfficiency = -0.3f;
382 // m_bankingTimescale = 1; 423 m_bankingMix = 0.8f;
383 // m_referenceFrame = Quaternion.Identity; 424 m_bankingTimescale = 1;
425
426 m_referenceFrame = Quaternion.Identity;
384 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY 427 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
385 | VehicleFlag.HOVER_GLOBAL_HEIGHT 428 | VehicleFlag.HOVER_GLOBAL_HEIGHT
386 | VehicleFlag.LIMIT_ROLL_ONLY 429 | VehicleFlag.LIMIT_ROLL_ONLY
387 | VehicleFlag.HOVER_UP_ONLY); 430 | VehicleFlag.HOVER_UP_ONLY);
388 m_flags |= (VehicleFlag.NO_DEFLECTION_UP 431 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
@@ -390,28 +433,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
390 | VehicleFlag.HOVER_WATER_ONLY); 433 | VehicleFlag.HOVER_WATER_ONLY);
391 break; 434 break;
392 case Vehicle.TYPE_AIRPLANE: 435 case Vehicle.TYPE_AIRPLANE:
393 m_linearFrictionTimescale = new Vector3(200, 10, 5);
394 m_angularFrictionTimescale = new Vector3(20, 20, 20);
395 m_linearMotorDirection = Vector3.Zero; 436 m_linearMotorDirection = Vector3.Zero;
396 m_linearMotorTimescale = 2; 437 m_linearMotorTimescale = 2;
397 m_linearMotorDecayTimescale = 60; 438 m_linearMotorDecayTimescale = 60;
439 m_linearFrictionTimescale = new Vector3(200, 10, 5);
440
398 m_angularMotorDirection = Vector3.Zero; 441 m_angularMotorDirection = Vector3.Zero;
399 m_angularMotorTimescale = 4; 442 m_angularMotorTimescale = 4;
400 m_angularMotorDecayTimescale = 4; 443 m_angularMotorDecayTimescale = 4;
444 m_angularFrictionTimescale = new Vector3(20, 20, 20);
445
401 m_VhoverHeight = 0; 446 m_VhoverHeight = 0;
402// m_VhoverEfficiency = 0.5f; 447 m_VhoverEfficiency = 0.5f;
403 m_VhoverTimescale = 1000; 448 m_VhoverTimescale = 1000;
404 m_VehicleBuoyancy = 0; 449 m_VehicleBuoyancy = 0;
405 // m_linearDeflectionEfficiency = 0.5f; 450
406 // m_linearDeflectionTimescale = 3; 451 m_linearDeflectionEfficiency = 0.5f;
407 // m_angularDeflectionEfficiency = 1; 452 m_linearDeflectionTimescale = 3;
408 // m_angularDeflectionTimescale = 2; 453
454 m_angularDeflectionEfficiency = 1;
455 m_angularDeflectionTimescale = 2;
456
409 m_verticalAttractionEfficiency = 0.9f; 457 m_verticalAttractionEfficiency = 0.9f;
410 m_verticalAttractionTimescale = 2f; 458 m_verticalAttractionTimescale = 2f;
411 // m_bankingEfficiency = 1; 459
412 // m_bankingMix = 0.7f; 460 m_bankingEfficiency = 1;
413 // m_bankingTimescale = 2; 461 m_bankingMix = 0.7f;
414 // m_referenceFrame = Quaternion.Identity; 462 m_bankingTimescale = 2;
463
464 m_referenceFrame = Quaternion.Identity;
415 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 465 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
416 | VehicleFlag.HOVER_TERRAIN_ONLY 466 | VehicleFlag.HOVER_TERRAIN_ONLY
417 | VehicleFlag.HOVER_GLOBAL_HEIGHT 467 | VehicleFlag.HOVER_GLOBAL_HEIGHT
@@ -421,28 +471,36 @@ namespace OpenSim.Region.Physics.BulletSPlugin
421 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 471 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
422 break; 472 break;
423 case Vehicle.TYPE_BALLOON: 473 case Vehicle.TYPE_BALLOON:
424 m_linearFrictionTimescale = new Vector3(5, 5, 5);
425 m_angularFrictionTimescale = new Vector3(10, 10, 10);
426 m_linearMotorDirection = Vector3.Zero; 474 m_linearMotorDirection = Vector3.Zero;
427 m_linearMotorTimescale = 5; 475 m_linearMotorTimescale = 5;
476 m_linearFrictionTimescale = new Vector3(5, 5, 5);
428 m_linearMotorDecayTimescale = 60; 477 m_linearMotorDecayTimescale = 60;
478
429 m_angularMotorDirection = Vector3.Zero; 479 m_angularMotorDirection = Vector3.Zero;
430 m_angularMotorTimescale = 6; 480 m_angularMotorTimescale = 6;
481 m_angularFrictionTimescale = new Vector3(10, 10, 10);
431 m_angularMotorDecayTimescale = 10; 482 m_angularMotorDecayTimescale = 10;
483
432 m_VhoverHeight = 5; 484 m_VhoverHeight = 5;
433// m_VhoverEfficiency = 0.8f; 485 m_VhoverEfficiency = 0.8f;
434 m_VhoverTimescale = 10; 486 m_VhoverTimescale = 10;
435 m_VehicleBuoyancy = 1; 487 m_VehicleBuoyancy = 1;
436 // m_linearDeflectionEfficiency = 0; 488
437 // m_linearDeflectionTimescale = 5; 489 m_linearDeflectionEfficiency = 0;
438 // m_angularDeflectionEfficiency = 0; 490 m_linearDeflectionTimescale = 5;
439 // m_angularDeflectionTimescale = 5; 491
492 m_angularDeflectionEfficiency = 0;
493 m_angularDeflectionTimescale = 5;
494
440 m_verticalAttractionEfficiency = 1f; 495 m_verticalAttractionEfficiency = 1f;
441 m_verticalAttractionTimescale = 100f; 496 m_verticalAttractionTimescale = 100f;
442 // m_bankingEfficiency = 0; 497
443 // m_bankingMix = 0.7f; 498 m_bankingEfficiency = 0;
444 // m_bankingTimescale = 5; 499 m_bankingMix = 0.7f;
445 // m_referenceFrame = Quaternion.Identity; 500 m_bankingTimescale = 5;
501 m_referenceFrame = Quaternion.Identity;
502
503 m_referenceFrame = Quaternion.Identity;
446 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY 504 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
447 | VehicleFlag.HOVER_TERRAIN_ONLY 505 | VehicleFlag.HOVER_TERRAIN_ONLY
448 | VehicleFlag.HOVER_UP_ONLY 506 | VehicleFlag.HOVER_UP_ONLY
@@ -452,20 +510,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
452 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 510 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
453 break; 511 break;
454 } 512 }
455 }//end SetDefaultsForType 513 }
456 514
457 // Some of the properties of this prim may have changed. 515 // Some of the properties of this prim may have changed.
458 // Do any updating needed for a vehicle 516 // Do any updating needed for a vehicle
459 public void Refresh() 517 public void Refresh()
460 { 518 {
461 if (!IsActive) 519 if (IsActive)
462 return; 520 {
521 // Friction effects are handled by this vehicle code
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
463 526
464 // Set the prim's inertia to zero. The vehicle code handles that and this 527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
465 // removes the motion and torque actions introduced by Bullet. 528 }
466 Vector3 inertia = Vector3.Zero; 529 }
467 BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); 530
468 BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); 531 public bool RemoveBodyDependencies(BSPhysObject prim)
532 {
533 // If active, we need to add our properties back when the body is rebuilt.
534 return IsActive;
535 }
536
537 public void RestoreBodyDependencies(BSPhysObject prim)
538 {
539 if (Prim.LocalID != prim.LocalID)
540 {
541 // The call should be on us by our prim. Error if not.
542 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
543 LogHeader, prim.LocalID, Prim.LocalID);
544 return;
545 }
546 Refresh();
469 } 547 }
470 548
471 // One step of the vehicle properties for the next 'pTimestep' seconds. 549 // One step of the vehicle properties for the next 'pTimestep' seconds.
@@ -473,13 +551,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
473 { 551 {
474 if (!IsActive) return; 552 if (!IsActive) return;
475 553
554 // DEBUG
555 // Because Bullet does apply forces to the vehicle, our last computed
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
564
476 MoveLinear(pTimestep); 565 MoveLinear(pTimestep);
566 // Commented out for debug
477 MoveAngular(pTimestep); 567 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570
478 LimitRotation(pTimestep); 571 LimitRotation(pTimestep);
479 572
480 // remember the position so next step we can limit absolute movement effects 573 // remember the position so next step we can limit absolute movement effects
481 m_lastPositionVector = Prim.ForcePosition; 574 m_lastPositionVector = Prim.ForcePosition;
482 575
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
577 Prim.LocalID,
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
483 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
484 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
485 }// end Step 585 }// end Step
@@ -488,62 +588,52 @@ namespace OpenSim.Region.Physics.BulletSPlugin
488 // Also does hover and float. 588 // Also does hover and float.
489 private void MoveLinear(float pTimestep) 589 private void MoveLinear(float pTimestep)
490 { 590 {
491 // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates 591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
492 // m_lastLinearVelocityVector is the speed we are moving in that direction 592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
493 if (m_linearMotorDirection.LengthSquared() > 0.001f) 593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
494 { 594 {
495 Vector3 origDir = m_linearMotorDirection; 595 Vector3 origDir = m_linearMotorDirection; // DEBUG
496 Vector3 origVel = m_lastLinearVelocityVector; 596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
497 597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
498 // add drive to body 598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
499 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep); 599
500 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep); 600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
501 // lastLinearVelocityVector is the current body velocity vector 601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
502 // RA: Not sure what the *10 is for. A correction for pTimestep?
503 // m_lastLinearVelocityVector += (addAmount*10);
504 m_lastLinearVelocityVector += addAmount; 602 m_lastLinearVelocityVector += addAmount;
505 603
506 // Limit the velocity vector to less than the last set linear motor direction 604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
507 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) 605 m_linearMotorDirection *= (1f - decayFactor);
508 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; 606
509 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) 607 // Rotate new object velocity from vehicle relative to world coordinates
510 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; 608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
511 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) 609
512 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; 610 // Apply friction for next time
513 611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
514 /* 612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
515 // decay applied velocity 613
516 Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep); 614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
517 // (RA: do not know where the 0.5f comes from) 615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
518 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; 616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
519 */
520 float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep));
521 m_linearMotorDirection *= keepfraction;
522
523 VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
524 Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
525 } 617 }
526 else 618 else
527 { 619 {
528 // if what remains of direction is very small, zero it. 620 // if what remains of direction is very small, zero it.
529 m_linearMotorDirection = Vector3.Zero; 621 m_linearMotorDirection = Vector3.Zero;
530 m_lastLinearVelocityVector = Vector3.Zero; 622 m_lastLinearVelocityVector = Vector3.Zero;
623 m_newVelocity = Vector3.Zero;
624
531 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
532 } 626 }
533 627
534 // convert requested object velocity to object relative vector 628 // m_newVelocity is velocity computed from linear motor in world coordinates
535 Quaternion rotq = Prim.ForceOrientation;
536 m_newVelocity = m_lastLinearVelocityVector * rotq;
537
538 // Add the various forces into m_dir which will be our new direction vector (velocity)
539 629
540 // add Gravity and Buoyancy 630 // Gravity and Buoyancy
541 // There is some gravity, make a gravity force vector that is applied after object velocity. 631 // There is some gravity, make a gravity force vector that is applied after object velocity.
542 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
543 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy)); 633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
544 634
545 /* 635 /*
546 * RA: Not sure why one would do this 636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
547 // Preserve the current Z velocity 637 // Preserve the current Z velocity
548 Vector3 vel_now = m_prim.Velocity; 638 Vector3 vel_now = m_prim.Velocity;
549 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
@@ -555,7 +645,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
555 // If below the terrain, move us above the ground a little. 645 // If below the terrain, move us above the ground a little.
556 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
557 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
558 // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. 648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
559 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; 649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
560 // if (rotatedSize.Z < terrainHeight) 650 // if (rotatedSize.Z < terrainHeight)
561 if (pos.Z < terrainHeight) 651 if (pos.Z < terrainHeight)
@@ -566,6 +656,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
566 } 656 }
567 657
568 // Check if hovering 658 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height
569 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
570 { 662 {
571 // We should hover, get the target height 663 // We should hover, get the target height
@@ -584,25 +676,33 @@ namespace OpenSim.Region.Physics.BulletSPlugin
584 676
585 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
586 { 678 {
587 // If body is aready heigher, use its height as target height 679 // If body is already heigher, use its height as target height
588 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 680 if (pos.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z;
589 } 682 }
590 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
591 { 684 {
592 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
593 { 686 {
687 pos.Z = m_VhoverTargetHeight;
594 Prim.ForcePosition = pos; 688 Prim.ForcePosition = pos;
595 } 689 }
596 } 690 }
597 else 691 else
598 { 692 {
599 float herr0 = pos.Z - m_VhoverTargetHeight; 693 float verticalError = pos.Z - m_VhoverTargetHeight;
694 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
600 // Replace Vertical speed with correction figure if significant 696 // Replace Vertical speed with correction figure if significant
601 if (Math.Abs(herr0) > 0.01f) 697 if (Math.Abs(verticalError) > 0.01f)
602 { 698 {
603 m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 699 m_newVelocity.Z += verticalCorrectionVelocity;
604 //KF: m_VhoverEfficiency is not yet implemented 700 //KF: m_VhoverEfficiency is not yet implemented
605 } 701 }
702 else if (verticalError < -0.01)
703 {
704 m_newVelocity.Z -= verticalCorrectionVelocity;
705 }
606 else 706 else
607 { 707 {
608 m_newVelocity.Z = 0f; 708 m_newVelocity.Z = 0f;
@@ -649,25 +749,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
649 } 749 }
650 } 750 }
651 751
652 // Limit absolute vertical change 752 #region downForce
653 float Zchange = Math.Abs(posChange.Z); 753 Vector3 downForce = Vector3.Zero;
754
654 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
655 { 756 {
656 if (Zchange > .3) 757 // If the vehicle is motoring into the sky, get it going back down.
657 grav.Z = (float)(grav.Z * 3); 758 // Is this an angular force or both linear and angular??
658 if (Zchange > .15) 759 float distanceAboveGround = pos.Z - terrainHeight;
659 grav.Z = (float)(grav.Z * 2); 760 if (distanceAboveGround > 2f)
660 if (Zchange > .75) 761 {
661 grav.Z = (float)(grav.Z * 1.5); 762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
662 if (Zchange > .05) 763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
663 grav.Z = (float)(grav.Z * 1.25); 764 downForce = new Vector3(0, 0, -distanceAboveGround);
664 if (Zchange > .025) 765 }
665 grav.Z = (float)(grav.Z * 1.125); 766 // TODO: this calculation is all wrong. From the description at
666 float postemp = (pos.Z - terrainHeight); 767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
667 if (postemp > 2.5f) 768 // has a decay factor. This says this force should
668 grav.Z = (float)(grav.Z * 1.037125); 769 // be computed with a motor.
669 VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav); 770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
771 Prim.LocalID, distanceAboveGround, downForce);
670 } 772 }
773 #endregion // downForce
671 774
672 // If not changing some axis, reduce out velocity 775 // If not changing some axis, reduce out velocity
673 if ((m_flags & (VehicleFlag.NO_X)) != 0) 776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
@@ -677,21 +780,32 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
678 m_newVelocity.Z = 0; 781 m_newVelocity.Z = 0;
679 782
680 // Apply velocity 783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
785 {
786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
788 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
791
792 // Stuff new linear velocity into the vehicle
681 Prim.ForceVelocity = m_newVelocity; 793 Prim.ForceVelocity = m_newVelocity;
682 // apply gravity force 794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
683 // Why is this set here? The physics engine already does gravity.
684 Prim.AddForce(grav, false, true);
685 795
686 // Apply friction 796 Vector3 totalDownForce = downForce + grav;
687 Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); 797 if (totalDownForce != Vector3.Zero)
688 m_lastLinearVelocityVector *= keepFraction; 798 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 }
689 802
690 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", 803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
691 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); 804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
692 805
693 } // end MoveLinear() 806 } // end MoveLinear()
694 807
808 // =======================================================================
695 // Apply the effect of the angular motor. 809 // Apply the effect of the angular motor.
696 private void MoveAngular(float pTimestep) 810 private void MoveAngular(float pTimestep)
697 { 811 {
@@ -703,95 +817,191 @@ namespace OpenSim.Region.Physics.BulletSPlugin
703 // m_angularFrictionTimescale // body angular velocity decay rate 817 // m_angularFrictionTimescale // body angular velocity decay rate
704 // m_lastAngularVelocity // what was last applied to body 818 // m_lastAngularVelocity // what was last applied to body
705 819
706 // Get what the body is doing, this includes 'external' influences 820 if (m_angularMotorDirection.LengthSquared() > 0.0001)
707 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
708
709 if (m_angularMotorApply > 0)
710 { 821 {
711 // Rather than snapping the angular motor velocity from the old value to
712 // a newly set velocity, this routine steps the value from the previous
713 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection).
714 // There are m_angularMotorApply steps.
715 Vector3 origVel = m_angularMotorVelocity; 822 Vector3 origVel = m_angularMotorVelocity;
716 Vector3 origDir = m_angularMotorDirection; 823 Vector3 origDir = m_angularMotorDirection;
717 824
718 // ramp up to new value 825 // new velocity += error / ( time to get there / step interval)
719 // new velocity += error / ( time to get there / step interval) 826 // requested direction - current vehicle direction
720 // requested speed - last motor speed 827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
721 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 828 // decay requested direction
722 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
723 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
724
725 VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}",
726 Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
727 830
728 m_angularMotorApply--; 831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
729 } 833 }
730 else 834 else
731 { 835 {
732 // No motor recently applied, keep the body velocity 836 m_angularMotorVelocity = Vector3.Zero;
733 // and decay the velocity 837 }
734 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 838
735 if (m_angularMotorVelocity.LengthSquared() < 0.00001) 839 #region Vertical attactor
736 m_angularMotorVelocity = Vector3.Zero; 840
737 } // end motor section
738
739 // Vertical attractor section
740 Vector3 vertattr = Vector3.Zero; 841 Vector3 vertattr = Vector3.Zero;
741 Vector3 deflection = Vector3.Zero; 842 Vector3 deflection = Vector3.Zero;
742 Vector3 banking = Vector3.Zero; 843 Vector3 banking = Vector3.Zero;
743 844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
744 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) 846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
745 { 847 {
746 float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); 848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
747 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 849 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
748 851
749 // get present body rotation 852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
750 Quaternion rotq = Prim.ForceOrientation;
751 // vector pointing up
752 Vector3 verterr = Vector3.Zero;
753 verterr.Z = 1.0f;
754 853
755 // rotate it to Body Angle 854 // Create a vector of the vehicle "up" in world coordinates
756 verterr = verterr * rotq; 855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
757 // verterr.X and .Y are the World error amounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. 856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
758 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go 857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
759 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
760 861
761 // Error is 0 (no error) to +/- 2 (max error) 862 // Error is 0 (no error) to +/- 2 (max error)
762 if (verterr.Z < 0.0f) 863 if (verticalError.Z < 0.0f)
763 { 864 {
764 verterr.X = 2.0f - verterr.X; 865 verticalError.X = 2.0f - verticalError.X;
765 verterr.Y = 2.0f - verterr.Y; 866 verticalError.Y = 2.0f - verticalError.Y;
766 } 867 }
767 // scale it by VAservo 868 // scale it by VAservo (timestep and timescale)
768 verterr = verterr * VAservo; 869 verticalError = verticalError * VAservo;
769 870
770 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
771 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
772 vertattr.X = verterr.Y; 873 // Z is not changed.
773 vertattr.Y = - verterr.X; 874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
774 vertattr.Z = 0f; 876 vertattr.Z = 0f;
775 877
776 // scaling appears better usingsquare-law 878 // scaling appears better usingsquare-law
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
777 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
778 vertattr.X += bounce * angularVelocity.X; 881 vertattr.X += bounce * angularVelocity.X;
779 vertattr.Y += bounce * angularVelocity.Y; 882 vertattr.Y += bounce * angularVelocity.Y;
780 883
781 VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
782 Prim.LocalID, verterr, bounce, vertattr); 885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
783 886
784 } // else vertical attractor is off 887 }
888 #endregion // Vertical attactor
785 889
786 m_lastVertAttractor = vertattr; 890 #region Deflection
891
892 if (m_angularDeflectionEfficiency != 0)
893 {
894 // Compute a scaled vector that points in the preferred axis (X direction)
895 Vector3 scaledDefaultDirection =
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
897 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
898 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900
901 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct.
907 deflection = Vector3.Zero;
908 }
787 909
788 // Bank section tba 910 #endregion
789 911
790 // Deflection section tba 912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation;
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns
919
920 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
922 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative!
924
925 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0)
927 {
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 {
930 Vector3 axisAngle;
931 float angle;
932 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
933 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
934 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
935 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
936 else
937 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
938 }*/
939 }
940 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 {
945 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix)
947 angVelZ = mix;
948 else if(angVelZ < -mix)
949 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
952 if (bankingRot.X > 3)
953 bankingRot.X = 3;
954 else if (bankingRot.X < -3)
955 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot;
958 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
962 }
963
964 #endregion
965
966 m_lastVertAttractor = vertattr;
791 967
792 // Sum velocities 968 // Sum velocities
793 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
794 970
971 #region Linear Motor Offset
972
973 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero)
975 {
976 //Offset of linear velocity doesn't change the linear velocity,
977 // but causes a torque to be applied, for example...
978 //
979 // IIIII >>> IIIII
980 // IIIII >>> IIIII
981 // IIIII >>> IIIII
982 // ^
983 // | Applying a force at the arrow will cause the object to move forward, but also rotate
984 //
985 //
986 // The torque created is the linear velocity crossed with the offset
987
988 // NOTE: this computation does should be in the linear section
989 // because there we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X))
993 torqueFromOffset.X = 0;
994 if (float.IsNaN(torqueFromOffset.Y))
995 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass;
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 }
1002
1003 #endregion
1004
795 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
796 { 1006 {
797 m_lastAngularVelocity.X = 0; 1007 m_lastAngularVelocity.X = 0;
@@ -802,55 +1012,56 @@ namespace OpenSim.Region.Physics.BulletSPlugin
802 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
803 { 1013 {
804 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
805 VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1015 Prim.ZeroAngularMotion(true);
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1017 }
1018 else
1019 {
1020 // Apply to the body.
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
1022 // Since we are stuffing the angular velocity directly into the object, the computed
1023 // velocity needs to be scaled by the timestep.
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
1025 Prim.ForceRotationalVelocity = applyAngularForce;
1026
1027 // Decay the angular movement for next time
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
1029 m_lastAngularVelocity *= Vector3.One - decayamount;
1030
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
806 } 1033 }
807
808 // apply friction
809 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
810 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
811
812 // Apply to the body
813 Prim.ForceRotationalVelocity = m_lastAngularVelocity;
814
815 VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
816 } //end MoveAngular 1034 } //end MoveAngular
817 1035
818 internal void LimitRotation(float timestep) 1036 internal void LimitRotation(float timestep)
819 { 1037 {
820 Quaternion rotq = Prim.ForceOrientation; 1038 Quaternion rotq = Prim.ForceOrientation;
821 Quaternion m_rot = rotq; 1039 Quaternion m_rot = rotq;
822 bool changed = false;
823 if (m_RollreferenceFrame != Quaternion.Identity) 1040 if (m_RollreferenceFrame != Quaternion.Identity)
824 { 1041 {
825 if (rotq.X >= m_RollreferenceFrame.X) 1042 if (rotq.X >= m_RollreferenceFrame.X)
826 { 1043 {
827 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 1044 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
828 changed = true;
829 } 1045 }
830 if (rotq.Y >= m_RollreferenceFrame.Y) 1046 if (rotq.Y >= m_RollreferenceFrame.Y)
831 { 1047 {
832 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 1048 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
833 changed = true;
834 } 1049 }
835 if (rotq.X <= -m_RollreferenceFrame.X) 1050 if (rotq.X <= -m_RollreferenceFrame.X)
836 { 1051 {
837 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 1052 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
838 changed = true;
839 } 1053 }
840 if (rotq.Y <= -m_RollreferenceFrame.Y) 1054 if (rotq.Y <= -m_RollreferenceFrame.Y)
841 { 1055 {
842 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 1056 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
843 changed = true;
844 } 1057 }
845 changed = true;
846 } 1058 }
847 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 1059 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
848 { 1060 {
849 m_rot.X = 0; 1061 m_rot.X = 0;
850 m_rot.Y = 0; 1062 m_rot.Y = 0;
851 changed = true;
852 } 1063 }
853 if (changed) 1064 if (rotq != m_rot)
854 { 1065 {
855 Prim.ForceOrientation = m_rot; 1066 Prim.ForceOrientation = m_rot;
856 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 43b1262..0df4310 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,10 +32,39 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public abstract class BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 public enum LinksetImplementation
40 {
41 Constraint = 0, // linkset tied together with constraints
42 Compound = 1, // linkset tied together as a compound object
43 Manual = 2 // linkset tied together manually (code moves all the pieces)
44 }
45 // Create the correct type of linkset for this child
46 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
47 {
48 BSLinkset ret = null;
49
50 switch ((int)physScene.Params.linksetImplementation)
51 {
52 case (int)LinksetImplementation.Constraint:
53 ret = new BSLinksetConstraints(physScene, parent);
54 break;
55 case (int)LinksetImplementation.Compound:
56 ret = new BSLinksetCompound(physScene, parent);
57 break;
58 case (int)LinksetImplementation.Manual:
59 // ret = new BSLinksetManual(physScene, parent);
60 break;
61 default:
62 ret = new BSLinksetCompound(physScene, parent);
63 break;
64 }
65 return ret;
66 }
67
39 public BSPhysObject LinksetRoot { get; protected set; } 68 public BSPhysObject LinksetRoot { get; protected set; }
40 69
41 public BSScene PhysicsScene { get; private set; } 70 public BSScene PhysicsScene { get; private set; }
@@ -44,33 +73,39 @@ public class BSLinkset
44 public int LinksetID { get; private set; } 73 public int LinksetID { get; private set; }
45 74
46 // The children under the root in this linkset. 75 // The children under the root in this linkset.
47 // There are two lists of children: the current children at runtime 76 protected HashSet<BSPhysObject> m_children;
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.
55 private HashSet<BSPhysObject> m_children;
56 private HashSet<BSPhysObject> m_taintChildren;
57 77
58 // We lock the diddling of linkset classes to prevent any badness. 78 // We lock the diddling of linkset classes to prevent any badness.
59 // This locks the modification of the instances of this class. Changes 79 // This locks the modification of the instances of this class. Changes
60 // to the physical representation is done via the tainting mechenism. 80 // to the physical representation is done via the tainting mechenism.
61 private object m_linksetActivityLock = new Object(); 81 protected object m_linksetActivityLock = new Object();
62 82
83 // Some linksets have a preferred physical shape.
84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
85 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
86 {
87 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 }
89
90 // Linksets move around the children so the linkset might need to compute the child position
91 public virtual OMV.Vector3 Position(BSPhysObject member)
92 { return member.RawPosition; }
93 public virtual OMV.Quaternion Orientation(BSPhysObject member)
94 { return member.RawOrientation; }
95 // TODO: does this need to be done for Velocity and RotationalVelocityy?
96
63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 97 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
64 private float m_mass; 98 protected float m_mass;
65 public float LinksetMass 99 public float LinksetMass
66 { 100 {
67 get 101 get
68 { 102 {
69 m_mass = ComputeLinksetMass();
70 return m_mass; 103 return m_mass;
71 } 104 }
72 } 105 }
73 106
107 public virtual bool LinksetIsColliding { get { return false; } }
108
74 public OMV.Vector3 CenterOfMass 109 public OMV.Vector3 CenterOfMass
75 { 110 {
76 get { return ComputeLinksetCenterOfMass(); } 111 get { return ComputeLinksetCenterOfMass(); }
@@ -81,7 +116,7 @@ public class BSLinkset
81 get { return ComputeLinksetGeometricCenter(); } 116 get { return ComputeLinksetGeometricCenter(); }
82 } 117 }
83 118
84 public BSLinkset(BSScene scene, BSPhysObject parent) 119 protected void Initialize(BSScene scene, BSPhysObject parent)
85 { 120 {
86 // A simple linkset of one (no children) 121 // A simple linkset of one (no children)
87 LinksetID = m_nextLinksetID++; 122 LinksetID = m_nextLinksetID++;
@@ -91,8 +126,7 @@ public class BSLinkset
91 PhysicsScene = scene; 126 PhysicsScene = scene;
92 LinksetRoot = parent; 127 LinksetRoot = parent;
93 m_children = new HashSet<BSPhysObject>(); 128 m_children = new HashSet<BSPhysObject>();
94 m_taintChildren = new HashSet<BSPhysObject>(); 129 m_mass = parent.RawMass;
95 m_mass = parent.MassRaw;
96 } 130 }
97 131
98 // Link to a linkset where the child knows the parent. 132 // Link to a linkset where the child knows the parent.
@@ -106,6 +140,7 @@ public class BSLinkset
106 // Don't add the root to its own linkset 140 // Don't add the root to its own linkset
107 if (!IsRoot(child)) 141 if (!IsRoot(child))
108 AddChildToLinkset(child); 142 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass();
109 } 144 }
110 return this; 145 return this;
111 } 146 }
@@ -123,12 +158,12 @@ public class BSLinkset
123 // Cannot remove the root from a linkset. 158 // Cannot remove the root from a linkset.
124 return this; 159 return this;
125 } 160 }
126
127 RemoveChildFromLinkset(child); 161 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass();
128 } 163 }
129 164
130 // The child is down to a linkset of just itself 165 // The child is down to a linkset of just itself
131 return new BSLinkset(PhysicsScene, child); 166 return BSLinkset.Factory(PhysicsScene, child);
132 } 167 }
133 168
134 // Return 'true' if the passed object is the root object of this linkset 169 // Return 'true' if the passed object is the root object of this linkset
@@ -148,6 +183,8 @@ public class BSLinkset
148 bool ret = false; 183 bool ret = false;
149 lock (m_linksetActivityLock) 184 lock (m_linksetActivityLock)
150 { 185 {
186 ret = m_children.Contains(child);
187 /* Safer version but the above should work
151 foreach (BSPhysObject bp in m_children) 188 foreach (BSPhysObject bp in m_children)
152 { 189 {
153 if (child.LocalID == bp.LocalID) 190 if (child.LocalID == bp.LocalID)
@@ -156,159 +193,102 @@ public class BSLinkset
156 break; 193 break;
157 } 194 }
158 } 195 }
196 */
159 } 197 }
160 return ret; 198 return ret;
161 } 199 }
162 200
163 // When physical properties are changed the linkset needs to recalculate 201 // Perform an action on each member of the linkset including root prim.
164 // its internal properties. 202 // Depends on the action on whether this should be done at taint time.
165 // May be called at runtime or taint-time (just pass the appropriate flag). 203 public delegate bool ForEachMemberAction(BSPhysObject obj);
166 public void Refresh(BSPhysObject requestor, bool inTaintTime) 204 public virtual bool ForEachMember(ForEachMemberAction action)
167 { 205 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints 206 bool ret = false;
169 // (For the moment, static linksets do create constraints so remove the test for physical.) 207 lock (m_linksetActivityLock)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor)) 208 {
171 return; 209 action(LinksetRoot);
172 210 foreach (BSPhysObject po in m_children)
173 BSScene.TaintCallback refreshOperation = delegate()
174 { 211 {
175 RecomputeLinksetConstraintVariables(); 212 if (action(po))
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}", 213 break;
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); 214 }
178 }; 215 }
179 if (inTaintTime) 216 return ret;
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 } 217 }
184 218
219 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child);
222
223 // I am the root of a linkset and one of my children is being removed.
224 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
226
227 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties.
229 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor);
231
185 // The object is going dynamic (physical). Do any setup necessary 232 // The object is going dynamic (physical). Do any setup necessary
186 // for a dynamic linkset. 233 // for a dynamic linkset.
187 // Only the state of the passed object can be modified. The rest of the linkset 234 // Only the state of the passed object can be modified. The rest of the linkset
188 // has not yet been fully constructed. 235 // has not yet been fully constructed.
189 // Return 'true' if any properties updated on the passed object. 236 // Return 'true' if any properties updated on the passed object.
190 // Called at taint-time! 237 // Called at taint-time!
191 public bool MakeDynamic(BSPhysObject child) 238 public abstract bool MakeDynamic(BSPhysObject child);
192 {
193 // What is done for each object in BSPrim is what we want.
194 return false;
195 }
196 239
197 // The object is going static (non-physical). Do any setup necessary 240 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset. 241 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object. 242 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time! 243 // Called at taint-time!
201 public bool MakeStatic(BSPhysObject child) 244 public abstract bool MakeStatic(BSPhysObject child);
202 {
203 // What is done for each object in BSPrim is what we want.
204 return false;
205 }
206 245
207 // If the software is handling the movement of all the objects in a linkset 246 // Called when a parameter update comes from the physics engine for any object
208 // (like if one doesn't use constraints for static linksets), this is called 247 // of the linkset is received.
209 // when an update for the root of the linkset is received.
210 // Called at taint-time!! 248 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject) 249 public abstract void UpdateProperties(BSPhysObject physObject);
212 {
213 // The root local properties have been updated. Apply to the children if appropriate.
214 if (IsRoot(physObject) && HasAnyChildren)
215 {
216 if (!physObject.IsPhysical)
217 {
218 // TODO: implement software linkset update for static object linksets
219 }
220 }
221 }
222 250
223 // Routine used when rebuilding the body of the root of the linkset 251 // Routine used when rebuilding the body of the root of the linkset
224 // Destroy all the constraints have have been made to root. 252 // Destroy all the constraints have have been made to root.
225 // This is called when the root body is changing. 253 // This is called when the root body is changing.
226 // Returns 'true' of something eas actually removed and would need restoring 254 // Returns 'true' of something was actually removed and would need restoring
227 // Called at taint-time!! 255 // Called at taint-time!!
228 public bool RemoveBodyDependencies(BSPrim child) 256 public abstract bool RemoveBodyDependencies(BSPrim child);
229 {
230 bool ret = false;
231
232 lock (m_linksetActivityLock)
233 {
234 if (IsRoot(child))
235 {
236 // If the one with the dependency is root, must undo all children
237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
239
240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
241 }
242 else
243 {
244 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
245 child.LocalID,
246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
247 child.LocalID, child.BSBody.ptr.ToString("X"));
248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
249 // Despite the function name, this removes any link to the specified object.
250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
251 }
252 }
253 return ret;
254 }
255 257
256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 258 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
257 // this routine will restore the removed constraints. 259 // this routine will restore the removed constraints.
258 // Called at taint-time!! 260 // Called at taint-time!!
259 public void RestoreBodyDependencies(BSPrim child) 261 public abstract void RestoreBodyDependencies(BSPrim child);
260 {
261 lock (m_linksetActivityLock)
262 {
263 if (IsRoot(child))
264 {
265 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
267 foreach (BSPhysObject bpo in m_taintChildren)
268 {
269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
270 }
271 }
272 else
273 {
274 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
275 LinksetRoot.LocalID,
276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
277 child.LocalID, child.BSBody.ptr.ToString("X"));
278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
279 }
280 }
281 }
282 262
283 // ================================================================ 263 // ================================================================
284 // Below this point is internal magic 264 protected virtual float ComputeLinksetMass()
285
286 private float ComputeLinksetMass()
287 { 265 {
288 float mass; 266 float mass = LinksetRoot.RawMass;
289 lock (m_linksetActivityLock) 267 if (HasAnyChildren)
290 { 268 {
291 mass = LinksetRoot.MassRaw; 269 lock (m_linksetActivityLock)
292 foreach (BSPhysObject bp in m_taintChildren)
293 { 270 {
294 mass += bp.MassRaw; 271 foreach (BSPhysObject bp in m_children)
272 {
273 mass += bp.RawMass;
274 }
295 } 275 }
296 } 276 }
297 return mass; 277 return mass;
298 } 278 }
299 279
300 private OMV.Vector3 ComputeLinksetCenterOfMass() 280 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
301 { 281 {
302 OMV.Vector3 com; 282 OMV.Vector3 com;
303 lock (m_linksetActivityLock) 283 lock (m_linksetActivityLock)
304 { 284 {
305 com = LinksetRoot.Position * LinksetRoot.MassRaw; 285 com = LinksetRoot.Position * LinksetRoot.RawMass;
306 float totalMass = LinksetRoot.MassRaw; 286 float totalMass = LinksetRoot.RawMass;
307 287
308 foreach (BSPhysObject bp in m_taintChildren) 288 foreach (BSPhysObject bp in m_children)
309 { 289 {
310 com += bp.Position * bp.MassRaw; 290 com += bp.Position * bp.RawMass;
311 totalMass += bp.MassRaw; 291 totalMass += bp.RawMass;
312 } 292 }
313 if (totalMass != 0f) 293 if (totalMass != 0f)
314 com /= totalMass; 294 com /= totalMass;
@@ -317,255 +297,25 @@ public class BSLinkset
317 return com; 297 return com;
318 } 298 }
319 299
320 private OMV.Vector3 ComputeLinksetGeometricCenter() 300 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
321 { 301 {
322 OMV.Vector3 com; 302 OMV.Vector3 com;
323 lock (m_linksetActivityLock) 303 lock (m_linksetActivityLock)
324 { 304 {
325 com = LinksetRoot.Position; 305 com = LinksetRoot.Position;
326 306
327 foreach (BSPhysObject bp in m_taintChildren) 307 foreach (BSPhysObject bp in m_children)
328 { 308 {
329 com += bp.Position * bp.MassRaw; 309 com += bp.Position * bp.RawMass;
330 } 310 }
331 com /= (m_taintChildren.Count + 1); 311 com /= (m_children.Count + 1);
332 } 312 }
333 313
334 return com; 314 return com;
335 } 315 }
336 316
337 // I am the root of a linkset and a new child is being added
338 // Called while LinkActivity is locked.
339 private void AddChildToLinkset(BSPhysObject child)
340 {
341 if (!HasChild(child))
342 {
343 m_children.Add(child);
344
345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
346 BSPhysObject childx = child;
347
348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
349
350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
351 {
352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
353 rootx.LocalID,
354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
356 // Since this is taint-time, the body and shape could have changed for the child
357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
361 });
362 }
363 return;
364 }
365
366 // Forcefully removing a child from a linkset.
367 // This is not being called by the child so we have to make sure the child doesn't think
368 // it's still connected to the linkset.
369 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
370 // also has to be updated (like pointer to prim's parent).
371 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
372 {
373 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
374 RemoveChildFromLinkset(pchild);
375 }
376
377 // I am the root of a linkset and one of my children is being removed.
378 // Safe to call even if the child is not really in my linkset.
379 private void RemoveChildFromLinkset(BSPhysObject child)
380 {
381 if (m_children.Remove(child))
382 {
383 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
384 BSPhysObject childx = child;
385
386 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
387 childx.LocalID,
388 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
389 childx.LocalID, childx.BSBody.ptr.ToString("X"));
390
391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
392 {
393 m_taintChildren.Remove(child);
394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
395 RecomputeLinksetConstraintVariables();
396 });
397
398 }
399 else
400 {
401 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
402 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
403 }
404 return;
405 }
406
407 // Create a constraint between me (root of linkset) and the passed prim (the child).
408 // Called at taint time!
409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
410 {
411 // Zero motion for children so they don't interpolate
412 childPrim.ZeroMotion();
413
414 // Relative position normalized to the root prim
415 // Essentually a vector pointing from center of rootPrim to center of childPrim
416 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
417
418 // real world coordinate of midpoint between the two objects
419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
420
421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
422 rootPrim.LocalID,
423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
425 rootPrim.Position, childPrim.Position, midPoint);
426
427 // create a constraint that allows no freedom of movement between the two objects
428 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
429
430 BS6DofConstraint constrain = new BS6DofConstraint(
431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
432
433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
435 * of the objects.
436 * Code left as a warning to future programmers.
437 // ==================================================================================
438 // relative position normalized to the root prim
439 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
440 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
441
442 // relative rotation of the child to the parent
443 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
444 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
445
446 // create a constraint that allows no freedom of movement between the two objects
447 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
449 BS6DofConstraint constrain = new BS6DofConstraint(
450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
451 OMV.Vector3.Zero,
452 OMV.Quaternion.Inverse(rootPrim.Orientation),
453 OMV.Vector3.Zero,
454 OMV.Quaternion.Inverse(childPrim.Orientation),
455 // A point half way between the parent and child
456 // childRelativePosition/2,
457 // childRelativeRotation,
458 // childRelativePosition/2,
459 // inverseChildRelativeRotation,
460 true,
461 true
462 );
463 // ==================================================================================
464 */
465
466 PhysicsScene.Constraints.AddConstraint(constrain);
467
468 // zero linear and angular limits makes the objects unable to move in relation to each other
469 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
470 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
471
472 // tweek the constraint to increase stability
473 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
474 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
475 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
476 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
477 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
478 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
479 {
480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
481 }
482 }
483
484 // Remove linkage between myself and a particular child
485 // The root and child bodies are passed in because we need to remove the constraint between
486 // the bodies that were at unlink time.
487 // Called at taint time!
488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
489 {
490 bool ret = false;
491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
492 rootPrim.LocalID,
493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
495
496 // Find the constraint for this link and get rid of it from the overall collection and from my list
497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
503
504 return ret;
505 }
506
507 // Remove linkage between myself and any possible children I might have.
508 // Called at taint time!
509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
510 {
511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
512 bool ret = false;
513
514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
519 }
520
521 // Call each of the constraints that make up this linkset and recompute the
522 // various transforms and variables. Used when objects are added or removed
523 // from a linkset to make sure the constraints know about the new mass and
524 // geometry.
525 // Must only be called at taint time!!
526 private void RecomputeLinksetConstraintVariables()
527 {
528 float linksetMass = LinksetMass;
529 foreach (BSPhysObject child in m_taintChildren)
530 {
531 BSConstraint constrain;
532 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
533 {
534 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
535 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
536 constrain.RecomputeConstraintVariables(linksetMass);
537 }
538 else
539 {
540 // Non-fatal error that happens when children are being added to the linkset but
541 // their constraints have not been created yet.
542 break;
543 }
544 }
545
546 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
547 if (m_children.Count == m_taintChildren.Count)
548 {
549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
555 foreach (BSPhysObject child in m_taintChildren)
556 {
557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
562 }
563 return;
564 }
565
566
567 // Invoke the detailed logger and output something if it's enabled. 317 // Invoke the detailed logger and output something if it's enabled.
568 private void DetailLog(string msg, params Object[] args) 318 protected void DetailLog(string msg, params Object[] args)
569 { 319 {
570 if (PhysicsScene.PhysicsLogging.Enabled) 320 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args); 321 PhysicsScene.DetailLog(msg, args);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
new file mode 100755
index 0000000..b9c2cf9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -0,0 +1,275 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetCompound : BSLinkset
36{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 {
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren)
49 {
50 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
51 }
52 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
53 return ret;
54 }
55
56 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 {
62 // External request for Refresh (from BSPrim) is not necessary
63 // InternalRefresh(requestor);
64 }
65
66 private void InternalRefresh(BSPhysObject requestor)
67 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
69 // Queue to happen after all the other taint processing
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
71 {
72 if (IsRoot(requestor) && HasAnyChildren)
73 RecomputeLinksetCompound();
74 });
75 }
76
77 // The object is going dynamic (physical). Do any setup necessary
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child)
84 {
85 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child))
88 {
89 // Physical children are removed from the world as the shape ofthe root compound
90 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
93 ret = true;
94 }
95 return ret;
96 }
97
98 // The object is going static (non-physical). Do any setup necessary for a static linkset.
99 // Return 'true' if any properties updated on the passed object.
100 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset.
102 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child)
104 {
105 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child))
108 {
109 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true;
114 }
115 return ret;
116 }
117
118 // Called at taint-time!!
119 public override void UpdateProperties(BSPhysObject updated)
120 {
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
134 }
135
136 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child)
141 {
142 bool ret = false;
143
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
146
147 if (!IsRoot(child))
148 {
149 // Cause the current shape to be freed and the new one to be built.
150 InternalRefresh(LinksetRoot);
151 ret = true;
152 }
153
154 return ret;
155 }
156
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints.
159 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child)
161 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
163 }
164
165 // ================================================================
166
167 // Add a new child to the linkset.
168 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child)
170 {
171 if (!HasChild(child))
172 {
173 m_children.Add(child);
174
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176
177 // Cause constraints and assorted properties to be recomputed before the next simulation step.
178 InternalRefresh(LinksetRoot);
179 }
180 return;
181 }
182
183 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 {
187 if (m_children.Remove(child))
188 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"),
192 child.LocalID, child.PhysBody.ptr.ToString("X"));
193
194 // Cause the child's body to be rebuilt and thus restored to normal operation
195 child.ForceBodyShapeRebuild(false);
196
197 if (!HasAnyChildren)
198 {
199 // The linkset is now empty. The root needs rebuilding.
200 LinksetRoot.ForceBodyShapeRebuild(false);
201 }
202 else
203 {
204 // Schedule a rebuild of the linkset before the next simulation tick.
205 InternalRefresh(LinksetRoot);
206 }
207 }
208 return;
209 }
210
211 // Called before the simulation step to make sure the compound based linkset
212 // is all initialized.
213 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!!
216 private void RecomputeLinksetCompound()
217 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 {
227 if (!IsRoot(cPrim))
228 {
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
236
237 if (cPrim.PhysShape.isNativeShape)
238 {
239 // Native shapes are not shared so we need to create a new one.
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
253 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
256 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262
263 // With all of the linkset packed into the root prim, it has the mass of everyone.
264 float linksetMass = LinksetMass;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
268
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
272
273 }
274}
275} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..c855fda
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,327 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // This is queued in the 'post taint' queue so the
47 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor)
49 {
50 // Queue to happen after all the other taint processing
51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
52 {
53 if (HasAnyChildren && IsRoot(requestor))
54 RecomputeLinksetConstraints();
55 });
56 }
57
58 // The object is going dynamic (physical). Do any setup necessary
59 // for a dynamic linkset.
60 // Only the state of the passed object can be modified. The rest of the linkset
61 // has not yet been fully constructed.
62 // Return 'true' if any properties updated on the passed object.
63 // Called at taint-time!
64 public override bool MakeDynamic(BSPhysObject child)
65 {
66 // What is done for each object in BSPrim is what we want.
67 return false;
68 }
69
70 // The object is going static (non-physical). Do any setup necessary for a static linkset.
71 // Return 'true' if any properties updated on the passed object.
72 // This doesn't normally happen -- OpenSim removes the objects from the physical
73 // world if it is a static linkset.
74 // Called at taint-time!
75 public override bool MakeStatic(BSPhysObject child)
76 {
77 // What is done for each object in BSPrim is what we want.
78 return false;
79 }
80
81 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated)
83 {
84 // Nothing to do for constraints on property updates
85 }
86
87 // The children of the linkset are moved around by the constraints.
88 // Just grab the current values of wherever it is right now.
89 public override OMV.Vector3 Position(BSPhysObject member)
90 {
91 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
92 }
93
94 public override OMV.Quaternion Orientation(BSPhysObject member)
95 {
96 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
97 }
98
99 // Routine called when rebuilding the body of some member of the linkset.
100 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step.
102 // Returns 'true' of something was actually removed and would need restoring
103 // Called at taint-time!!
104 public override bool RemoveBodyDependencies(BSPrim child)
105 {
106 bool ret = false;
107
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"));
110
111 lock (m_linksetActivityLock)
112 {
113 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
114 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
115 // Cause the constraints, et al to be rebuilt before the next simulation step.
116 Refresh(LinksetRoot);
117 }
118 return ret;
119 }
120
121 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
122 // this routine will restore the removed constraints.
123 // Called at taint-time!!
124 public override void RestoreBodyDependencies(BSPrim child)
125 {
126 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
127 }
128
129 // ================================================================
130
131 // Add a new child to the linkset.
132 // Called while LinkActivity is locked.
133 protected override void AddChildToLinkset(BSPhysObject child)
134 {
135 if (!HasChild(child))
136 {
137 m_children.Add(child);
138
139 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
140
141 // Cause constraints and assorted properties to be recomputed before the next simulation step.
142 Refresh(LinksetRoot);
143 }
144 return;
145 }
146
147 // Remove the specified child from the linkset.
148 // Safe to call even if the child is not really in my linkset.
149 protected override void RemoveChildFromLinkset(BSPhysObject child)
150 {
151 if (m_children.Remove(child))
152 {
153 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
154 BSPhysObject childx = child;
155
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"),
159 childx.LocalID, childx.PhysBody.ptr.ToString("X"));
160
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 {
163 PhysicallyUnlinkAChildFromRoot(rootx, childx);
164 });
165 // See that the linkset parameters are recomputed at the end of the taint time.
166 Refresh(LinksetRoot);
167 }
168 else
169 {
170 // Non-fatal occurance.
171 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
172 }
173 return;
174 }
175
176 // Create a constraint between me (root of linkset) and the passed prim (the child).
177 // Called at taint time!
178 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
179 {
180 // Don't build the constraint when asked. Put it off until just before the simulation step.
181 Refresh(rootPrim);
182 }
183
184 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
185 {
186 // Zero motion for children so they don't interpolate
187 childPrim.ZeroMotion(true);
188
189 // Relative position normalized to the root prim
190 // Essentually a vector pointing from center of rootPrim to center of childPrim
191 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
192
193 // real world coordinate of midpoint between the two objects
194 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
195
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"),
200 rootPrim.Position, childPrim.Position, midPoint);
201
202 // create a constraint that allows no freedom of movement between the two objects
203 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
204
205 BSConstraint6Dof constrain = new BSConstraint6Dof(
206 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
207 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
208
209 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
210 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
211 * of the objects.
212 * Code left for future programmers.
213 // ==================================================================================
214 // relative position normalized to the root prim
215 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
216 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
217
218 // relative rotation of the child to the parent
219 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
220 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
221
222 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
223 BS6DofConstraint constrain = new BS6DofConstraint(
224 PhysicsScene.World, rootPrim.Body, childPrim.Body,
225 OMV.Vector3.Zero,
226 OMV.Quaternion.Inverse(rootPrim.Orientation),
227 OMV.Vector3.Zero,
228 OMV.Quaternion.Inverse(childPrim.Orientation),
229 true,
230 true
231 );
232 // ==================================================================================
233 */
234
235 PhysicsScene.Constraints.AddConstraint(constrain);
236
237 // zero linear and angular limits makes the objects unable to move in relation to each other
238 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240
241 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
248 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
250 }
251 return constrain;
252 }
253
254 // Remove linkage between the linkset root and a particular child
255 // The root and child bodies are passed in because we need to remove the constraint between
256 // the bodies that were present at unlink time.
257 // Called at taint time!
258 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
259 {
260 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"));
265
266 // Find the constraint for this link and get rid of it from the overall collection and from my list
267 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 {
269 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
271 ret = true;
272 }
273
274 return ret;
275 }
276
277 // Remove linkage between myself and any possible children I might have.
278 // Returns 'true' of any constraints were destroyed.
279 // Called at taint time!
280 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
281 {
282 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
283
284 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
285 }
286
287 // Call each of the constraints that make up this linkset and recompute the
288 // various transforms and variables. Create constraints of not created yet.
289 // Called before the simulation step to make sure the constraint based linkset
290 // is all initialized.
291 // Called at taint time!!
292 private void RecomputeLinksetConstraints()
293 {
294 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
296
297 // DEBUG: see of inter-linkset collisions are causing problems
298 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
299 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
300 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
302
303 foreach (BSPhysObject child in m_children)
304 {
305 // A child in the linkset physically shows the mass of the whole linkset.
306 // This allows Bullet to apply enough force on the child to move the whole linkset.
307 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass);
309
310 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
312 {
313 // If constraint doesn't exist yet, create it.
314 constrain = BuildConstraint(LinksetRoot, child);
315 }
316 constrain.RecomputeConstraintVariables(linksetMass);
317
318 // DEBUG: see of inter-linkset collisions are causing problems
319 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
320 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
321
322 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
323 }
324
325 }
326}
327}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
new file mode 100755
index 0000000..bc6e4c4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -0,0 +1,104 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using OpenMetaverse;
5
6namespace OpenSim.Region.Physics.BulletSPlugin
7{
8public abstract class BSMotor
9{
10 public virtual void Reset() { }
11 public virtual void Zero() { }
12}
13// Can all the incremental stepping be replaced with motor classes?
14public class BSVMotor : BSMotor
15{
16 public Vector3 FrameOfReference { get; set; }
17 public Vector3 Offset { get; set; }
18
19 public float TimeScale { get; set; }
20 public float TargetValueDecayTimeScale { get; set; }
21 public Vector3 CurrentValueReductionTimescale { get; set; }
22 public float Efficiency { get; set; }
23
24 public Vector3 TargetValue { get; private set; }
25 public Vector3 CurrentValue { get; private set; }
26
27
28
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
30 {
31 TimeScale = timeScale;
32 TargetValueDecayTimeScale = decayTimeScale;
33 CurrentValueReductionTimescale = frictionTimeScale;
34 Efficiency = efficiency;
35 }
36 public void SetCurrent(Vector3 current)
37 {
38 CurrentValue = current;
39 }
40 public void SetTarget(Vector3 target)
41 {
42 TargetValue = target;
43 }
44 public Vector3 Step(float timeStep)
45 {
46 if (CurrentValue.LengthSquared() > 0.001f)
47 {
48 // Vector3 origDir = Target; // DEBUG
49 // Vector3 origVel = CurrentValue; // DEBUG
50
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
53 CurrentValue += addAmount;
54
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
56 TargetValue *= (1f - decayFactor);
57
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
59 CurrentValue *= (Vector3.One - frictionFactor);
60 }
61 else
62 {
63 // if what remains of direction is very small, zero it.
64 TargetValue = Vector3.Zero;
65 CurrentValue = Vector3.Zero;
66
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
68 }
69 return CurrentValue;
70 }
71}
72
73public class BSFMotor : BSMotor
74{
75 public float TimeScale { get; set; }
76 public float DecayTimeScale { get; set; }
77 public float Friction { get; set; }
78 public float Efficiency { get; set; }
79
80 public float Target { get; private set; }
81 public float CurrentValue { get; private set; }
82
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
84 {
85 }
86 public void SetCurrent(float target)
87 {
88 }
89 public void SetTarget(float target)
90 {
91 }
92 public float Step(float timeStep)
93 {
94 return 0f;
95 }
96}
97public class BSPIDMotor : BSMotor
98{
99 // TODO: write and use this one
100 BSPIDMotor()
101 {
102 }
103}
104}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index ead6a08..f6a890e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -34,19 +34,30 @@ using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37// Class to wrap all objects. 37/*
38// The rest of BulletSim doesn't need to keep checking for avatars or prims 38 * Class to wrap all objects.
39// unless the difference is significant. 39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */
40public abstract class BSPhysObject : PhysicsActor 48public abstract class BSPhysObject : PhysicsActor
41{ 49{
42 protected void BaseInitialize(BSScene parentScene, uint localID, string name, string typeName) 50 protected BSPhysObject()
51 {
52 }
53 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
43 { 54 {
44 PhysicsScene = parentScene; 55 PhysicsScene = parentScene;
45 LocalID = localID; 56 LocalID = localID;
46 PhysObjectName = name; 57 PhysObjectName = name;
47 TypeName = typeName; 58 TypeName = typeName;
48 59
49 Linkset = new BSLinkset(PhysicsScene, this); 60 Linkset = BSLinkset.Factory(PhysicsScene, this);
50 LastAssetBuildFailed = false; 61 LastAssetBuildFailed = false;
51 62
52 CollisionCollection = new CollisionEventUpdate(); 63 CollisionCollection = new CollisionEventUpdate();
@@ -63,12 +74,17 @@ public abstract class BSPhysObject : PhysicsActor
63 public BSLinkset Linkset { get; set; } 74 public BSLinkset Linkset { get; set; }
64 75
65 // Return the object mass without calculating it or having side effects 76 // Return the object mass without calculating it or having side effects
66 public abstract float MassRaw { get; } 77 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass);
80
81 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; }
67 83
68 // Reference to the physical body (btCollisionObject) of this object 84 // Reference to the physical body (btCollisionObject) of this object
69 public BulletBody BSBody; 85 public BulletBody PhysBody;
70 // Reference to the physical shape (btCollisionShape) of this object 86 // Reference to the physical shape (btCollisionShape) of this object
71 public BulletShape BSShape; 87 public BulletShape PhysShape;
72 88
73 // 'true' if the mesh's underlying asset failed to build. 89 // 'true' if the mesh's underlying asset failed to build.
74 // This will keep us from looping after the first time the build failed. 90 // This will keep us from looping after the first time the build failed.
@@ -76,9 +92,15 @@ public abstract class BSPhysObject : PhysicsActor
76 92
77 // The objects base shape information. Null if not a prim type shape. 93 // The objects base shape information. Null if not a prim type shape.
78 public PrimitiveBaseShape BaseShape { get; protected set; } 94 public PrimitiveBaseShape BaseShape { get; protected set; }
95 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape
98 {
99 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
100 }
79 101
80 // When the physical properties are updated, an EntityProperty holds the update values. 102 // When the physical properties are updated, an EntityProperty holds the update values.
81 // Keep the current and last EntityProperties to enable computation of differences 103 // Keep the current and last EntityProperties to enable computation of differences
82 // between the current update and the previous values. 104 // between the current update and the previous values.
83 public EntityProperties CurrentEntityProperties { get; set; } 105 public EntityProperties CurrentEntityProperties { get; set; }
84 public EntityProperties LastEntityProperties { get; set; } 106 public EntityProperties LastEntityProperties { get; set; }
@@ -88,7 +110,8 @@ public abstract class BSPhysObject : PhysicsActor
88 public abstract bool IsStatic { get; } 110 public abstract bool IsStatic { get; }
89 111
90 // Stop all physical motion. 112 // Stop all physical motion.
91 public abstract void ZeroMotion(); 113 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime);
92 115
93 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured. 116 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
94 public virtual void StepVehicle(float timeStep) { } 117 public virtual void StepVehicle(float timeStep) { }
@@ -99,8 +122,10 @@ public abstract class BSPhysObject : PhysicsActor
99 // Tell the object to clean up. 122 // Tell the object to clean up.
100 public abstract void Destroy(); 123 public abstract void Destroy();
101 124
125 public abstract OMV.Vector3 RawPosition { get; set; }
102 public abstract OMV.Vector3 ForcePosition { get; set; } 126 public abstract OMV.Vector3 ForcePosition { get; set; }
103 127
128 public abstract OMV.Quaternion RawOrientation { get; set; }
104 public abstract OMV.Quaternion ForceOrientation { get; set; } 129 public abstract OMV.Quaternion ForceOrientation { get; set; }
105 130
106 public abstract OMV.Vector3 ForceVelocity { get; set; } 131 public abstract OMV.Vector3 ForceVelocity { get; set; }
@@ -204,7 +229,7 @@ public abstract class BSPhysObject : PhysicsActor
204 229
205 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
206 { 231 {
207 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
208 }); 233 });
209 } 234 }
210 else 235 else
@@ -213,16 +238,16 @@ public abstract class BSPhysObject : PhysicsActor
213 UnSubscribeEvents(); 238 UnSubscribeEvents();
214 } 239 }
215 } 240 }
216 public override void UnSubscribeEvents() { 241 public override void UnSubscribeEvents() {
217 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); 242 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
218 SubscribedEventsMs = 0; 243 SubscribedEventsMs = 0;
219 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
220 { 245 {
221 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
222 }); 247 });
223 } 248 }
224 // Return 'true' if the simulator wants collision events 249 // Return 'true' if the simulator wants collision events
225 public override bool SubscribedEvents() { 250 public override bool SubscribedEvents() {
226 return (SubscribedEventsMs > 0); 251 return (SubscribedEventsMs > 0);
227 } 252 }
228 253
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index aeeb4dd..2b3fa25 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -25,8 +25,6 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28// Uncomment this it enable code to do all shape an body memory management
29// in the C# code.
30using System; 28using System;
31using System.Reflection; 29using System.Reflection;
32using System.Collections.Generic; 30using System.Collections.Generic;
@@ -49,7 +47,6 @@ public sealed class BSPrim : BSPhysObject
49 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
50 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. 48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
51 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
52 // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
53 50
54 private bool _grabbed; 51 private bool _grabbed;
55 private bool _isSelected; 52 private bool _isSelected;
@@ -90,13 +87,13 @@ public sealed class BSPrim : BSPhysObject
90 87
91 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
92 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
90 : base(parent_scene, localID, primName, "BSPrim")
93 { 91 {
94 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 92 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
95 base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
96 _physicsActorType = (int)ActorTypes.Prim; 93 _physicsActorType = (int)ActorTypes.Prim;
97 _position = pos; 94 _position = pos;
98 _size = size; 95 _size = size;
99 Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 96 Scale = size; // the scale will be set by CreateGeom depending on object type
100 _orientation = rotation; 97 _orientation = rotation;
101 _buoyancy = 1f; 98 _buoyancy = 1f;
102 _velocity = OMV.Vector3.Zero; 99 _velocity = OMV.Vector3.Zero;
@@ -111,8 +108,8 @@ public sealed class BSPrim : BSPhysObject
111 _mass = CalculateMass(); 108 _mass = CalculateMass();
112 109
113 // No body or shape yet 110 // No body or shape yet
114 BSBody = new BulletBody(LocalID, IntPtr.Zero); 111 PhysBody = new BulletBody(LocalID, IntPtr.Zero);
115 BSShape = new BulletShape(IntPtr.Zero); 112 PhysShape = new BulletShape(IntPtr.Zero);
116 113
117 DetailLog("{0},BSPrim.constructor,call", LocalID); 114 DetailLog("{0},BSPrim.constructor,call", LocalID);
118 // do the actual object creation at taint time 115 // do the actual object creation at taint time
@@ -120,7 +117,7 @@ public sealed class BSPrim : BSPhysObject
120 { 117 {
121 CreateGeomAndObject(true); 118 CreateGeomAndObject(true);
122 119
123 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr); 120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
124 }); 121 });
125 } 122 }
126 123
@@ -145,8 +142,8 @@ public sealed class BSPrim : BSPhysObject
145 { 142 {
146 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
147 // If there are physical body and shape, release my use of same. 144 // If there are physical body and shape, release my use of same.
148 PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); 145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
149 PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); 146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
150 }); 147 });
151 } 148 }
152 149
@@ -157,6 +154,8 @@ public sealed class BSPrim : BSPhysObject
157 public override OMV.Vector3 Size { 154 public override OMV.Vector3 Size {
158 get { return _size; } 155 get { return _size; }
159 set { 156 set {
157 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built.
160 _size = value; 159 _size = value;
161 ForceBodyShapeRebuild(false); 160 ForceBodyShapeRebuild(false);
162 } 161 }
@@ -171,17 +170,18 @@ public sealed class BSPrim : BSPhysObject
171 ForceBodyShapeRebuild(false); 170 ForceBodyShapeRebuild(false);
172 } 171 }
173 } 172 }
173 // Whatever the linkset wants is what I want.
174 public override BSPhysicsShapeType PreferredPhysicalShape
175 { get { return Linkset.PreferredPhysicalShape(this); } }
176
174 public override bool ForceBodyShapeRebuild(bool inTaintTime) 177 public override bool ForceBodyShapeRebuild(bool inTaintTime)
175 { 178 {
176 BSScene.TaintCallback rebuildOperation = delegate() 179 LastAssetBuildFailed = false;
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
177 { 181 {
178 _mass = CalculateMass(); // changing the shape changes the mass 182 _mass = CalculateMass(); // changing the shape changes the mass
179 CreateGeomAndObject(true); 183 CreateGeomAndObject(true);
180 }; 184 });
181 if (inTaintTime)
182 rebuildOperation();
183 else
184 PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
185 return true; 185 return true;
186 } 186 }
187 public override bool Grabbed { 187 public override bool Grabbed {
@@ -235,14 +235,27 @@ public sealed class BSPrim : BSPhysObject
235 // Do it to the properties so the values get set in the physics engine. 235 // Do it to the properties so the values get set in the physics engine.
236 // Push the setting of the values to the viewer. 236 // Push the setting of the values to the viewer.
237 // Called at taint time! 237 // Called at taint time!
238 public override void ZeroMotion() 238 public override void ZeroMotion(bool inTaintTime)
239 { 239 {
240 _velocity = OMV.Vector3.Zero; 240 _velocity = OMV.Vector3.Zero;
241 _acceleration = OMV.Vector3.Zero; 241 _acceleration = OMV.Vector3.Zero;
242 _rotationalVelocity = OMV.Vector3.Zero; 242 _rotationalVelocity = OMV.Vector3.Zero;
243 243
244 // Zero some other properties directly into the physics engine 244 // Zero some other properties in the physics engine
245 BulletSimAPI.ClearForces2(BSBody.ptr); 245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
248 });
249 }
250 public override void ZeroAngularMotion(bool inTaintTime)
251 {
252 _rotationalVelocity = OMV.Vector3.Zero;
253 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
258 });
246 } 259 }
247 260
248 public override void LockAngularMotion(OMV.Vector3 axis) 261 public override void LockAngularMotion(OMV.Vector3 axis)
@@ -251,97 +264,91 @@ public sealed class BSPrim : BSPhysObject
251 return; 264 return;
252 } 265 }
253 266
267 public override OMV.Vector3 RawPosition
268 {
269 get { return _position; }
270 set { _position = value; }
271 }
254 public override OMV.Vector3 Position { 272 public override OMV.Vector3 Position {
255 get { 273 get {
274 // child prims move around based on their parent. Need to get the latest location
256 if (!Linkset.IsRoot(this)) 275 if (!Linkset.IsRoot(this))
257 // child prims move around based on their parent. Need to get the latest location 276 _position = Linkset.Position(this);
258 _position = BulletSimAPI.GetPosition2(BSBody.ptr);
259 277
260 // don't do the GetObjectPosition for root elements because this function is called a zillion times 278 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
261 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
262 return _position; 280 return _position;
263 } 281 }
264 set { 282 set {
265 // If you must push the position into the physics engine, use ForcePosition. 283 // If the position must be forced into the physics engine, use ForcePosition.
266 if (_position == value) 284 if (_position == value)
267 { 285 {
268 return; 286 return;
269 } 287 }
270 _position = value; 288 _position = value;
271 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
272 PositionSanityCheck(); 290 PositionSanityCheck(false);
273 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
274 { 292 {
275 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
295 ActivateIfPhysical(false);
277 }); 296 });
278 } 297 }
279 } 298 }
280 public override OMV.Vector3 ForcePosition { 299 public override OMV.Vector3 ForcePosition {
281 get { 300 get {
282 _position = BulletSimAPI.GetPosition2(BSBody.ptr); 301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
283 return _position; 302 return _position;
284 } 303 }
285 set { 304 set {
286 _position = value; 305 _position = value;
287 PositionSanityCheck(); 306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better.
288 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
308 ActivateIfPhysical(false);
289 } 309 }
290 } 310 }
291 311
292 // Check that the current position is sane and, if not, modify the position to make it so. 312 // Check that the current position is sane and, if not, modify the position to make it so.
293 // Check for being below terrain and being out of bounds. 313 // Check for being below terrain and being out of bounds.
294 // Returns 'true' of the position was made sane by some action. 314 // Returns 'true' of the position was made sane by some action.
295 private bool PositionSanityCheck() 315 private bool PositionSanityCheck(bool inTaintTime)
296 { 316 {
297 bool ret = false; 317 bool ret = false;
298 318
299 // If totally below the ground, move the prim up
300 // TODO: figure out the right solution for this... only for dynamic objects?
301 /*
302 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero;
303 if (Position.Z < terrainHeight) 321 if (Position.Z < terrainHeight)
304 { 322 {
305 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
306 _position.Z = terrainHeight + 2.0f; 324 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
326 upForce.Z = (terrainHeight - Position.Z) * 1f;
307 ret = true; 327 ret = true;
308 } 328 }
309 */ 329
310 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
311 { 331 {
312 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
313 if (Position.Z < waterHeight) 333 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f)
314 { 335 {
315 _position.Z = waterHeight; 336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f;
316 ret = true; 338 ret = true;
317 } 339 }
318 } 340 }
319 341
320 // TODO: check for out of bounds 342 // TODO: check for out of bounds
321 return ret;
322 }
323 343
324 // A version of the sanity check that also makes sure a new position value is 344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
325 // pushed to the physics engine. This routine would be used by anyone 345 if (ret)
326 // who is not already pushing the value.
327 private bool PositionSanityCheck(bool inTaintTime)
328 {
329 bool ret = false;
330 if (PositionSanityCheck())
331 { 346 {
332 // The new position value must be pushed into the physics engine but we can't 347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
333 // just assign to "Position" because of potential call loops.
334 BSScene.TaintCallback sanityOperation = delegate()
335 { 348 {
336 DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 349 // Apply upforce and overcome gravity.
337 ForcePosition = _position; 350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
338 }; 351 });
339 if (inTaintTime)
340 sanityOperation();
341 else
342 PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
343
344 ret = true;
345 } 352 }
346 return ret; 353 return ret;
347 } 354 }
@@ -352,13 +359,35 @@ public sealed class BSPrim : BSPhysObject
352 { 359 {
353 get 360 get
354 { 361 {
355 // return Linkset.LinksetMass; 362 return Linkset.LinksetMass;
356 return _mass; 363 // return _mass;
357 } 364 }
358 } 365 }
359 366
360 // used when we only want this prim's mass and not the linkset thing 367 // used when we only want this prim's mass and not the linkset thing
361 public override float MassRaw { get { return _mass; } } 368 public override float RawMass {
369 get { return _mass; }
370 }
371 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass)
374 {
375 if (IsStatic)
376 {
377 Inertia = OMV.Vector3.Zero;
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
380 }
381 else
382 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
386 // center of mass is at the zero of the object
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
389 }
390 }
362 391
363 // Is this used? 392 // Is this used?
364 public override OMV.Vector3 CenterOfMass 393 public override OMV.Vector3 CenterOfMass
@@ -379,7 +408,7 @@ public sealed class BSPrim : BSPhysObject
379 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
380 { 409 {
381 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
382 BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); 411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
383 }); 412 });
384 } 413 }
385 } 414 }
@@ -398,7 +427,8 @@ public sealed class BSPrim : BSPhysObject
398 { 427 {
399 // Done at taint time so we're sure the physics engine is not using the variables 428 // Done at taint time so we're sure the physics engine is not using the variables
400 // Vehicle code changes the parameters for this vehicle type. 429 // Vehicle code changes the parameters for this vehicle type.
401 this._vehicle.ProcessTypeChange(type); 430 _vehicle.ProcessTypeChange(type);
431 ActivateIfPhysical(false);
402 }); 432 });
403 } 433 }
404 } 434 }
@@ -407,6 +437,7 @@ public sealed class BSPrim : BSPhysObject
407 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 437 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
408 { 438 {
409 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); 439 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
440 ActivateIfPhysical(false);
410 }); 441 });
411 } 442 }
412 public override void VehicleVectorParam(int param, OMV.Vector3 value) 443 public override void VehicleVectorParam(int param, OMV.Vector3 value)
@@ -414,6 +445,7 @@ public sealed class BSPrim : BSPhysObject
414 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 445 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
415 { 446 {
416 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); 447 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
448 ActivateIfPhysical(false);
417 }); 449 });
418 } 450 }
419 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 451 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
@@ -421,6 +453,7 @@ public sealed class BSPrim : BSPhysObject
421 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 453 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
422 { 454 {
423 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 455 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
456 ActivateIfPhysical(false);
424 }); 457 });
425 } 458 }
426 public override void VehicleFlags(int param, bool remove) 459 public override void VehicleFlags(int param, bool remove)
@@ -435,9 +468,16 @@ public sealed class BSPrim : BSPhysObject
435 // Called from Scene when doing simulation step so we're in taint processing time. 468 // Called from Scene when doing simulation step so we're in taint processing time.
436 public override void StepVehicle(float timeStep) 469 public override void StepVehicle(float timeStep)
437 { 470 {
438 if (IsPhysical) 471 if (IsPhysical && _vehicle.IsActive)
439 { 472 {
440 _vehicle.Step(timeStep); 473 _vehicle.Step(timeStep);
474 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
475 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
476 {
477 // This resets the interpolation values and recomputes the tensor variables
478 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
479 });
480 */
441 } 481 }
442 } 482 }
443 483
@@ -462,7 +502,7 @@ public sealed class BSPrim : BSPhysObject
462 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
463 { 503 {
464 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
465 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
466 }); 506 });
467 } 507 }
468 } 508 }
@@ -470,12 +510,14 @@ public sealed class BSPrim : BSPhysObject
470 get { return _velocity; } 510 get { return _velocity; }
471 set { 511 set {
472 _velocity = value; 512 _velocity = value;
473 BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); 513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
474 } 514 }
475 } 515 }
476 public override OMV.Vector3 Torque { 516 public override OMV.Vector3 Torque {
477 get { return _torque; } 517 get { return _torque; }
478 set { _torque = value; 518 set {
519 _torque = value;
520 AddAngularForce(_torque, false, false);
479 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
480 } 522 }
481 } 523 }
@@ -488,12 +530,17 @@ public sealed class BSPrim : BSPhysObject
488 get { return _acceleration; } 530 get { return _acceleration; }
489 set { _acceleration = value; } 531 set { _acceleration = value; }
490 } 532 }
533 public override OMV.Quaternion RawOrientation
534 {
535 get { return _orientation; }
536 set { _orientation = value; }
537 }
491 public override OMV.Quaternion Orientation { 538 public override OMV.Quaternion Orientation {
492 get { 539 get {
540 // Children move around because tied to parent. Get a fresh value.
493 if (!Linkset.IsRoot(this)) 541 if (!Linkset.IsRoot(this))
494 { 542 {
495 // Children move around because tied to parent. Get a fresh value. 543 _orientation = Linkset.Orientation(this);
496 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
497 } 544 }
498 return _orientation; 545 return _orientation;
499 } 546 }
@@ -506,22 +553,22 @@ public sealed class BSPrim : BSPhysObject
506 { 553 {
507 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
508 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
509 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
510 }); 557 });
511 } 558 }
512 } 559 }
513 // Go directly to Bullet to get/set the value. 560 // Go directly to Bullet to get/set the value.
514 public override OMV.Quaternion ForceOrientation 561 public override OMV.Quaternion ForceOrientation
515 { 562 {
516 get 563 get
517 { 564 {
518 _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); 565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
519 return _orientation; 566 return _orientation;
520 } 567 }
521 set 568 set
522 { 569 {
523 _orientation = value; 570 _orientation = value;
524 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
525 } 572 }
526 } 573 }
527 public override int PhysicsActorType { 574 public override int PhysicsActorType {
@@ -538,6 +585,8 @@ public sealed class BSPrim : BSPhysObject
538 { 585 {
539 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
540 SetObjectDynamic(true); 587 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true);
541 }); 590 });
542 } 591 }
543 } 592 }
@@ -575,7 +624,7 @@ public sealed class BSPrim : BSPhysObject
575 624
576 // Mangling all the physical properties requires the object not be in the physical world. 625 // Mangling all the physical properties requires the object not be in the physical world.
577 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 626 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
578 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); 627 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
579 628
580 // Set up the object physicalness (does gravity and collisions move this object) 629 // Set up the object physicalness (does gravity and collisions move this object)
581 MakeDynamic(IsStatic); 630 MakeDynamic(IsStatic);
@@ -589,24 +638,25 @@ public sealed class BSPrim : BSPhysObject
589 // Make solid or not (do things bounce off or pass through this object). 638 // Make solid or not (do things bounce off or pass through this object).
590 MakeSolid(IsSolid); 639 MakeSolid(IsSolid);
591 640
592 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); 641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
593 642
594 // Rebuild its shape 643 // Rebuild its shape
595 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); 644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
596 645
597 // Collision filter can be set only when the object is in the world 646 // Collision filter can be set only when the object is in the world
598 if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0) 647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
599 { 648 {
600 BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask); 649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
601 } 650 }
602 651
603 // Recompute any linkset parameters. 652 // Recompute any linkset parameters.
604 // When going from non-physical to physical, this re-enables the constraints that 653 // When going from non-physical to physical, this re-enables the constraints that
605 // had been automatically disabled when the mass was set to zero. 654 // had been automatically disabled when the mass was set to zero.
606 Linkset.Refresh(this, true); 655 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this);
607 657
608 DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
609 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); 659 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
610 } 660 }
611 661
612 // "Making dynamic" means changing to and from static. 662 // "Making dynamic" means changing to and from static.
@@ -619,75 +669,74 @@ public sealed class BSPrim : BSPhysObject
619 if (makeStatic) 669 if (makeStatic)
620 { 670 {
621 // Become a Bullet 'static' object type 671 // Become a Bullet 'static' object type
622 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
623 // Stop all movement 673 // Stop all movement
624 BulletSimAPI.ClearAllForces2(BSBody.ptr); 674 ZeroMotion(true);
625 // Center of mass is at the center of the object 675 // Center of mass is at the center of the object
626 BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation); 676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
627 // Mass is zero which disables a bunch of physics stuff in Bullet 677 // Mass is zero which disables a bunch of physics stuff in Bullet
628 BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); 678 UpdatePhysicalMassProperties(0f);
629 // There is no inertia in a static object
630 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
631 // Set collision detection parameters 679 // Set collision detection parameters
632 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 680 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
633 { 681 {
634 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
635 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
636 } 684 }
637 // There can be special things needed for implementing linksets 685 // There can be special things needed for implementing linksets
638 Linkset.MakeStatic(this); 686 Linkset.MakeStatic(this);
639 // The activation state is 'disabled' so Bullet will not try to act on it. 687 // The activation state is 'disabled' so Bullet will not try to act on it.
640 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); 688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
641 // Start it out sleeping and physical actions could wake it up. 689 // Start it out sleeping and physical actions could wake it up.
642 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
643 691
644 BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
645 BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
646 } 694 }
647 else 695 else
648 { 696 {
649 // Not a Bullet static object 697 // Not a Bullet static object
650 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
651 699
652 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
653 BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction); 701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
654 BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution); 702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
655 703
656 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
657 BulletSimAPI.ClearAllForces2(BSBody.ptr); 705 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
658 707
659 // For good measure, make sure the transform is set through to the motion state 708 // For good measure, make sure the transform is set through to the motion state
660 BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); 709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
710
711 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
661 713
662 // A dynamic object has mass 714 // A dynamic object has mass
663 IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); 715 UpdatePhysicalMassProperties(RawMass);
664 OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
665 BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
666 BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
667 716
668 // Set collision detection parameters 717 // Set collision detection parameters
669 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 718 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
670 { 719 {
671 BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
672 BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
673 } 722 }
674 723
675 // Various values for simulation limits 724 // Various values for simulation limits
676 BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
677 BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); 726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
678 BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
679 BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
680 729
681 // There might be special things needed for implementing linksets. 730 // There might be special things needed for implementing linksets.
682 Linkset.MakeDynamic(this); 731 Linkset.MakeDynamic(this);
683 732
684 // Force activation of the object so Bullet will act on it. 733 // Force activation of the object so Bullet will act on it.
685 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
686 BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
687 // BulletSimAPI.Activate2(BSBody.ptr, true); 736 // BulletSimAPI.Activate2(BSBody.ptr, true);
688 737
689 BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
690 BSBody.collisionMask = CollisionFilterGroups.ObjectMask; 739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
691 } 740 }
692 } 741 }
693 742
@@ -697,7 +746,7 @@ public sealed class BSPrim : BSPhysObject
697 // the functions after this one set up the state of a possibly newly created collision body. 746 // the functions after this one set up the state of a possibly newly created collision body.
698 private void MakeSolid(bool makeSolid) 747 private void MakeSolid(bool makeSolid)
699 { 748 {
700 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr); 749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
701 if (makeSolid) 750 if (makeSolid)
702 { 751 {
703 // Verify the previous code created the correct shape for this type of thing. 752 // Verify the previous code created the correct shape for this type of thing.
@@ -705,7 +754,7 @@ public sealed class BSPrim : BSPhysObject
705 { 754 {
706 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
707 } 756 }
708 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
709 } 758 }
710 else 759 else
711 { 760 {
@@ -713,22 +762,31 @@ public sealed class BSPrim : BSPhysObject
713 { 762 {
714 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
715 } 764 }
716 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
717 BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
718 BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
719 } 768 }
720 } 769 }
721 770
771 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
772 // they need waking up when parameters are changed.
773 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt)
775 {
776 if (IsPhysical)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
778 }
779
722 // Turn on or off the flag controlling whether collision events are returned to the simulator. 780 // Turn on or off the flag controlling whether collision events are returned to the simulator.
723 private void EnableCollisions(bool wantsCollisionEvents) 781 private void EnableCollisions(bool wantsCollisionEvents)
724 { 782 {
725 if (wantsCollisionEvents) 783 if (wantsCollisionEvents)
726 { 784 {
727 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
728 } 786 }
729 else 787 else
730 { 788 {
731 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
732 } 790 }
733 } 791 }
734 792
@@ -768,14 +826,14 @@ public sealed class BSPrim : BSPhysObject
768 } 826 }
769 } 827 }
770 public override bool FloatOnWater { 828 public override bool FloatOnWater {
771 set { 829 set {
772 _floatOnWater = value; 830 _floatOnWater = value;
773 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
774 { 832 {
775 if (_floatOnWater) 833 if (_floatOnWater)
776 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
777 else 835 else
778 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
779 }); 837 });
780 } 838 }
781 } 839 }
@@ -797,8 +855,8 @@ public sealed class BSPrim : BSPhysObject
797 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
798 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
799 { 857 {
800 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
801 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); 859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
802 }); 860 });
803 } 861 }
804 } 862 }
@@ -808,7 +866,7 @@ public sealed class BSPrim : BSPhysObject
808 } 866 }
809 set { 867 set {
810 _rotationalVelocity = value; 868 _rotationalVelocity = value;
811 BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); 869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
812 } 870 }
813 } 871 }
814 public override bool Kinematic { 872 public override bool Kinematic {
@@ -834,7 +892,7 @@ public sealed class BSPrim : BSPhysObject
834 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
835 // Buoyancy is faked by changing the gravity applied to the object 893 // Buoyancy is faked by changing the gravity applied to the object
836 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
837 BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); 895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
838 } 896 }
839 } 897 }
840 898
@@ -874,6 +932,7 @@ public sealed class BSPrim : BSPhysObject
874 public override void AddForce(OMV.Vector3 force, bool pushforce) { 932 public override void AddForce(OMV.Vector3 force, bool pushforce) {
875 AddForce(force, pushforce, false); 933 AddForce(force, pushforce, false);
876 } 934 }
935 // Applying a force just adds this to the total force on the object.
877 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
878 // for an object, doesn't matter if force is a pushforce or not 937 // for an object, doesn't matter if force is a pushforce or not
879 if (force.IsFinite()) 938 if (force.IsFinite())
@@ -887,7 +946,7 @@ public sealed class BSPrim : BSPhysObject
887 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
888 return; 947 return;
889 } 948 }
890 BSScene.TaintCallback addForceOperation = delegate() 949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
891 { 950 {
892 OMV.Vector3 fSum = OMV.Vector3.Zero; 951 OMV.Vector3 fSum = OMV.Vector3.Zero;
893 lock (m_accumulatedForces) 952 lock (m_accumulatedForces)
@@ -899,20 +958,70 @@ public sealed class BSPrim : BSPhysObject
899 } 958 }
900 m_accumulatedForces.Clear(); 959 m_accumulatedForces.Clear();
901 } 960 }
902 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); 961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
903 // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. 962 if (fSum != OMV.Vector3.Zero)
904 BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); 963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
905 }; 964 });
906 if (inTaintTime) 965 }
907 addForceOperation(); 966
908 else 967 // An impulse force is scaled by the mass of the object.
909 PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation); 968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
969 {
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
975 });
910 } 976 }
911 977
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
912 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
913 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 980 AddAngularForce(force, pushforce, false);
914 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
915 } 981 }
982 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
983 {
984 if (force.IsFinite())
985 {
986 // _force += force;
987 lock (m_accumulatedAngularForces)
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force));
989 }
990 else
991 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return;
994 }
995 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
996 {
997 OMV.Vector3 fSum = OMV.Vector3.Zero;
998 lock (m_accumulatedAngularForces)
999 {
1000 // Sum the accumulated additional forces for one big force to apply once.
1001 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
1002 {
1003 fSum += v;
1004 }
1005 m_accumulatedAngularForces.Clear();
1006 }
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero)
1009 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum;
1012 }
1013 });
1014 }
1015 // A torque impulse.
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 {
1018 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1022 });
1023 }
1024
916 public override void SetMomentum(OMV.Vector3 momentum) { 1025 public override void SetMomentum(OMV.Vector3 momentum) {
917 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 1026 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
918 } 1027 }
@@ -971,7 +1080,7 @@ public sealed class BSPrim : BSPhysObject
971 if (hollowAmount > 0.0) 1080 if (hollowAmount > 0.0)
972 { 1081 {
973 hollowVolume *= hollowAmount; 1082 hollowVolume *= hollowAmount;
974 1083
975 switch (BaseShape.HollowShape) 1084 switch (BaseShape.HollowShape)
976 { 1085 {
977 case HollowShape.Square: 1086 case HollowShape.Square:
@@ -1194,9 +1303,7 @@ public sealed class BSPrim : BSPhysObject
1194 1303
1195 returnMass = _density * volume; 1304 returnMass = _density * volume;
1196 1305
1197 /* 1306 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1198 * This change means each object keeps its own mass and the Mass property
1199 * will return the sum if we're part of a linkset.
1200 if (IsRootOfLinkset) 1307 if (IsRootOfLinkset)
1201 { 1308 {
1202 foreach (BSPrim prim in _childrenPrims) 1309 foreach (BSPrim prim in _childrenPrims)
@@ -1216,48 +1323,27 @@ public sealed class BSPrim : BSPhysObject
1216 }// end CalculateMass 1323 }// end CalculateMass
1217 #endregion Mass Calculation 1324 #endregion Mass Calculation
1218 1325
1219 // Copy prim's info into the BulletSim shape description structure
1220 public void FillShapeInfo(out ShapeData shape)
1221 {
1222 shape.ID = LocalID;
1223 shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
1224 shape.Position = _position;
1225 shape.Rotation = _orientation;
1226 shape.Velocity = _velocity;
1227 shape.Size = _size;
1228 shape.Scale = Scale;
1229 shape.Mass = _isPhysical ? _mass : 0f;
1230 shape.Buoyancy = _buoyancy;
1231 shape.HullKey = 0;
1232 shape.MeshKey = 0;
1233 shape.Friction = _friction;
1234 shape.Restitution = _restitution;
1235 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1236 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1237 shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
1238 }
1239 // Rebuild the geometry and object. 1326 // Rebuild the geometry and object.
1240 // This is called when the shape changes so we need to recreate the mesh/hull. 1327 // This is called when the shape changes so we need to recreate the mesh/hull.
1241 // Called at taint-time!!! 1328 // Called at taint-time!!!
1242 private void CreateGeomAndObject(bool forceRebuild) 1329 private void CreateGeomAndObject(bool forceRebuild)
1243 { 1330 {
1244 ShapeData shapeData;
1245 FillShapeInfo(out shapeData);
1246
1247 // If this prim is part of a linkset, we must remove and restore the physical 1331 // If this prim is part of a linkset, we must remove and restore the physical
1248 // links of the body is rebuilt. 1332 // links if the body is rebuilt.
1249 bool needToRestoreLinkset = false; 1333 bool needToRestoreLinkset = false;
1334 bool needToRestoreVehicle = false;
1250 1335
1251 // Create the correct physical representation for this type of object. 1336 // Create the correct physical representation for this type of object.
1252 // Updates BSBody and BSShape with the new information. 1337 // Updates PhysBody and PhysShape with the new information.
1253 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1254 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, 1339 // Returns 'true' if either the body or the shape was changed.
1255 null, delegate(BulletBody dBody) 1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1256 { 1341 {
1257 // Called if the current prim body is about to be destroyed. 1342 // Called if the current prim body is about to be destroyed.
1258 // Remove all the physical dependencies on the old body. 1343 // Remove all the physical dependencies on the old body.
1259 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1260 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1261 }); 1347 });
1262 1348
1263 if (needToRestoreLinkset) 1349 if (needToRestoreLinkset)
@@ -1265,6 +1351,11 @@ public sealed class BSPrim : BSPhysObject
1265 // If physical body dependencies were removed, restore them 1351 // If physical body dependencies were removed, restore them
1266 Linkset.RestoreBodyDependencies(this); 1352 Linkset.RestoreBodyDependencies(this);
1267 } 1353 }
1354 if (needToRestoreVehicle)
1355 {
1356 // If physical body dependencies were removed, restore them
1357 _vehicle.RestoreBodyDependencies(this);
1358 }
1268 1359
1269 // Make sure the properties are set on the new object 1360 // Make sure the properties are set on the new object
1270 UpdatePhysicalParameters(); 1361 UpdatePhysicalParameters();
@@ -1326,7 +1417,7 @@ public sealed class BSPrim : BSPhysObject
1326 if (changed != 0) 1417 if (changed != 0)
1327 { 1418 {
1328 // Only update the position of single objects and linkset roots 1419 // Only update the position of single objects and linkset roots
1329 if (this._parentPrim == null) 1420 if (Linkset.IsRoot(this))
1330 { 1421 {
1331 base.RequestPhysicsterseUpdate(); 1422 base.RequestPhysicsterseUpdate();
1332 } 1423 }
@@ -1338,23 +1429,29 @@ public sealed class BSPrim : BSPhysObject
1338 // Updates only for individual prims and for the root object of a linkset. 1429 // Updates only for individual prims and for the root object of a linkset.
1339 if (Linkset.IsRoot(this)) 1430 if (Linkset.IsRoot(this))
1340 { 1431 {
1341 // Assign to the local variables so the normal set action does not happen 1432 // Assign directly to the local variables so the normal set action does not happen
1342 _position = entprop.Position; 1433 _position = entprop.Position;
1343 _orientation = entprop.Rotation; 1434 _orientation = entprop.Rotation;
1344 _velocity = entprop.Velocity; 1435 _velocity = entprop.Velocity;
1345 _acceleration = entprop.Acceleration; 1436 _acceleration = entprop.Acceleration;
1346 _rotationalVelocity = entprop.RotationalVelocity; 1437 _rotationalVelocity = entprop.RotationalVelocity;
1347 1438
1439 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true))
1441 {
1442 entprop.Position = _position;
1443 entprop.Velocity = _velocity;
1444 }
1445
1348 // remember the current and last set values 1446 // remember the current and last set values
1349 LastEntityProperties = CurrentEntityProperties; 1447 LastEntityProperties = CurrentEntityProperties;
1350 CurrentEntityProperties = entprop; 1448 CurrentEntityProperties = entprop;
1351 1449
1352 PositionSanityCheck(true); 1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1353 1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1354 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1355 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
1356 1453
1357 // BulletSimAPI.DumpRigidBody2(Scene.World.Ptr, BSBody.Ptr); 1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1358 1455
1359 base.RequestPhysicsterseUpdate(); 1456 base.RequestPhysicsterseUpdate();
1360 } 1457 }
@@ -1367,8 +1464,8 @@ public sealed class BSPrim : BSPhysObject
1367 entprop.Acceleration, entprop.RotationalVelocity); 1464 entprop.Acceleration, entprop.RotationalVelocity);
1368 } 1465 }
1369 */ 1466 */
1370 // The linkset implimentation might want to know about this.
1371 1467
1468 // The linkset implimentation might want to know about this.
1372 Linkset.UpdateProperties(this); 1469 Linkset.UpdateProperties(this);
1373 } 1470 }
1374} 1471}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 6621d39..27a78d1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -62,7 +62,7 @@ using OpenMetaverse;
62// 62//
63namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
64{ 64{
65public class BSScene : PhysicsScene, IPhysicsParameters 65public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 66{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
@@ -116,6 +116,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
116 // True if initialized and ready to do simulation steps 116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false; 117 private bool m_initialized = false;
118 118
119 // Flag which is true when processing taints.
120 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
121 public bool InTaintTime { get; private set; }
122
119 // Pinned memory used to pass step information between managed and unmanaged 123 // Pinned memory used to pass step information between managed and unmanaged
120 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
121 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
@@ -171,7 +175,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
171 } 175 }
172 } 176 }
173 private Object _taintLock = new Object(); // lock for using the next object 177 private Object _taintLock = new Object(); // lock for using the next object
174 private List<TaintCallbackEntry> _taintedObjects; 178 private List<TaintCallbackEntry> _taintOperations;
179 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
180 private List<TaintCallbackEntry> _postStepOperations;
175 181
176 // A pointer to an instance if this structure is passed to the C++ code 182 // A pointer to an instance if this structure is passed to the C++ code
177 // Used to pass basic configuration values to the unmanaged code. 183 // Used to pass basic configuration values to the unmanaged code.
@@ -203,7 +209,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
203 public override void Initialise(IMesher meshmerizer, IConfigSource config) 209 public override void Initialise(IMesher meshmerizer, IConfigSource config)
204 { 210 {
205 mesher = meshmerizer; 211 mesher = meshmerizer;
206 _taintedObjects = new List<TaintCallbackEntry>(); 212 _taintOperations = new List<TaintCallbackEntry>();
213 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
214 _postStepOperations = new List<TaintCallbackEntry>();
207 PhysObjects = new Dictionary<uint, BSPhysObject>(); 215 PhysObjects = new Dictionary<uint, BSPhysObject>();
208 Shapes = new BSShapeCollection(this); 216 Shapes = new BSShapeCollection(this);
209 217
@@ -266,6 +274,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
266 TerrainManager = new BSTerrainManager(this); 274 TerrainManager = new BSTerrainManager(this);
267 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 275 TerrainManager.CreateInitialGroundPlaneAndTerrain();
268 276
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
278
279 InTaintTime = false;
269 m_initialized = true; 280 m_initialized = true;
270 } 281 }
271 282
@@ -320,7 +331,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
320 { 331 {
321 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 332 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
322 } 333 }
323 334
324 // Called directly from unmanaged code so don't do much 335 // Called directly from unmanaged code so don't do much
325 private void BulletLoggerPhysLog(string msg) 336 private void BulletLoggerPhysLog(string msg)
326 { 337 {
@@ -475,23 +486,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters
475 if (!m_initialized) return 5.0f; 486 if (!m_initialized) return 5.0f;
476 487
477 // update the prim states while we know the physics engine is not busy 488 // update the prim states while we know the physics engine is not busy
478 int numTaints = _taintedObjects.Count; 489 int numTaints = _taintOperations.Count;
479 ProcessTaints(); 490 ProcessTaints();
480 491
481 // Some of the prims operate with special vehicle properties 492 // Some of the prims operate with special vehicle properties
482 ProcessVehicles(timeStep); 493 ProcessVehicles(timeStep);
483 numTaints += _taintedObjects.Count;
484 ProcessTaints(); // the vehicles might have added taints 494 ProcessTaints(); // the vehicles might have added taints
485 495
486 // step the physical world one interval 496 // step the physical world one interval
487 m_simulationStep++; 497 m_simulationStep++;
488 int numSubSteps = 0; 498 int numSubSteps = 0;
489 499
490 // DEBUG
491 // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
492
493 try 500 try
494 { 501 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
495 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
496 504
497 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@@ -500,6 +508,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
500 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
501 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
502 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
503 } 512 }
504 catch (Exception e) 513 catch (Exception e)
505 { 514 {
@@ -511,7 +520,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
511 collidersCount = 0; 520 collidersCount = 0;
512 } 521 }
513 522
514
515 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
516 524
517 // Get a value for 'now' so all the collision and update routines don't have to get their own 525 // Get a value for 'now' so all the collision and update routines don't have to get their own
@@ -545,7 +553,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
545 } 553 }
546 554
547 // This is a kludge to get avatar movement updates. 555 // This is a kludge to get avatar movement updates.
548 // The simulator expects collisions for avatars even if there are have been no collisions. 556 // The simulator expects collisions for avatars even if there are have been no collisions.
549 // The event updates avatar animations and stuff. 557 // The event updates avatar animations and stuff.
550 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. 558 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
551 foreach (BSPhysObject bsp in m_avatars) 559 foreach (BSPhysObject bsp in m_avatars)
@@ -575,6 +583,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
575 } 583 }
576 } 584 }
577 585
586 ProcessPostStepTaints();
587
578 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
579 // Only enable this in a limited test world with few objects. 589 // Only enable this in a limited test world with few objects.
580 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
@@ -670,8 +680,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters
670 680
671 public override bool IsThreaded { get { return false; } } 681 public override bool IsThreaded { get { return false; } }
672 682
683 #region Taints
684
673 // Calls to the PhysicsActors can't directly call into the physics engine 685 // Calls to the PhysicsActors can't directly call into the physics engine
674 // because it might be busy. We delay changes to a known time. 686 // because it might be busy. We delay changes to a known time.
675 // We rely on C#'s closure to save and restore the context for the delegate. 687 // We rely on C#'s closure to save and restore the context for the delegate.
676 public void TaintedObject(String ident, TaintCallback callback) 688 public void TaintedObject(String ident, TaintCallback callback)
677 { 689 {
@@ -679,31 +691,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
679 691
680 lock (_taintLock) 692 lock (_taintLock)
681 { 693 {
682 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 694 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
683 } 695 }
684 696
685 return; 697 return;
686 } 698 }
687 699
700 // Sometimes a potentially tainted operation can be used in and out of taint time.
701 // This routine executes the command immediately if in taint-time otherwise it is queued.
702 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
703 {
704 if (inTaintTime)
705 callback();
706 else
707 TaintedObject(ident, callback);
708 }
709
688 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
689 // a callback into itself to do the actual property change. That callback is called 711 // a callback into itself to do the actual property change. That callback is called
690 // here just before the physics engine is called to step the simulation. 712 // here just before the physics engine is called to step the simulation.
691 public void ProcessTaints() 713 public void ProcessTaints()
692 { 714 {
693 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints();
717 ProcessPostTaintTaints();
718 InTaintTime = false;
719 }
720
721 private void ProcessRegularTaints()
722 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
694 { 724 {
695 // swizzle a new list into the list location so we can process what's there 725 /*
726 // Code to limit the number of taints processed per step. Meant to limit step time.
727 // Unsure if a good idea as code assumes that taints are done before the step.
696 int taintCount = m_taintsToProcessPerStep; 728 int taintCount = m_taintsToProcessPerStep;
697 TaintCallbackEntry oneCallback = new TaintCallbackEntry(); 729 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
698 while (_taintedObjects.Count > 0 && taintCount-- > 0) 730 while (_taintOperations.Count > 0 && taintCount-- > 0)
699 { 731 {
700 bool gotOne = false; 732 bool gotOne = false;
701 lock (_taintLock) 733 lock (_taintLock)
702 { 734 {
703 if (_taintedObjects.Count > 0) 735 if (_taintOperations.Count > 0)
704 { 736 {
705 oneCallback = _taintedObjects[0]; 737 oneCallback = _taintOperations[0];
706 _taintedObjects.RemoveAt(0); 738 _taintOperations.RemoveAt(0);
707 gotOne = true; 739 gotOne = true;
708 } 740 }
709 } 741 }
@@ -711,22 +743,28 @@ public class BSScene : PhysicsScene, IPhysicsParameters
711 { 743 {
712 try 744 try
713 { 745 {
714 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG 746 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
715 oneCallback.callback(); 747 oneCallback.callback();
716 } 748 }
717 catch (Exception e) 749 catch (Exception e)
718 { 750 {
751 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
719 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); 752 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
720 } 753 }
721 } 754 }
722 } 755 }
723 /* 756 if (_taintOperations.Count > 0)
757 {
758 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
759 }
760 */
761
724 // swizzle a new list into the list location so we can process what's there 762 // swizzle a new list into the list location so we can process what's there
725 List<TaintCallbackEntry> oldList; 763 List<TaintCallbackEntry> oldList;
726 lock (_taintLock) 764 lock (_taintLock)
727 { 765 {
728 oldList = _taintedObjects; 766 oldList = _taintOperations;
729 _taintedObjects = new List<TaintCallbackEntry>(); 767 _taintOperations = new List<TaintCallbackEntry>();
730 } 768 }
731 769
732 foreach (TaintCallbackEntry tcbe in oldList) 770 foreach (TaintCallbackEntry tcbe in oldList)
@@ -742,10 +780,103 @@ public class BSScene : PhysicsScene, IPhysicsParameters
742 } 780 }
743 } 781 }
744 oldList.Clear(); 782 oldList.Clear();
745 */
746 } 783 }
747 } 784 }
748 785
786 // Schedule an update to happen after all the regular taints are processed.
787 // Note that new requests for the same operation ("ident") for the same object ("ID")
788 // will replace any previous operation by the same object.
789 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
790 {
791 string uniqueIdent = ident + "-" + ID.ToString();
792 lock (_taintLock)
793 {
794 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
795 }
796
797 return;
798 }
799
800 private void ProcessPostTaintTaints()
801 {
802 if (_postTaintOperations.Count > 0)
803 {
804 Dictionary<string, TaintCallbackEntry> oldList;
805 lock (_taintLock)
806 {
807 oldList = _postTaintOperations;
808 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
809 }
810
811 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
812 {
813 try
814 {
815 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
816 kvp.Value.callback();
817 }
818 catch (Exception e)
819 {
820 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
821 }
822 }
823 oldList.Clear();
824 }
825 }
826
827 public void PostStepTaintObject(String ident, TaintCallback callback)
828 {
829 if (!m_initialized) return;
830
831 lock (_taintLock)
832 {
833 _postStepOperations.Add(new TaintCallbackEntry(ident, callback));
834 }
835
836 return;
837 }
838
839 private void ProcessPostStepTaints()
840 {
841 if (_postStepOperations.Count > 0)
842 {
843 List<TaintCallbackEntry> oldList;
844 lock (_taintLock)
845 {
846 oldList = _postStepOperations;
847 _postStepOperations = new List<TaintCallbackEntry>();
848 }
849
850 foreach (TaintCallbackEntry tcbe in oldList)
851 {
852 try
853 {
854 DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
855 tcbe.callback();
856 }
857 catch (Exception e)
858 {
859 m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
860 }
861 }
862 oldList.Clear();
863 }
864 }
865
866 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom)
868 {
869 if (!InTaintTime)
870 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
872 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
873 Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
874 }
875 return InTaintTime;
876 }
877
878 #endregion // Taints
879
749 #region Vehicles 880 #region Vehicles
750 881
751 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 882 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
@@ -916,7 +1047,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
916 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 1047 (s) => { return (float)s.m_maxUpdatesPerFrame; },
917 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 1048 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
918 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", 1049 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
919 100f, 1050 500f,
920 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, 1051 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
921 (s) => { return (float)s.m_taintsToProcessPerStep; }, 1052 (s) => { return (float)s.m_taintsToProcessPerStep; },
922 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), 1053 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
@@ -970,50 +1101,55 @@ public class BSScene : PhysicsScene, IPhysicsParameters
970 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 1101 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].linearDamping; }, 1102 (s) => { return s.m_params[0].linearDamping; },
972 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, 1103 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
973 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), 1104 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
974 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 1105 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
975 0f, 1106 0f,
976 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 1107 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
977 (s) => { return s.m_params[0].angularDamping; }, 1108 (s) => { return s.m_params[0].angularDamping; },
978 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, 1109 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
979 (s,o,v) => { BulletSimAPI.SetDamping2(o.BSBody.ptr, v, v); } ), 1110 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
980 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 1111 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
981 0.2f, 1112 0.2f,
982 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 1113 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].deactivationTime; }, 1114 (s) => { return s.m_params[0].deactivationTime; },
984 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, 1115 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
985 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.BSBody.ptr, v); } ), 1116 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
986 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 1117 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
987 0.8f, 1118 0.8f,
988 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 1119 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
989 (s) => { return s.m_params[0].linearSleepingThreshold; }, 1120 (s) => { return s.m_params[0].linearSleepingThreshold; },
990 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, 1121 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
991 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), 1122 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
992 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 1123 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
993 1.0f, 1124 1.0f,
994 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 1125 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
995 (s) => { return s.m_params[0].angularSleepingThreshold; }, 1126 (s) => { return s.m_params[0].angularSleepingThreshold; },
996 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, 1127 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
997 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.BSBody.ptr, v, v); } ), 1128 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
998 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 1129 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
999 0f, // set to zero to disable 1130 0f, // set to zero to disable
1000 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1131 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1001 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1132 (s) => { return s.m_params[0].ccdMotionThreshold; },
1002 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, 1133 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1003 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.BSBody.ptr, v); } ), 1134 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
1004 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1135 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1005 0f, 1136 0f,
1006 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1137 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1007 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1138 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1008 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, 1139 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1009 (s,o,v) => { BulletSimAPI.SetCcdSweepSphereRadius2(o.BSBody.ptr, v); } ), 1140 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1141 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 1142 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1143 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1144 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, 1145 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1015 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.BSBody.ptr, v); } ), 1146 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1016 1147
1148 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
1149 (float)BSTerrainPhys.TerrainImplementation.Mesh,
1150 (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
1151 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1017 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1018 0.5f, 1154 0.5f,
1019 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
@@ -1049,11 +1185,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1049 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1185 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1050 (s) => { return s.m_params[0].avatarRestitution; }, 1186 (s) => { return s.m_params[0].avatarRestitution; },
1051 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1052 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 1188 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
1053 0.37f, 1189 0.6f,
1054 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1190 (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
1055 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1191 (s) => { return s.m_params[0].avatarCapsuleWidth; },
1056 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1192 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
1193 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
1194 0.45f,
1195 (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
1196 (s) => { return s.m_params[0].avatarCapsuleDepth; },
1197 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
1057 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1198 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1058 1.5f, 1199 1.5f,
1059 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1200 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
@@ -1107,6 +1248,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1107 (s) => { return s.m_params[0].numberOfSolverIterations; }, 1248 (s) => { return s.m_params[0].numberOfSolverIterations; },
1108 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), 1249 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1109 1250
1251 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1252 (float)BSLinkset.LinksetImplementation.Compound,
1253 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1254 (s) => { return s.m_params[0].linksetImplementation; },
1255 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
1110 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 1256 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1111 ConfigurationParameters.numericFalse, 1257 ConfigurationParameters.numericFalse,
1112 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1258 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
@@ -1128,12 +1274,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1128 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1274 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1129 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1275 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1130 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", 1276 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1131 0.001f, 1277 0.1f,
1132 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1278 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1133 (s) => { return s.m_params[0].linkConstraintCFM; }, 1279 (s) => { return s.m_params[0].linkConstraintCFM; },
1134 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1280 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1135 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1281 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1136 0.8f, 1282 0.1f,
1137 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1283 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1138 (s) => { return s.m_params[0].linkConstraintERP; }, 1284 (s) => { return s.m_params[0].linkConstraintERP; },
1139 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1285 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
@@ -1259,7 +1405,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1259 // If the local ID is APPLY_TO_NONE, just change the default value 1405 // If the local ID is APPLY_TO_NONE, just change the default value
1260 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1406 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1261 // If the localID is a specific object, apply the parameter change to only that object 1407 // If the localID is a specific object, apply the parameter change to only that object
1262 protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) 1408 private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1263 { 1409 {
1264 List<uint> objectIDs = new List<uint>(); 1410 List<uint> objectIDs = new List<uint>();
1265 switch (localID) 1411 switch (localID)
@@ -1284,7 +1430,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1284 } 1430 }
1285 1431
1286 // schedule the actual updating of the paramter to when the phys engine is not busy 1432 // schedule the actual updating of the paramter to when the phys engine is not busy
1287 protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) 1433 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1288 { 1434 {
1289 float xval = val; 1435 float xval = val;
1290 List<uint> xlIDs = lIDs; 1436 List<uint> xlIDs = lIDs;
@@ -1326,14 +1472,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1326 1472
1327 #endregion Runtime settable parameters 1473 #endregion Runtime settable parameters
1328 1474
1475 // Debugging routine for dumping detailed physical information for vehicle prims
1476 private void DumpVehicles()
1477 {
1478 foreach (BSPrim prim in m_vehicles)
1479 {
1480 BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
1481 BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
1482 }
1483 }
1484
1329 // Invoke the detailed logger and output something if it's enabled. 1485 // Invoke the detailed logger and output something if it's enabled.
1330 public void DetailLog(string msg, params Object[] args) 1486 public void DetailLog(string msg, params Object[] args)
1331 { 1487 {
1332 PhysicsLogging.Write(msg, args); 1488 PhysicsLogging.Write(msg, args);
1333 // Add the Flush() if debugging crashes to get all the messages written out. 1489 // Add the Flush() if debugging crashes. Gets all the messages written out.
1334 // PhysicsLogging.Flush(); 1490 // PhysicsLogging.Flush();
1335 } 1491 }
1336 // used to fill in the LocalID when there isn't one 1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1337 public const string DetailLogZero = "0000000000"; 1493 public const string DetailLogZero = "0000000000";
1338 1494
1339} 1495}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index d3ba273..892c34b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -34,11 +34,11 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSShapeCollection : IDisposable 37public sealed class BSShapeCollection : IDisposable
38{ 38{
39 // private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; 39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40 40
41 protected BSScene PhysicsScene { get; set; } 41 private BSScene PhysicsScene { get; set; }
42 42
43 private Object m_collectionActivityLock = new Object(); 43 private Object m_collectionActivityLock = new Object();
44 44
@@ -48,6 +48,7 @@ public class BSShapeCollection : IDisposable
48 public IntPtr ptr; 48 public IntPtr ptr;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
51 } 52 }
52 53
53 // Description of a hull. 54 // Description of a hull.
@@ -57,6 +58,7 @@ public class BSShapeCollection : IDisposable
57 public IntPtr ptr; 58 public IntPtr ptr;
58 public int referenceCount; 59 public int referenceCount;
59 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
60 } 62 }
61 63
62 // The sharable set of meshes and hulls. Indexed by their shape hash. 64 // The sharable set of meshes and hulls. Indexed by their shape hash.
@@ -89,10 +91,11 @@ public class BSShapeCollection : IDisposable
89 // higher level dependencies on the shape or body. Mostly used for LinkSets to 91 // higher level dependencies on the shape or body. Mostly used for LinkSets to
90 // remove the physical constraints before the body is destroyed. 92 // remove the physical constraints before the body is destroyed.
91 // Called at taint-time!! 93 // Called at taint-time!!
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeData shapeData, PrimitiveBaseShape pbs,
94 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
95 { 96 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
98
96 bool ret = false; 99 bool ret = false;
97 100
98 // This lock could probably be pushed down lower but building shouldn't take long 101 // This lock could probably be pushed down lower but building shouldn't take long
@@ -100,41 +103,38 @@ public class BSShapeCollection : IDisposable
100 { 103 {
101 // Do we have the correct geometry for this type of object? 104 // Do we have the correct geometry for this type of object?
102 // Updates prim.BSShape with information/pointers to shape. 105 // Updates prim.BSShape with information/pointers to shape.
103 // CreateGeom returns 'true' of BSShape as changed to a new shape. 106 // Returns 'true' of BSShape is changed to a new shape.
104 bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); 107 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
105 // If we had to select a new shape geometry for the object, 108 // If we had to select a new shape geometry for the object,
106 // rebuild the body around it. 109 // rebuild the body around it.
107 // Updates prim.BSBody with information/pointers to requested body 110 // Updates prim.BSBody with information/pointers to requested body
108 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, 111 // Returns 'true' if BSBody was changed.
109 prim.BSShape, shapeData, bodyCallback); 112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
113 prim.PhysShape, bodyCallback);
110 ret = newGeom || newBody; 114 ret = newGeom || newBody;
111 } 115 }
112 DetailLog("{0},BSShapeCollection.GetBodyAndShape,force={1},ret={2},body={3},shape={4}", 116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
113 prim.LocalID, forceRebuild, ret, prim.BSBody, prim.BSShape); 117 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
114 118
115 return ret; 119 return ret;
116 } 120 }
117 121
118 // Track another user of a body 122 // Track another user of a body.
119 // We presume the caller has allocated the body. 123 // We presume the caller has allocated the body.
120 // Bodies only have one user so the body is just put into the world if not already there. 124 // Bodies only have one user so the body is just put into the world if not already there.
121 public void ReferenceBody(BulletBody body, bool inTaintTime) 125 public void ReferenceBody(BulletBody body, bool inTaintTime)
122 { 126 {
123 lock (m_collectionActivityLock) 127 lock (m_collectionActivityLock)
124 { 128 {
125 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); 129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
126 BSScene.TaintCallback createOperation = delegate() 130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
127 { 131 {
128 if (!BulletSimAPI.IsInWorld2(body.ptr)) 132 if (!BulletSimAPI.IsInWorld2(body.ptr))
129 { 133 {
130 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
131 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
132 } 136 }
133 }; 137 });
134 if (inTaintTime)
135 createOperation();
136 else
137 PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
138 } 138 }
139 } 139 }
140 140
@@ -147,25 +147,23 @@ public class BSShapeCollection : IDisposable
147 147
148 lock (m_collectionActivityLock) 148 lock (m_collectionActivityLock)
149 { 149 {
150 BSScene.TaintCallback removeOperation = delegate() 150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 151 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", 152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body.ptr.ToString("X"), inTaintTime); 153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 155 if (bodyCallback != null) bodyCallback(body);
156 156
157 // It may have already been removed from the world in which case the next is a NOOP. 157 if (BulletSimAPI.IsInWorld2(body.ptr))
158 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 158 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 }
159 162
160 // Zero any reference to the shape so it is not freed when the body is deleted. 163 // Zero any reference to the shape so it is not freed when the body is deleted.
161 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
162 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
163 }; 166 });
164 // If already in taint-time, do the operations now. Otherwise queue for later.
165 if (inTaintTime)
166 removeOperation();
167 else
168 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation);
169 } 167 }
170 } 168 }
171 169
@@ -175,12 +173,12 @@ public class BSShapeCollection : IDisposable
175 // Meshes and hulls for the same shape have the same hash key. 173 // Meshes and hulls for the same shape have the same hash key.
176 // NOTE that native shapes are not added to the mesh list or removed. 174 // NOTE that native shapes are not added to the mesh list or removed.
177 // Returns 'true' if this is the initial reference to the shape. Otherwise reused. 175 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
178 private bool ReferenceShape(BulletShape shape) 176 public bool ReferenceShape(BulletShape shape)
179 { 177 {
180 bool ret = false; 178 bool ret = false;
181 switch (shape.type) 179 switch (shape.type)
182 { 180 {
183 case ShapeData.PhysicsShapeType.SHAPE_MESH: 181 case BSPhysicsShapeType.SHAPE_MESH:
184 MeshDesc meshDesc; 182 MeshDesc meshDesc;
185 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc)) 183 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
186 { 184 {
@@ -193,6 +191,7 @@ public class BSShapeCollection : IDisposable
193 { 191 {
194 // This is a new reference to a mesh 192 // This is a new reference to a mesh
195 meshDesc.ptr = shape.ptr; 193 meshDesc.ptr = shape.ptr;
194 meshDesc.shapeKey = shape.shapeKey;
196 // We keep a reference to the underlying IMesh data so a hull can be built 195 // We keep a reference to the underlying IMesh data so a hull can be built
197 meshDesc.referenceCount = 1; 196 meshDesc.referenceCount = 1;
198 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
@@ -202,7 +201,7 @@ public class BSShapeCollection : IDisposable
202 meshDesc.lastReferenced = System.DateTime.Now; 201 meshDesc.lastReferenced = System.DateTime.Now;
203 Meshes[shape.shapeKey] = meshDesc; 202 Meshes[shape.shapeKey] = meshDesc;
204 break; 203 break;
205 case ShapeData.PhysicsShapeType.SHAPE_HULL: 204 case BSPhysicsShapeType.SHAPE_HULL:
206 HullDesc hullDesc; 205 HullDesc hullDesc;
207 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc)) 206 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
208 { 207 {
@@ -215,6 +214,7 @@ public class BSShapeCollection : IDisposable
215 { 214 {
216 // This is a new reference to a hull 215 // This is a new reference to a hull
217 hullDesc.ptr = shape.ptr; 216 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 218 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
@@ -224,7 +224,7 @@ public class BSShapeCollection : IDisposable
224 hullDesc.lastReferenced = System.DateTime.Now; 224 hullDesc.lastReferenced = System.DateTime.Now;
225 Hulls[shape.shapeKey] = hullDesc; 225 Hulls[shape.shapeKey] = hullDesc;
226 break; 226 break;
227 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 227 case BSPhysicsShapeType.SHAPE_UNKNOWN:
228 break; 228 break;
229 default: 229 default:
230 // Native shapes are not tracked and they don't go into any list 230 // Native shapes are not tracked and they don't go into any list
@@ -239,7 +239,7 @@ public class BSShapeCollection : IDisposable
239 if (shape.ptr == IntPtr.Zero) 239 if (shape.ptr == IntPtr.Zero)
240 return; 240 return;
241 241
242 BSScene.TaintCallback dereferenceOperation = delegate() 242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 243 {
244 if (shape.ptr != IntPtr.Zero) 244 if (shape.ptr != IntPtr.Zero)
245 { 245 {
@@ -255,31 +255,23 @@ public class BSShapeCollection : IDisposable
255 { 255 {
256 switch (shape.type) 256 switch (shape.type)
257 { 257 {
258 case ShapeData.PhysicsShapeType.SHAPE_HULL: 258 case BSPhysicsShapeType.SHAPE_HULL:
259 DereferenceHull(shape, shapeCallback); 259 DereferenceHull(shape, shapeCallback);
260 break; 260 break;
261 case ShapeData.PhysicsShapeType.SHAPE_MESH: 261 case BSPhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback); 262 DereferenceMesh(shape, shapeCallback);
263 break; 263 break;
264 case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: 264 case BSPhysicsShapeType.SHAPE_COMPOUND:
265 DereferenceCompound(shape, shapeCallback);
266 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN:
265 break; 268 break;
266 default: 269 default:
267 break; 270 break;
268 } 271 }
269 } 272 }
270 } 273 }
271 }; 274 });
272 if (inTaintTime)
273 {
274 lock (m_collectionActivityLock)
275 {
276 dereferenceOperation();
277 }
278 }
279 else
280 {
281 PhysicsScene.TaintedObject("BSShapeCollection.DereferenceShape", dereferenceOperation);
282 }
283 } 275 }
284 276
285 // Count down the reference count for a mesh shape 277 // Count down the reference count for a mesh shape
@@ -294,8 +286,8 @@ public class BSShapeCollection : IDisposable
294 if (shapeCallback != null) shapeCallback(shape); 286 if (shapeCallback != null) shapeCallback(shape);
295 meshDesc.lastReferenced = System.DateTime.Now; 287 meshDesc.lastReferenced = System.DateTime.Now;
296 Meshes[shape.shapeKey] = meshDesc; 288 Meshes[shape.shapeKey] = meshDesc;
297 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}", 289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
298 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 290 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
299 291
300 } 292 }
301 } 293 }
@@ -309,11 +301,94 @@ public class BSShapeCollection : IDisposable
309 { 301 {
310 hullDesc.referenceCount--; 302 hullDesc.referenceCount--;
311 // TODO: release the Bullet storage (aging old entries?) 303 // TODO: release the Bullet storage (aging old entries?)
304
305 // Tell upper layers that, if they have dependencies on this shape, this link is going away
312 if (shapeCallback != null) shapeCallback(shape); 306 if (shapeCallback != null) shapeCallback(shape);
307
313 hullDesc.lastReferenced = System.DateTime.Now; 308 hullDesc.lastReferenced = System.DateTime.Now;
314 Hulls[shape.shapeKey] = hullDesc; 309 Hulls[shape.shapeKey] = hullDesc;
315 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", 310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
316 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 311 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 }
313 }
314
315 // Remove a reference to a compound shape.
316 // Taking a compound shape apart is a little tricky because if you just delete the
317 // physical shape, it will free all the underlying children. We can't do that because
318 // they could be shared. So, this removes each of the children from the compound and
319 // dereferences them separately before destroying the compound collision object itself.
320 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr))
324 {
325 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return;
331 }
332
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335
336 for (int ii = numChildren - 1; ii >= 0; ii--)
337 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
339 DereferenceAnonCollisionShape(childShape);
340 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
342 }
343
344 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine.
346 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape)
348 {
349 MeshDesc meshDesc;
350 HullDesc hullDesc;
351
352 BulletShape shapeInfo = new BulletShape(cShape);
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey;
357 }
358 else
359 {
360 if (TryGetHullByPtr(cShape, out hullDesc))
361 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey;
364 }
365 else
366 {
367 if (BulletSimAPI.IsCompound2(cShape))
368 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 }
371 else
372 {
373 if (BulletSimAPI.IsNativeShape2(cShape))
374 {
375 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
377 }
378 }
379 }
380 }
381
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 {
386 DereferenceShape(shapeInfo, true, null);
387 }
388 else
389 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X"));
317 } 392 }
318 } 393 }
319 394
@@ -325,21 +400,46 @@ public class BSShapeCollection : IDisposable
325 // Info in prim.BSShape is updated to the new shape. 400 // Info in prim.BSShape is updated to the new shape.
326 // Returns 'true' if the geometry was rebuilt. 401 // Returns 'true' if the geometry was rebuilt.
327 // Called at taint-time! 402 // Called at taint-time!
328 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, 403 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
329 PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback)
330 { 404 {
331 bool ret = false; 405 bool ret = false;
332 bool haveShape = false; 406 bool haveShape = false;
333 bool nativeShapePossible = true;
334 407
335 if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
336 { 409 {
337 // an avatar capsule is close to a native shape (it is not shared) 410 // an avatar capsule is close to a native shape (it is not shared)
338 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, 411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
339 ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); 412 FixedShapeKey.KEY_CAPSULE, shapeCallback);
340 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); 413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true;
341 haveShape = true; 415 haveShape = true;
342 } 416 }
417
418 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true;
425 }
426
427 if (!haveShape)
428 {
429 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
430 }
431
432 return ret;
433 }
434
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 {
438 bool ret = false;
439 bool haveShape = false;
440 bool nativeShapePossible = true;
441 PrimitiveBaseShape pbs = prim.BaseShape;
442
343 // If the prim attributes are simple, this could be a simple Bullet native shape 443 // If the prim attributes are simple, this could be a simple Bullet native shape
344 if (!haveShape 444 if (!haveShape
345 && pbs != null 445 && pbs != null
@@ -353,97 +453,120 @@ public class BSShapeCollection : IDisposable
353 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
354 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
355 { 455 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
356 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
357 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
358 { 459 {
359 haveShape = true; 460 haveShape = true;
360 if (forceRebuild 461 if (forceRebuild
361 || prim.Scale != shapeData.Size 462 || prim.Scale != prim.Size
362 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE 463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
363 ) 464 )
364 { 465 {
365 ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, 466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
366 ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); 467 FixedShapeKey.KEY_SPHERE, shapeCallback);
367 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
368 prim.LocalID, forceRebuild, prim.BSShape); 469 prim.LocalID, forceRebuild, prim.PhysShape);
369 } 470 }
370 } 471 }
371 if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
372 { 473 {
373 haveShape = true; 474 haveShape = true;
374 if (forceRebuild 475 if (forceRebuild
375 || prim.Scale != shapeData.Size 476 || prim.Scale != prim.Size
376 || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX 477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
377 ) 478 )
378 { 479 {
379 ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, 480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
380 ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); 481 FixedShapeKey.KEY_BOX, shapeCallback);
381 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
382 prim.LocalID, forceRebuild, prim.BSShape); 483 prim.LocalID, forceRebuild, prim.PhysShape);
383 } 484 }
384 } 485 }
385 } 486 }
487
386 // If a simple shape is not happening, create a mesh and possibly a hull. 488 // If a simple shape is not happening, create a mesh and possibly a hull.
387 // Note that if it's a native shape, the check for physical/non-physical is not
388 // made. Native shapes are best used in either case.
389 if (!haveShape && pbs != null) 489 if (!haveShape && pbs != null)
390 { 490 {
391 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 491 ret = CreateGeomMeshOrHull(prim, shapeCallback);
392 { 492 }
393 // Update prim.BSShape to reference a hull of this shape. 493
394 ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); 494 return ret;
395 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 495 }
396 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 496
397 } 497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
398 else 498 {
399 { 499
400 ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback); 500 bool ret = false;
401 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 501 // Note that if it's a native shape, the check for physical/non-physical is not
402 shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); 502 // made. Native shapes work in either case.
403 } 503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
504 {
505 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 }
510 else
511 {
512 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
404 } 515 }
405 return ret; 516 return ret;
406 } 517 }
407 518
408 // Creates a native shape and assignes it to prim.BSShape. 519 // Creates a native shape and assignes it to prim.BSShape.
409 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). 520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
410 private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, 521 private bool GetReferenceToNativeShape(BSPhysObject prim,
411 ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, 522 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
412 ShapeDestructionCallback shapeCallback) 523 ShapeDestructionCallback shapeCallback)
413 { 524 {
414
415 shapeData.Type = shapeType;
416 // Bullet native objects are scaled by the Bullet engine so pass the size in
417 prim.Scale = shapeData.Size;
418 shapeData.Scale = shapeData.Size;
419
420 // release any previous shape 525 // release any previous shape
421 DereferenceShape(prim.BSShape, true, shapeCallback); 526 DereferenceShape(prim.PhysShape, true, shapeCallback);
422 527
423 BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); 528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
424 529
425 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
426 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
427 shapeData.ID, newShape, shapeData.Scale); 532 prim.LocalID, newShape, prim.Scale);
428 533
429 prim.BSShape = newShape; 534 prim.PhysShape = newShape;
430 return true; 535 return true;
431 } 536 }
432 537
433 private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, 538 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
434 ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) 539 FixedShapeKey shapeKey)
435 { 540 {
436 BulletShape newShape; 541 BulletShape newShape;
437 542 // Need to make sure the passed shape information is for the native type.
438 if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) 543 ShapeData nativeShapeData = new ShapeData();
544 nativeShapeData.Type = shapeType;
545 nativeShapeData.ID = prim.LocalID;
546 nativeShapeData.Scale = prim.Scale;
547 nativeShapeData.Size = prim.Scale; // unneeded, I think.
548 nativeShapeData.MeshKey = (ulong)shapeKey;
549 nativeShapeData.HullKey = (ulong)shapeKey;
550
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
439 { 552 {
553 // The proper scale has been calculated in the prim.
440 newShape = new BulletShape( 554 newShape = new BulletShape(
441 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), 555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
442 shapeType); 556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
443 } 558 }
444 else 559 else
445 { 560 {
446 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); 561 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size;
563 nativeShapeData.Scale = prim.Scale;
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 }
566 if (newShape.ptr == IntPtr.Zero)
567 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType);
447 } 570 }
448 newShape.shapeKey = (System.UInt64)shapeKey; 571 newShape.shapeKey = (System.UInt64)shapeKey;
449 newShape.isNativeShape = true; 572 newShape.isNativeShape = true;
@@ -455,33 +578,32 @@ public class BSShapeCollection : IDisposable
455 // Dereferences previous shape in BSShape and adds a reference for this new shape. 578 // Dereferences previous shape in BSShape and adds a reference for this new shape.
456 // Returns 'true' of a mesh was actually built. Otherwise . 579 // Returns 'true' of a mesh was actually built. Otherwise .
457 // Called at taint-time! 580 // Called at taint-time!
458 private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
459 ShapeDestructionCallback shapeCallback)
460 { 582 {
461 BulletShape newShape = new BulletShape(IntPtr.Zero); 583 BulletShape newShape = new BulletShape(IntPtr.Zero);
462 584
463 float lod; 585 float lod;
464 System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); 586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
465 587
466 // if this new shape is the same as last time, don't recreate the mesh 588 // if this new shape is the same as last time, don't recreate the mesh
467 if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) 589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
468 return false; 590 return false;
469 591
470 DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", 592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
471 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
472 594
473 // Since we're recreating new, get rid of the reference to the previous shape 595 // Since we're recreating new, get rid of the reference to the previous shape
474 DereferenceShape(prim.BSShape, true, shapeCallback); 596 DereferenceShape(prim.PhysShape, true, shapeCallback);
475 597
476 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); 598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
477 // Take evasive action if the mesh was not constructed. 599 // Take evasive action if the mesh was not constructed.
478 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 600 newShape = VerifyMeshCreated(newShape, prim);
479 601
480 ReferenceShape(newShape); 602 ReferenceShape(newShape);
481 603
482 // meshes are already scaled by the meshmerizer 604 // meshes are already scaled by the meshmerizer
483 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
484 prim.BSShape = newShape; 606 prim.PhysShape = newShape;
485 607
486 return true; // 'true' means a new shape has been added to this prim 608 return true; // 'true' means a new shape has been added to this prim
487 } 609 }
@@ -515,14 +637,14 @@ public class BSShapeCollection : IDisposable
515 verticesAsFloats[vi++] = vv.Z; 637 verticesAsFloats[vi++] = vv.Z;
516 } 638 }
517 639
518 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
519 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
520 642
521 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
522 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
523 } 645 }
524 } 646 }
525 BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); 647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
526 newShape.shapeKey = newMeshKey; 648 newShape.shapeKey = newMeshKey;
527 649
528 return newShape; 650 return newShape;
@@ -530,32 +652,31 @@ public class BSShapeCollection : IDisposable
530 652
531 // See that hull shape exists in the physical world and update prim.BSShape. 653 // See that hull shape exists in the physical world and update prim.BSShape.
532 // We could be creating the hull because scale changed or whatever. 654 // We could be creating the hull because scale changed or whatever.
533 private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, 655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
534 ShapeDestructionCallback shapeCallback)
535 { 656 {
536 BulletShape newShape; 657 BulletShape newShape;
537 658
538 float lod; 659 float lod;
539 System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); 660 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
540 661
541 // if the hull hasn't changed, don't rebuild it 662 // if the hull hasn't changed, don't rebuild it
542 if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) 663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
543 return false; 664 return false;
544 665
545 DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", 666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
546 prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
547 668
548 // Remove usage of the previous shape. 669 // Remove usage of the previous shape.
549 DereferenceShape(prim.BSShape, true, shapeCallback); 670 DereferenceShape(prim.PhysShape, true, shapeCallback);
550 671
551 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); 672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
552 newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); 673 newShape = VerifyMeshCreated(newShape, prim);
553 674
554 ReferenceShape(newShape); 675 ReferenceShape(newShape);
555 676
556 // hulls are already scaled by the meshmerizer 677 // hulls are already scaled by the meshmerizer
557 prim.Scale = new OMV.Vector3(1f, 1f, 1f); 678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
558 prim.BSShape = newShape; 679 prim.PhysShape = newShape;
559 return true; // 'true' means a new shape has been added to this prim 680 return true; // 'true' means a new shape has been added to this prim
560 } 681 }
561 682
@@ -660,7 +781,7 @@ public class BSShapeCollection : IDisposable
660 } 781 }
661 } 782 }
662 783
663 BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); 784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
664 newShape.shapeKey = newHullKey; 785 newShape.shapeKey = newHullKey;
665 786
666 return newShape; // 'true' means a new shape has been added to this prim 787 return newShape; // 'true' means a new shape has been added to this prim
@@ -674,9 +795,31 @@ public class BSShapeCollection : IDisposable
674 return; 795 return;
675 } 796 }
676 797
798 // Compound shapes are always built from scratch.
799 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
800 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
801 {
802 // Remove reference to the old shape
803 // Don't need to do this as the shape is freed when the new root shape is created below.
804 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805
806 BulletShape cShape = new BulletShape(
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape);
814
815 prim.PhysShape = cShape;
816
817 return true;
818 }
819
677 // Create a hash of all the shape parameters to be used as a key 820 // Create a hash of all the shape parameters to be used as a key
678 // for this particular shape. 821 // for this particular shape.
679 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) 822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
680 { 823 {
681 // level of detail based on size and type of the object 824 // level of detail based on size and type of the object
682 float lod = PhysicsScene.MeshLOD; 825 float lod = PhysicsScene.MeshLOD;
@@ -684,33 +827,40 @@ public class BSShapeCollection : IDisposable
684 lod = PhysicsScene.SculptLOD; 827 lod = PhysicsScene.SculptLOD;
685 828
686 // Mega prims usually get more detail because one can interact with shape approximations at this size. 829 // Mega prims usually get more detail because one can interact with shape approximations at this size.
687 float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); 830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
688 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
689 lod = PhysicsScene.MeshMegaPrimLOD; 832 lod = PhysicsScene.MeshMegaPrimLOD;
690 833
691 retLod = lod; 834 retLod = lod;
692 return pbs.GetMeshKey(shapeData.Size, lod); 835 return pbs.GetMeshKey(size, lod);
693 } 836 }
694 // For those who don't want the LOD 837 // For those who don't want the LOD
695 private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) 838 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
696 { 839 {
697 float lod; 840 float lod;
698 return ComputeShapeKey(shapeData, pbs, out lod); 841 return ComputeShapeKey(size, pbs, out lod);
699 } 842 }
700 843
701 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) 844 // The creation of a mesh or hull can fail if an underlying asset is not available.
845 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
846 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
847 // The first case causes the asset to be fetched. The second case requires
848 // us to not loop forever.
849 // Called after creating a physical mesh or hull. If the physical shape was created,
850 // just return.
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
702 { 852 {
703 // If the shape was successfully created, nothing more to do 853 // If the shape was successfully created, nothing more to do
704 if (newShape.ptr != IntPtr.Zero) 854 if (newShape.ptr != IntPtr.Zero)
705 return newShape; 855 return newShape;
706 856
707 // The most common reason for failure is that an underlying asset is not available
708
709 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
710 if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) 858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
711 { 859 {
712 prim.LastAssetBuildFailed = true; 860 prim.LastAssetBuildFailed = true;
713 BSPhysObject xprim = prim; 861 BSPhysObject xprim = prim;
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
714 Util.FireAndForget(delegate 864 Util.FireAndForget(delegate
715 { 865 {
716 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; 866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
@@ -724,20 +874,28 @@ public class BSShapeCollection : IDisposable
724 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) 874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
725 return; 875 return;
726 876
727 yprim.BaseShape.SculptData = new byte[asset.Data.Length]; 877 yprim.BaseShape.SculptData = asset.Data;
728 asset.Data.CopyTo(yprim.BaseShape.SculptData, 0);
729 // This will cause the prim to see that the filler shape is not the right 878 // This will cause the prim to see that the filler shape is not the right
730 // one and try again to build the object. 879 // one and try again to build the object.
880 // No race condition with the normal shape setting since the rebuild is at taint time.
731 yprim.ForceBodyShapeRebuild(false); 881 yprim.ForceBodyShapeRebuild(false);
732 882
733 }); 883 });
734 } 884 }
735 }); 885 });
736 } 886 }
887 else
888 {
889 if (prim.LastAssetBuildFailed)
890 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
893 }
894 }
737 895
738 // While we figure out the real problem, stick a simple native shape on the object. 896 // While we figure out the real problem, stick a simple native shape on the object.
739 BulletShape fillinShape = 897 BulletShape fillinShape =
740 BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); 898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
741 899
742 return fillinShape; 900 return fillinShape;
743 } 901 }
@@ -746,52 +904,51 @@ public class BSShapeCollection : IDisposable
746 // Updates prim.BSBody with the information about the new body if one is created. 904 // Updates prim.BSBody with the information about the new body if one is created.
747 // Returns 'true' if an object was actually created. 905 // Returns 'true' if an object was actually created.
748 // Called at taint-time. 906 // Called at taint-time.
749 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
750 ShapeData shapeData, BodyDestructionCallback bodyCallback) 908 BodyDestructionCallback bodyCallback)
751 { 909 {
752 bool ret = false; 910 bool ret = false;
753 911
754 // the mesh, hull or native shape must have already been created in Bullet 912 // the mesh, hull or native shape must have already been created in Bullet
755 bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero); 913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
756 914
757 // If there is an existing body, verify it's of an acceptable type. 915 // If there is an existing body, verify it's of an acceptable type.
758 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
759 if (!mustRebuild) 917 if (!mustRebuild)
760 { 918 {
761 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr); 919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
762 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
763 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
764 { 922 {
765 // If the collisionObject is not the correct type for solidness, rebuild what's there 923 // If the collisionObject is not the correct type for solidness, rebuild what's there
766 mustRebuild = true; 924 mustRebuild = true;
767 } 925 }
768
769 } 926 }
770 927
771 if (mustRebuild || forceRebuild) 928 if (mustRebuild || forceRebuild)
772 { 929 {
773 // Free any old body 930 // Free any old body
774 DereferenceBody(prim.BSBody, true, bodyCallback); 931 DereferenceBody(prim.PhysBody, true, bodyCallback);
775 932
776 BulletBody aBody; 933 BulletBody aBody;
777 IntPtr bodyPtr = IntPtr.Zero; 934 IntPtr bodyPtr = IntPtr.Zero;
778 if (prim.IsSolid) 935 if (prim.IsSolid)
779 { 936 {
780 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
781 shapeData.ID, shapeData.Position, shapeData.Rotation); 938 prim.LocalID, prim.RawPosition, prim.RawOrientation);
782 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
783 } 940 }
784 else 941 else
785 { 942 {
786 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
787 shapeData.ID, shapeData.Position, shapeData.Rotation); 944 prim.LocalID, prim.RawPosition, prim.RawOrientation);
788 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); 945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
789 } 946 }
790 aBody = new BulletBody(shapeData.ID, bodyPtr); 947 aBody = new BulletBody(prim.LocalID, bodyPtr);
791 948
792 ReferenceBody(aBody, true); 949 ReferenceBody(aBody, true);
793 950
794 prim.BSBody = aBody; 951 prim.PhysBody = aBody;
795 952
796 ret = true; 953 ret = true;
797 } 954 }
@@ -799,6 +956,42 @@ public class BSShapeCollection : IDisposable
799 return ret; 956 return ret;
800 } 957 }
801 958
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc)
960 {
961 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values)
964 {
965 if (md.ptr == addr)
966 {
967 foundDesc = md;
968 ret = true;
969 break;
970 }
971
972 }
973 outDesc = foundDesc;
974 return ret;
975 }
976
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc)
978 {
979 bool ret = false;
980 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values)
982 {
983 if (hd.ptr == addr)
984 {
985 foundDesc = hd;
986 ret = true;
987 break;
988 }
989
990 }
991 outDesc = foundDesc;
992 return ret;
993 }
994
802 private void DetailLog(string msg, params Object[] args) 995 private void DetailLog(string msg, params Object[] args)
803 { 996 {
804 if (PhysicsScene.PhysicsLogging.Enabled) 997 if (PhysicsScene.PhysicsLogging.Enabled)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
new file mode 100755
index 0000000..96cd55e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -0,0 +1,208 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public abstract class BSShape
36{
37 public IntPtr ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; }
42
43 public BSShape()
44 {
45 ptr = IntPtr.Zero;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now;
50 }
51
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 {
55 BSShape ret = null;
56
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 {
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73
74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76
77 return ret;
78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 {
81 return null;
82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 {
85 return null;
86 }
87
88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene);
90
91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference();
93
94 public override string ToString()
95 {
96 StringBuilder buff = new StringBuilder();
97 buff.Append("<p=");
98 buff.Append(ptr.ToString("X"));
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c=");
104 buff.Append(referenceCount.ToString());
105 buff.Append(">");
106 return buff.ToString();
107 }
108}
109
110public class BSShapeNull : BSShape
111{
112 public BSShapeNull() : base()
113 {
114 }
115 public static BSShape GetReference() { return new BSShapeNull(); }
116 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
117}
118
119public class BSShapeNative : BSShape
120{
121 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
122 public BSShapeNative() : base()
123 {
124 }
125 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 {
128 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
130 }
131
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
133 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
134 {
135 ShapeData nativeShapeData = new ShapeData();
136 nativeShapeData.Type = shapeType;
137 nativeShapeData.ID = prim.LocalID;
138 nativeShapeData.Scale = prim.Scale;
139 nativeShapeData.Size = prim.Scale;
140 nativeShapeData.MeshKey = (ulong)shapeKey;
141 nativeShapeData.HullKey = (ulong)shapeKey;
142
143
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 }
149 else
150 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
152 }
153 if (ptr == IntPtr.Zero)
154 {
155 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
156 LogHeader, prim.LocalID, shapeType);
157 }
158 type = shapeType;
159 key = (UInt64)shapeKey;
160 }
161 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene)
163 {
164 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
167 ptr = IntPtr.Zero;
168 // Garbage collection will free up this instance.
169 }
170}
171
172public class BSShapeMesh : BSShape
173{
174 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
175 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
176
177 public BSShapeMesh() : base()
178 {
179 }
180 public static BSShape GetReference() { return new BSShapeNull(); }
181 public override void Dereference(BSScene physicsScene) { }
182}
183
184public class BSShapeHull : BSShape
185{
186 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
187 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
188
189 public BSShapeHull() : base()
190 {
191 }
192 public static BSShape GetReference() { return new BSShapeNull(); }
193 public override void Dereference(BSScene physicsScene) { }
194}
195
196public class BSShapeCompound : BSShape
197{
198 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
199 public BSShapeCompound() : base()
200 {
201 }
202 public static BSShape GetReference(BSPhysObject prim)
203 {
204 return new BSShapeNull();
205 }
206 public override void Dereference(BSScene physicsScene) { }
207}
208}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..3ca756c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -0,0 +1,170 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
97
98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
100 BSPhysicsShapeType.SHAPE_TERRAIN);
101
102 // The terrain object initial position is at the center of the object
103 Vector3 centerPos;
104 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
107
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111
112 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
117
118 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
120
121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr,
125 (uint)CollisionFilterGroups.TerrainFilter,
126 (uint)CollisionFilterGroups.TerrainMask);
127
128 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
130
131 return;
132 }
133
134 // If there is information in m_mapInfo pointing to physical structures, release same.
135 private void ReleaseHeightMapTerrain()
136 {
137 if (m_mapInfo != null)
138 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 // Frees both the body and the shape.
143 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
144 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
145 }
146 }
147 m_mapInfo = null;
148 }
149
150 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos)
152 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154
155 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
156 try
157 {
158 ret = m_mapInfo.heightMap[mapIndex];
159 }
160 catch
161 {
162 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
163 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
164 LogHeader, m_mapInfo.terrainRegionBase, pos);
165 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
166 }
167 return ret;
168 }
169}
170}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 4106534..23fcfd3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -40,7 +40,33 @@ using OpenMetaverse;
40 40
41namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
42{ 42{
43public class BSTerrainManager 43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 public BSScene PhysicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 PhysicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos);
66}
67
68// ==========================================================================================
69public sealed class BSTerrainManager
44{ 70{
45 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
46 72
@@ -67,11 +93,10 @@ public class BSTerrainManager
67 93
68 // If doing mega-regions, if we're region zero we will be managing multiple 94 // 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. 95 // region terrains since region zero does the physics for the whole mega-region.
70 private Dictionary<Vector2, BulletHeightMapInfo> m_heightMaps; 96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
71 97
72 // True of the terrain has been modified. 98 // Flags used to know when to recalculate the height.
73 // Used to force recalculation of terrain height after terrain has been modified 99 private bool m_terrainModified = false;
74 private bool m_terrainModified;
75 100
76 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. 101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
77 // This is incremented before assigning to new region so it is the last ID allocated. 102 // This is incremented before assigning to new region so it is the last ID allocated.
@@ -89,8 +114,7 @@ public class BSTerrainManager
89 public BSTerrainManager(BSScene physicsScene) 114 public BSTerrainManager(BSScene physicsScene)
90 { 115 {
91 PhysicsScene = physicsScene; 116 PhysicsScene = physicsScene;
92 m_heightMaps = new Dictionary<Vector2,BulletHeightMapInfo>(); 117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
93 m_terrainModified = false;
94 118
95 // Assume one region of default size 119 // Assume one region of default size
96 m_worldOffset = Vector3.Zero; 120 m_worldOffset = Vector3.Zero;
@@ -99,9 +123,6 @@ public class BSTerrainManager
99 } 123 }
100 124
101 // Create the initial instance of terrain and the underlying ground plane. 125 // Create the initial instance of terrain and the underlying ground plane.
102 // The objects are allocated in the unmanaged space and the pointers are tracked
103 // by the managed code.
104 // The terrains and the groundPlane are not added to the list of PhysObjects.
105 // This is called from the initialization routine so we presume it is 126 // This is called from the initialization routine so we presume it is
106 // safe to call Bullet in real time. We hope no one is moving prims around yet. 127 // safe to call Bullet in real time. We hope no one is moving prims around yet.
107 public void CreateInitialGroundPlaneAndTerrain() 128 public void CreateInitialGroundPlaneAndTerrain()
@@ -109,7 +130,7 @@ public class BSTerrainManager
109 // The ground plane is here to catch things that are trying to drop to negative infinity 130 // The ground plane is here to catch things that are trying to drop to negative infinity
110 BulletShape groundPlaneShape = new BulletShape( 131 BulletShape groundPlaneShape = new BulletShape(
111 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
112 ShapeData.PhysicsShapeType.SHAPE_GROUNDPLANE); 133 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
113 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
114 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
115 Vector3.Zero, Quaternion.Identity)); 136 Vector3.Zero, Quaternion.Identity));
@@ -121,15 +142,9 @@ public class BSTerrainManager
121 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
122 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
123 144
124 Vector3 minTerrainCoords = new Vector3(0f, 0f, HEIGHT_INITIALIZATION - HEIGHT_EQUAL_FUDGE); 145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
125 Vector3 maxTerrainCoords = new Vector3(DefaultRegionSize.X, DefaultRegionSize.Y, HEIGHT_INITIALIZATION); 146 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
126 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; 147 m_terrains.Add(Vector3.Zero, initialTerrain);
127 float[] initialMap = new float[totalHeights];
128 for (int ii = 0; ii < totalHeights; ii++)
129 {
130 initialMap[ii] = HEIGHT_INITIALIZATION;
131 }
132 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, initialMap, minTerrainCoords, maxTerrainCoords, true);
133 } 148 }
134 149
135 // Release all the terrain structures we might have allocated 150 // Release all the terrain structures we might have allocated
@@ -150,15 +165,11 @@ public class BSTerrainManager
150 // Release all the terrain we have allocated 165 // Release all the terrain we have allocated
151 public void ReleaseTerrain() 166 public void ReleaseTerrain()
152 { 167 {
153 foreach (KeyValuePair<Vector2, BulletHeightMapInfo> kvp in m_heightMaps) 168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
154 { 169 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr)) 170 kvp.Value.Dispose();
156 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, kvp.Value.terrainBody.ptr);
158 BulletSimAPI.ReleaseHeightMapInfo2(kvp.Value.Ptr);
159 }
160 } 171 }
161 m_heightMaps.Clear(); 172 m_terrains.Clear();
162 } 173 }
163 174
164 // The simulator wants to set a new heightmap for the terrain. 175 // The simulator wants to set a new heightmap for the terrain.
@@ -176,8 +187,9 @@ public class BSTerrainManager
176 { 187 {
177 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", 188 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
178 BSScene.DetailLogZero, m_worldOffset, m_worldMax); 189 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
179 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateOrCreateTerrain(BSScene.CHILDTERRAIN_ID, 190 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
180 localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize, true); 191 BSScene.CHILDTERRAIN_ID, localHeightMap,
192 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
181 } 193 }
182 } 194 }
183 else 195 else
@@ -185,7 +197,7 @@ public class BSTerrainManager
185 // If not doing the mega-prim thing, just change the terrain 197 // If not doing the mega-prim thing, just change the terrain
186 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); 198 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
187 199
188 UpdateOrCreateTerrain(BSScene.TERRAIN_ID, localHeightMap, 200 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
189 m_worldOffset, m_worldOffset + DefaultRegionSize, true); 201 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
190 } 202 }
191 }); 203 });
@@ -195,58 +207,63 @@ public class BSTerrainManager
195 // based on the passed information. The 'id' should be either the terrain id or 207 // based on the passed information. The 'id' should be either the terrain id or
196 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. 208 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
197 // The latter feature is for creating child terrains for mega-regions. 209 // The latter feature is for creating child terrains for mega-regions.
198 // If called with a mapInfo in m_heightMaps but the terrain has no body yet (mapInfo.terrainBody.Ptr == 0)
199 // then a new body and shape is created and the mapInfo is filled.
200 // This call is used for doing the initial terrain creation.
201 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new 210 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
202 // terrain shape is created and added to the body. 211 // terrain shape is created and added to the body.
203 // This call is most often used to update the heightMap and parameters of the terrain. 212 // This call is most often used to update the heightMap and parameters of the terrain.
204 // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when 213 // (The above does suggest that some simplification/refactoring is in order.)
205 // calling this routine from initialization or taint-time routines) or whether to delay 214 private void UpdateTerrain(uint id, float[] heightMap,
206 // all the unmanaged activities to taint-time. 215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
207 private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
208 { 216 {
209 DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", 217 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
210 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); 218 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
211 219
220 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z.
212 float minZ = float.MaxValue; 224 float minZ = float.MaxValue;
213 float maxZ = float.MinValue; 225 float maxZ = float.MinValue;
214 Vector2 terrainRegionBase = new Vector2(minCoords.X, minCoords.Y); 226 foreach (float height in heightMap)
215
216 int heightMapSize = heightMap.Length;
217 for (int ii = 0; ii < heightMapSize; ii++)
218 { 227 {
219 float height = heightMap[ii];
220 if (height < minZ) minZ = height; 228 if (height < minZ) minZ = height;
221 if (height > maxZ) maxZ = height; 229 if (height > maxZ) maxZ = height;
222 } 230 }
223 231 if (minZ == maxZ)
224 // The shape of the terrain is from its base to its extents. 232 {
233 // If min and max are the same, reduce min a little bit so a good bounding box is created.
234 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
235 }
225 minCoords.Z = minZ; 236 minCoords.Z = minZ;
226 maxCoords.Z = maxZ; 237 maxCoords.Z = maxZ;
227 238
228 BulletHeightMapInfo mapInfo; 239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
229 if (m_heightMaps.TryGetValue(terrainRegionBase, out mapInfo)) 240
241 BSTerrainPhys terrainPhys;
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
230 { 243 {
231 // If this is terrain we know about, it's easy to update 244 // There is already a terrain in this spot. Free the old and build the new.
232 245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
233 mapInfo.heightMap = heightMap; 246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
234 mapInfo.minCoords = minCoords; 247
235 mapInfo.maxCoords = maxCoords; 248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
236 mapInfo.minZ = minZ;
237 mapInfo.maxZ = maxZ;
238 mapInfo.sizeX = maxCoords.X - minCoords.X;
239 mapInfo.sizeY = maxCoords.Y - minCoords.Y;
240 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
241 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
242
243 BSScene.TaintCallback rebuildOperation = delegate()
244 { 249 {
245 if (MegaRegionParentPhysicsScene != null) 250 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using.
253 terrainPhys.Dispose();
254
255 if (MegaRegionParentPhysicsScene == null)
256 {
257 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
258 m_terrains.Add(terrainRegionBase, newTerrainPhys);
259
260 m_terrainModified = true;
261 }
262 else
246 { 263 {
247 // It's possible that Combine() was called after this code was queued. 264 // It's possible that Combine() was called after this code was queued.
248 // If we are a child of combined regions, we don't create any terrain for us. 265 // If we are a child of combined regions, we don't create any terrain for us.
249 DetailLog("{0},UpdateOrCreateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); 266 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
250 267
251 // Get rid of any terrain that may have been allocated for us. 268 // Get rid of any terrain that may have been allocated for us.
252 ReleaseGroundPlaneAndTerrain(); 269 ReleaseGroundPlaneAndTerrain();
@@ -254,99 +271,7 @@ public class BSTerrainManager
254 // I hate doing this, but just bail 271 // I hate doing this, but just bail
255 return; 272 return;
256 } 273 }
257 274 });
258 if (mapInfo.terrainBody.ptr != IntPtr.Zero)
259 {
260 // Updating an existing terrain.
261 DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,taint,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}",
262 BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY);
263
264 // Remove from the dynamics world because we're going to mangle this object
265 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
266
267 // Get rid of the old terrain
268 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
269 BulletSimAPI.ReleaseHeightMapInfo2(mapInfo.Ptr);
270 mapInfo.Ptr = IntPtr.Zero;
271
272 /*
273 // NOTE: This routine is half here because I can't get the terrain shape replacement
274 // to work. In the short term, the above three lines completely delete the old
275 // terrain and the code below recreates one from scratch.
276 // Hopefully the Bullet community will help me out on this one.
277
278 // First, release the old collision shape (there is only one terrain)
279 BulletSimAPI.DeleteCollisionShape2(m_physicsScene.World.Ptr, mapInfo.terrainShape.Ptr);
280
281 // Fill the existing height map info with the new location and size information
282 BulletSimAPI.FillHeightMapInfo2(m_physicsScene.World.Ptr, mapInfo.Ptr, mapInfo.ID,
283 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
284
285 // Create a terrain shape based on the new info
286 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr));
287
288 // Stuff the shape into the existing terrain body
289 BulletSimAPI.SetBodyShape2(m_physicsScene.World.Ptr, mapInfo.terrainBody.Ptr, mapInfo.terrainShape.Ptr);
290 */
291 }
292 // else
293 {
294 // Creating a new terrain.
295 DetailLog("{0},UpdateOrCreateTerrain:CreateNewTerrain,taint,baseX={1},baseY={2},minZ={3},maxZ={4}",
296 BSScene.DetailLogZero, mapInfo.minCoords.X, mapInfo.minCoords.Y, minZ, maxZ);
297
298 mapInfo.ID = id;
299 mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID,
300 mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN);
301
302 // Create the terrain shape from the mapInfo
303 mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr),
304 ShapeData.PhysicsShapeType.SHAPE_TERRAIN);
305
306 // The terrain object initial position is at the center of the object
307 Vector3 centerPos;
308 centerPos.X = minCoords.X + (mapInfo.sizeX / 2f);
309 centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f);
310 centerPos.Z = minZ + ((maxZ - minZ) / 2f);
311
312 mapInfo.terrainBody = new BulletBody(mapInfo.ID,
313 BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr,
314 id, centerPos, Quaternion.Identity));
315 }
316
317 // Make sure the entry is in the heightmap table
318 m_heightMaps[terrainRegionBase] = mapInfo;
319
320 // Set current terrain attributes
321 BulletSimAPI.SetFriction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
322 BulletSimAPI.SetHitFraction2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
323 BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
324 BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
325
326 // Return the new terrain to the world of physical objects
327 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
328
329 // redo its bounding box now that it is in the world
330 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr);
331
332 BulletSimAPI.SetCollisionFilterMask2(mapInfo.terrainBody.ptr,
333 (uint)CollisionFilterGroups.TerrainFilter,
334 (uint)CollisionFilterGroups.TerrainMask);
335
336 // Make sure the new shape is processed.
337 // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
338 BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING);
339 // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
340
341 m_terrainModified = true;
342 };
343
344 // There is the option to do the changes now (we're already in 'taint time'), or
345 // to do the Bullet operations later.
346 if (inTaintTime)
347 rebuildOperation();
348 else
349 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation);
350 } 275 }
351 else 276 else
352 { 277 {
@@ -362,40 +287,51 @@ public class BSTerrainManager
362 Vector3 minCoordsX = minCoords; 287 Vector3 minCoordsX = minCoords;
363 Vector3 maxCoordsX = maxCoords; 288 Vector3 maxCoordsX = maxCoords;
364 289
365 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
366 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
367 292
368 // Code that must happen at taint-time 293 // Code that must happen at taint-time
369 BSScene.TaintCallback createOperation = delegate() 294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
370 { 295 {
371 DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); 296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
372 // Create a new mapInfo that will be filled with the new info 297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
373 mapInfo = new BulletHeightMapInfo(id, heightMapX, 298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
374 BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, newTerrainID, 299 m_terrains.Add(terrainRegionBase, newTerrainPhys);
375 minCoordsX, maxCoordsX, heightMapX, TERRAIN_COLLISION_MARGIN));
376 // Put the unfilled heightmap info into the collection of same
377 m_heightMaps.Add(terrainRegionBase, mapInfo);
378 // Build the terrain
379 UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true);
380 300
381 m_terrainModified = true; 301 m_terrainModified = true;
382 }; 302 });
383
384 // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time.
385 if (inTaintTime)
386 createOperation();
387 else
388 PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation);
389 } 303 }
390 } 304 }
391 305
392 // Someday we will have complex terrain with caves and tunnels 306 // TODO: redo terrain implementation selection to allow other base types than heightMap.
393 public float GetTerrainHeightAtXYZ(Vector3 loc) 307 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
394 { 308 {
395 // For the moment, it's flat and convex 309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
396 return GetTerrainHeightAtXY(loc.X, loc.Y); 310 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
312 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation)
314 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
317 heightMap, minCoords, maxCoords);
318 break;
319 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
320 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
321 heightMap, minCoords, maxCoords);
322 break;
323 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation,
327 PhysicsScene.Params.terrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase);
329 break;
330 }
331 return newTerrainPhys;
397 } 332 }
398 333
334
399 // Given an X and Y, find the height of the terrain. 335 // Given an X and Y, find the height of the terrain.
400 // Since we could be handling multiple terrains for a mega-region, 336 // Since we could be handling multiple terrains for a mega-region,
401 // the base of the region is calcuated assuming all regions are 337 // the base of the region is calcuated assuming all regions are
@@ -405,8 +341,10 @@ public class BSTerrainManager
405 private float lastHeightTX = 999999f; 341 private float lastHeightTX = 999999f;
406 private float lastHeightTY = 999999f; 342 private float lastHeightTY = 999999f;
407 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
408 private float GetTerrainHeightAtXY(float tX, float tY) 344 public float GetTerrainHeightAtXYZ(Vector3 loc)
409 { 345 {
346 float tX = loc.X;
347 float tY = loc.Y;
410 // You'd be surprized at the number of times this routine is called 348 // You'd be surprized at the number of times this routine is called
411 // with the same parameters as last time. 349 // with the same parameters as last time.
412 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
@@ -418,27 +356,14 @@ public class BSTerrainManager
418 356
419 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
420 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; 358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
421 Vector2 terrainBaseXY = new Vector2(offsetX, offsetY); 359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
422 360
423 BulletHeightMapInfo mapInfo; 361 BSTerrainPhys physTerrain;
424 if (m_heightMaps.TryGetValue(terrainBaseXY, out mapInfo)) 362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
425 { 363 {
426 float regionX = tX - offsetX; 364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
427 float regionY = tY - offsetY; 365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
428 int mapIndex = (int)regionY * (int)mapInfo.sizeY + (int)regionX; 366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
429 try
430 {
431 ret = mapInfo.heightMap[mapIndex];
432 }
433 catch
434 {
435 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
436 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, x={2}, y={3}",
437 LogHeader, terrainBaseXY, regionX, regionY);
438 ret = HEIGHT_GETHEIGHT_RET;
439 }
440 // DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXY,bX={1},baseY={2},szX={3},szY={4},regX={5},regY={6},index={7},ht={8}",
441 // BSScene.DetailLogZero, offsetX, offsetY, mapInfo.sizeX, mapInfo.sizeY, regionX, regionY, mapIndex, ret);
442 } 367 }
443 else 368 else
444 { 369 {
@@ -481,7 +406,7 @@ public class BSTerrainManager
481 // Unhook all the combining that I know about. 406 // Unhook all the combining that I know about.
482 public void UnCombine(PhysicsScene pScene) 407 public void UnCombine(PhysicsScene pScene)
483 { 408 {
484 // Just like ODE, for the moment a NOP 409 // Just like ODE, we don't do anything yet.
485 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); 410 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
486 } 411 }
487 412
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
new file mode 100755
index 0000000..dca7150
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero)
96 {
97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future.
101 return;
102 }
103
104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity;
106
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
108 if (m_terrainBody.ptr == IntPtr.Zero)
109 {
110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future.
113 return;
114 }
115
116 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
121
122 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124
125 // Return the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127
128 // redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
132 (uint)CollisionFilterGroups.TerrainFilter,
133 (uint)CollisionFilterGroups.TerrainMask);
134
135 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
137 }
138
139 public override void Dispose()
140 {
141 if (m_terrainBody.ptr != IntPtr.Zero)
142 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
144 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
146 }
147 }
148
149 public override float GetHeightAtXYZ(Vector3 pos)
150 {
151 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position.
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154
155 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
156 try
157 {
158 ret = m_savedHeightMap[mapIndex];
159 }
160 catch
161 {
162 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
163 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
164 LogHeader, TerrainBase, pos);
165 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
166 }
167 return ret;
168 }
169
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh(
173 BSScene physicsScene,
174 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
175 float extentX, float extentY, // zero based range for output vertices
176 Vector3 extentBase, // base to be added to all vertices
177 float magnification, // number of vertices to create between heightMap coords
178 out int indicesCountO, out int[] indicesO,
179 out int verticesCountO, out float[] verticesO)
180 {
181 bool ret = false;
182
183 int indicesCount = 0;
184 int verticesCount = 0;
185 int[] indices = new int[0];
186 float[] vertices = new float[0];
187
188 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190
191 try
192 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge.
194 int totalVertices = (sizeX + 1) * (sizeY + 1);
195 vertices = new float[totalVertices * 3];
196 int totalIndices = sizeX * sizeY * 6;
197 indices = new int[totalIndices];
198
199 float magX = (float)sizeX / extentX;
200 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
203 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++)
205 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times
207 {
208 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column
210 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset];
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z;
216 verticesCount += 3;
217 }
218 }
219 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222
223 for (int yy = 0; yy < sizeY; yy++)
224 {
225 for (int xx = 0; xx < sizeX; xx++)
226 {
227 int offset = yy * sizeX + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1;
231 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
232 indices[indicesCount + 3] = offset + 1;
233 indices[indicesCount + 4] = offset + sizeX + 2;
234 indices[indicesCount + 5] = offset + sizeX + 1;
235 indicesCount += 6;
236 }
237 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
239 LogHeader, indicesCount); // DEBUG
240 ret = true;
241 }
242 catch (Exception e)
243 {
244 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
245 LogHeader, physicsScene.RegionName, extentBase, e);
246 }
247
248 indicesCountO = indicesCount;
249 indicesO = indices;
250 verticesCountO = verticesCount;
251 verticesO = vertices;
252
253 return ret;
254 }
255}
256}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 5ffd591..e60a760 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -88,11 +88,11 @@ public struct BulletShape
88 public BulletShape(IntPtr xx) 88 public BulletShape(IntPtr xx)
89 { 89 {
90 ptr = xx; 90 ptr = xx;
91 type=ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; 91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = 0; 92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false; 93 isNativeShape = false;
94 } 94 }
95 public BulletShape(IntPtr xx, ShapeData.PhysicsShapeType typ) 95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 { 96 {
97 ptr = xx; 97 ptr = xx;
98 type = typ; 98 type = typ;
@@ -100,7 +100,7 @@ public struct BulletShape
100 isNativeShape = false; 100 isNativeShape = false;
101 } 101 }
102 public IntPtr ptr; 102 public IntPtr ptr;
103 public ShapeData.PhysicsShapeType type; 103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey; 104 public System.UInt64 shapeKey;
105 public bool isNativeShape; 105 public bool isNativeShape;
106 public override string ToString() 106 public override string ToString()
@@ -152,7 +152,7 @@ public class BulletHeightMapInfo
152 ID = id; 152 ID = id;
153 Ptr = xx; 153 Ptr = xx;
154 heightMap = hm; 154 heightMap = hm;
155 terrainRegionBase = new Vector2(0f, 0f); 155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f); 156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f); 157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f; 158 minZ = maxZ = 0f;
@@ -161,7 +161,7 @@ public class BulletHeightMapInfo
161 public uint ID; 161 public uint ID;
162 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap; 163 public float[] heightMap;
164 public Vector2 terrainRegionBase; 164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords; 165 public Vector3 minCoords;
166 public Vector3 maxCoords; 166 public Vector3 maxCoords;
167 public float sizeX, sizeY; 167 public float sizeX, sizeY;
@@ -178,25 +178,39 @@ public struct ConvexHull
178 int VertexCount; 178 int VertexCount;
179 Vector3[] Vertices; 179 Vector3[] Vertices;
180} 180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
181[StructLayout(LayoutKind.Sequential)] 209[StructLayout(LayoutKind.Sequential)]
182public struct ShapeData 210public struct ShapeData
183{ 211{
184 public enum PhysicsShapeType
185 {
186 SHAPE_UNKNOWN = 0,
187 SHAPE_AVATAR = 1,
188 SHAPE_BOX = 2,
189 SHAPE_CONE = 3,
190 SHAPE_CYLINDER = 4,
191 SHAPE_SPHERE = 5,
192 SHAPE_MESH = 6,
193 SHAPE_HULL = 7,
194 // following defined by BulletSim
195 SHAPE_GROUNDPLANE = 20,
196 SHAPE_TERRAIN = 21,
197 };
198 public uint ID; 212 public uint ID;
199 public PhysicsShapeType Type; 213 public BSPhysicsShapeType Type;
200 public Vector3 Position; 214 public Vector3 Position;
201 public Quaternion Rotation; 215 public Quaternion Rotation;
202 public Vector3 Velocity; 216 public Vector3 Velocity;
@@ -215,16 +229,6 @@ public struct ShapeData
215 // note that bools are passed as floats since bool size changes by language and architecture 229 // note that bools are passed as floats since bool size changes by language and architecture
216 public const float numericTrue = 1f; 230 public const float numericTrue = 1f;
217 public const float numericFalse = 0f; 231 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 KEY_CAPSULE = 5,
227 }
228} 232}
229[StructLayout(LayoutKind.Sequential)] 233[StructLayout(LayoutKind.Sequential)]
230public struct SweepHit 234public struct SweepHit
@@ -279,6 +283,7 @@ public struct ConfigurationParameters
279 public float ccdSweptSphereRadius; 283 public float ccdSweptSphereRadius;
280 public float contactProcessingThreshold; 284 public float contactProcessingThreshold;
281 285
286 public float terrainImplementation;
282 public float terrainFriction; 287 public float terrainFriction;
283 public float terrainHitFraction; 288 public float terrainHitFraction;
284 public float terrainRestitution; 289 public float terrainRestitution;
@@ -286,7 +291,8 @@ public struct ConfigurationParameters
286 public float avatarStandingFriction; 291 public float avatarStandingFriction;
287 public float avatarDensity; 292 public float avatarDensity;
288 public float avatarRestitution; 293 public float avatarRestitution;
289 public float avatarCapsuleRadius; 294 public float avatarCapsuleWidth;
295 public float avatarCapsuleDepth;
290 public float avatarCapsuleHeight; 296 public float avatarCapsuleHeight;
291 public float avatarContactProcessingThreshold; 297 public float avatarContactProcessingThreshold;
292 298
@@ -299,6 +305,7 @@ public struct ConfigurationParameters
299 public float shouldEnableFrictionCaching; 305 public float shouldEnableFrictionCaching;
300 public float numberOfSolverIterations; 306 public float numberOfSolverIterations;
301 307
308 public float linksetImplementation;
302 public float linkConstraintUseFrameOffset; 309 public float linkConstraintUseFrameOffset;
303 public float linkConstraintEnableTransMotor; 310 public float linkConstraintEnableTransMotor;
304 public float linkConstraintTransMotorMaxVel; 311 public float linkConstraintTransMotorMaxVel;
@@ -378,6 +385,7 @@ public enum CollisionFilterGroups : uint
378 BTerrainFilter = 1 << 11, 385 BTerrainFilter = 1 << 11,
379 BRaycastFilter = 1 << 12, 386 BRaycastFilter = 1 << 12,
380 BSolidFilter = 1 << 13, 387 BSolidFilter = 1 << 13,
388 BLinksetFilter = 1 << 14,
381 389
382 // The collsion filters and masked are defined in one place -- don't want them scattered 390 // The collsion filters and masked are defined in one place -- don't want them scattered
383 AvatarFilter = BCharacterFilter, 391 AvatarFilter = BCharacterFilter,
@@ -385,18 +393,18 @@ public enum CollisionFilterGroups : uint
385 ObjectFilter = BSolidFilter, 393 ObjectFilter = BSolidFilter,
386 ObjectMask = BAllFilter, 394 ObjectMask = BAllFilter,
387 StaticObjectFilter = BStaticFilter, 395 StaticObjectFilter = BStaticFilter,
388 StaticObjectMask = BAllFilter, 396 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
397 LinksetFilter = BLinksetFilter,
398 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
389 VolumeDetectFilter = BSensorTrigger, 399 VolumeDetectFilter = BSensorTrigger,
390 VolumeDetectMask = ~BSensorTrigger, 400 VolumeDetectMask = ~BSensorTrigger,
391 TerrainFilter = BTerrainFilter, 401 TerrainFilter = BTerrainFilter,
392 TerrainMask = BAllFilter & ~BStaticFilter, 402 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
393 GroundPlaneFilter = BGroundPlaneFilter, 403 GroundPlaneFilter = BGroundPlaneFilter,
394 GroundPlaneMask = BAllFilter 404 GroundPlaneMask = BAllFilter
395 405
396}; 406};
397 407
398
399
400// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
401// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. 409// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
402public enum ConstraintParams : int 410public enum ConstraintParams : int
@@ -426,140 +434,6 @@ static class BulletSimAPI {
426[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 434[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
427public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); 435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
428 436
429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
430[return: MarshalAs(UnmanagedType.LPStr)]
431public static extern string GetVersion();
432
433/* Remove the linkage to the old api methods
434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
435public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
436 int maxCollisions, IntPtr collisionArray,
437 int maxUpdates, IntPtr updateArray,
438 DebugLogCallback logRoutine);
439
440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
441public static extern void CreateInitialGroundPlaneAndTerrain(uint worldID);
442
443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
444public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);
445
446[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
447public static extern void Shutdown(uint worldID);
448
449[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
450public static extern bool UpdateParameter(uint worldID, uint localID,
451 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
452
453// ===============================================================================
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep,
456 out int updatedEntityCount,
457 out IntPtr updatedEntitiesPtr,
458 out int collidersCount,
459 out IntPtr collidersPtr);
460
461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
462public static extern bool CreateHull(uint worldID, System.UInt64 meshKey,
463 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
464 );
465
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey,
468 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices
470 );
471
472[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
473public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey);
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool CreateObject(uint worldID, ShapeData shapeData);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern Quaternion GetObjectOrientation(uint WorldID, uint id);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation);
489
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity);
492
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity);
495
496// Set the current force acting on the object
497[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
498public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force);
499
500[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
501public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic);
502
503[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
504public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom);
505
506[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
507public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass);
508
509[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
510public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly);
511
512[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
513public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass);
514
515[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
516public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy);
517
518[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
519public static extern bool HasObject(uint worldID, uint id);
520
521[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
522public static extern bool DestroyObject(uint worldID, uint id);
523
524// ===============================================================================
525[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
526public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin);
527
528[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
529public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to);
530
531[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
532public static extern Vector3 RecoverFromPenetration(uint worldID, uint id);
533
534// ===============================================================================
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern void DumpBulletStatistics();
537*/
538// Log a debug message
539[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
540public static extern void SetDebugLogCallback(DebugLogCallback callback);
541
542// ===============================================================================
543// ===============================================================================
544// ===============================================================================
545// A new version of the API that enables moving all the logic out of the C++ code and into
546// the C# code. This will make modifications easier for the next person.
547// This interface passes the actual pointers to the objects in the unmanaged
548// address space. All the management (calls for creation/destruction/lookup)
549// is done in the C# code.
550// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
551// and the old code is removed.
552
553// Functions use while converting from API1 to API2. Can be removed when totally converted.
554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
555public static extern IntPtr GetSimHandle2(uint worldID);
556
557[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
558public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id);
559
560[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
561public static extern IntPtr GetBodyHandle2(IntPtr world, uint id);
562
563// =============================================================================== 437// ===============================================================================
564// Initialization and simulation 438// Initialization and simulation
565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@@ -611,13 +485,25 @@ public static extern bool IsNativeShape2(IntPtr shape);
611public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); 485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
612 486
613[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
614public static extern IntPtr CreateCompoundShape2(IntPtr sim); 488public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
615 489
616[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
617public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); 491public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
618 492
619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
620public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape); 494public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
495
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
498
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
501
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
504
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
621 507
622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
623public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); 509public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
@@ -881,10 +767,10 @@ public static extern float GetCcdMotionThreshold2(IntPtr obj);
881public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); 767public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
882 768
883[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 769[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
884public static extern float GetCcdSweepSphereRadius2(IntPtr obj); 770public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
885 771
886[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 772[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
887public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val); 773public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
888 774
889[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 775[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
890public static extern IntPtr GetUserPointer2(IntPtr obj); 776public static extern IntPtr GetUserPointer2(IntPtr obj);
@@ -907,6 +793,12 @@ public static extern Vector3 GetGravity2(IntPtr obj);
907public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); 793public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
908 794
909[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
910public static extern float GetLinearDamping2(IntPtr obj); 802public static extern float GetLinearDamping2(IntPtr obj);
911 803
912[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0d1db3b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]