diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
15 files changed, 1583 insertions, 843 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index a041ba8..2a5397e 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 | ||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | public class BSCharacter : BSPhysObject | 37 | public 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]"; |
@@ -97,28 +97,14 @@ public class BSCharacter : BSPhysObject | |||
97 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 97 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
98 | ComputeAvatarVolumeAndMass(); | 98 | ComputeAvatarVolumeAndMass(); |
99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
100 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw); | 100 | 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; // capsule is a native shape but scale is not just <1,1,1> | ||
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 | 101 | ||
116 | // do actual create at taint time | 102 | // do actual create at taint time |
117 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 103 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
118 | { | 104 | { |
119 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 105 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
120 | // New body and shape into BSBody and BSShape | 106 | // New body and shape into BSBody and BSShape |
121 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null); | 107 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); |
122 | 108 | ||
123 | SetPhysicalProperties(); | 109 | SetPhysicalProperties(); |
124 | }); | 110 | }); |
@@ -131,46 +117,45 @@ public class BSCharacter : BSPhysObject | |||
131 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 117 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
132 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 118 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
133 | { | 119 | { |
134 | PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); | 120 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
135 | PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); | 121 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
136 | }); | 122 | }); |
137 | } | 123 | } |
138 | 124 | ||
139 | private void SetPhysicalProperties() | 125 | private void SetPhysicalProperties() |
140 | { | 126 | { |
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); | 127 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
142 | 128 | ||
143 | ZeroMotion(); | 129 | ZeroMotion(); |
144 | ForcePosition = _position; | 130 | ForcePosition = _position; |
145 | // Set the velocity and compute the proper friction | 131 | // Set the velocity and compute the proper friction |
146 | ForceVelocity = _velocity; | 132 | ForceVelocity = _velocity; |
147 | 133 | ||
148 | BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); | 134 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); |
149 | BulletSimAPI.SetMargin2(BSShape.ptr, PhysicsScene.Params.collisionMargin); | 135 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); |
150 | BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); | 136 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); |
151 | BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 137 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |
152 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 138 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) |
153 | { | 139 | { |
154 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 140 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |
155 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 141 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |
156 | } | 142 | } |
157 | 143 | ||
158 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); | 144 | UpdatePhysicalMassProperties(RawMass); |
159 | BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); | ||
160 | 145 | ||
161 | // Make so capsule does not fall over | 146 | // Make so capsule does not fall over |
162 | BulletSimAPI.SetAngularFactorV2(BSBody.ptr, OMV.Vector3.Zero); | 147 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); |
163 | 148 | ||
164 | BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | 149 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); |
165 | 150 | ||
166 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); | 151 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
167 | 152 | ||
168 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | 153 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); |
169 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_DEACTIVATION); | 154 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); |
170 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); | 155 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
171 | 156 | ||
172 | // Do this after the object has been added to the world | 157 | // Do this after the object has been added to the world |
173 | BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, | 158 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, |
174 | (uint)CollisionFilterGroups.AvatarFilter, | 159 | (uint)CollisionFilterGroups.AvatarFilter, |
175 | (uint)CollisionFilterGroups.AvatarMask); | 160 | (uint)CollisionFilterGroups.AvatarMask); |
176 | } | 161 | } |
@@ -196,13 +181,12 @@ public class BSCharacter : BSPhysObject | |||
196 | ComputeAvatarScale(_size); | 181 | ComputeAvatarScale(_size); |
197 | ComputeAvatarVolumeAndMass(); | 182 | ComputeAvatarVolumeAndMass(); |
198 | DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", | 183 | DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", |
199 | LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw); | 184 | LocalID, Scale, _avatarDensity, _avatarVolume, RawMass); |
200 | 185 | ||
201 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 186 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
202 | { | 187 | { |
203 | BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); | 188 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); |
204 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); | 189 | UpdatePhysicalMassProperties(RawMass); |
205 | BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); | ||
206 | }); | 190 | }); |
207 | 191 | ||
208 | } | 192 | } |
@@ -214,6 +198,11 @@ public class BSCharacter : BSPhysObject | |||
214 | { | 198 | { |
215 | set { BaseShape = value; } | 199 | set { BaseShape = value; } |
216 | } | 200 | } |
201 | // I want the physics engine to make an avatar capsule | ||
202 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | ||
203 | { | ||
204 | get {return ShapeData.PhysicsShapeType.SHAPE_AVATAR; } | ||
205 | } | ||
217 | 206 | ||
218 | public override bool Grabbed { | 207 | public override bool Grabbed { |
219 | set { _grabbed = value; } | 208 | set { _grabbed = value; } |
@@ -236,16 +225,22 @@ public class BSCharacter : BSPhysObject | |||
236 | _rotationalVelocity = OMV.Vector3.Zero; | 225 | _rotationalVelocity = OMV.Vector3.Zero; |
237 | 226 | ||
238 | // Zero some other properties directly into the physics engine | 227 | // Zero some other properties directly into the physics engine |
239 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, OMV.Vector3.Zero); | 228 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
240 | BulletSimAPI.SetAngularVelocity2(BSBody.ptr, OMV.Vector3.Zero); | 229 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
241 | BulletSimAPI.SetInterpolationVelocity2(BSBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | 230 | BulletSimAPI.SetInterpolationVelocity2(PhysBody.ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); |
242 | BulletSimAPI.ClearForces2(BSBody.ptr); | 231 | BulletSimAPI.ClearForces2(PhysBody.ptr); |
243 | } | 232 | } |
244 | 233 | ||
245 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 234 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } |
246 | 235 | ||
236 | public override OMV.Vector3 RawPosition | ||
237 | { | ||
238 | get { return _position; } | ||
239 | set { _position = value; } | ||
240 | } | ||
247 | public override OMV.Vector3 Position { | 241 | public override OMV.Vector3 Position { |
248 | get { | 242 | get { |
243 | // Don't refetch the position because this function is called a zillion times | ||
249 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | 244 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); |
250 | return _position; | 245 | return _position; |
251 | } | 246 | } |
@@ -256,19 +251,19 @@ public class BSCharacter : BSPhysObject | |||
256 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 251 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
257 | { | 252 | { |
258 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 253 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
259 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 254 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
260 | }); | 255 | }); |
261 | } | 256 | } |
262 | } | 257 | } |
263 | public override OMV.Vector3 ForcePosition { | 258 | public override OMV.Vector3 ForcePosition { |
264 | get { | 259 | get { |
265 | _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 260 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); |
266 | return _position; | 261 | return _position; |
267 | } | 262 | } |
268 | set { | 263 | set { |
269 | _position = value; | 264 | _position = value; |
270 | PositionSanityCheck(); | 265 | PositionSanityCheck(); |
271 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 266 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
272 | } | 267 | } |
273 | } | 268 | } |
274 | 269 | ||
@@ -312,15 +307,11 @@ public class BSCharacter : BSPhysObject | |||
312 | { | 307 | { |
313 | // The new position value must be pushed into the physics engine but we can't | 308 | // The new position value must be pushed into the physics engine but we can't |
314 | // just assign to "Position" because of potential call loops. | 309 | // just assign to "Position" because of potential call loops. |
315 | BSScene.TaintCallback sanityOperation = delegate() | 310 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
316 | { | 311 | { |
317 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 312 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
318 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 313 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
319 | }; | 314 | }); |
320 | if (inTaintTime) | ||
321 | sanityOperation(); | ||
322 | else | ||
323 | PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); | ||
324 | ret = true; | 315 | ret = true; |
325 | } | 316 | } |
326 | return ret; | 317 | return ret; |
@@ -329,7 +320,14 @@ public class BSCharacter : BSPhysObject | |||
329 | public override float Mass { get { return _mass; } } | 320 | public override float Mass { get { return _mass; } } |
330 | 321 | ||
331 | // used when we only want this prim's mass and not the linkset thing | 322 | // used when we only want this prim's mass and not the linkset thing |
332 | public override float MassRaw { get {return _mass; } } | 323 | public override float RawMass { |
324 | get {return _mass; } | ||
325 | } | ||
326 | public override void UpdatePhysicalMassProperties(float physMass) | ||
327 | { | ||
328 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
329 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
330 | } | ||
333 | 331 | ||
334 | public override OMV.Vector3 Force { | 332 | public override OMV.Vector3 Force { |
335 | get { return _force; } | 333 | get { return _force; } |
@@ -339,7 +337,7 @@ public class BSCharacter : BSPhysObject | |||
339 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 337 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
340 | { | 338 | { |
341 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 339 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
342 | BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); | 340 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); |
343 | }); | 341 | }); |
344 | } | 342 | } |
345 | } | 343 | } |
@@ -378,7 +376,7 @@ public class BSCharacter : BSPhysObject | |||
378 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | 376 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) |
379 | { | 377 | { |
380 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 378 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; |
381 | BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); | 379 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); |
382 | } | 380 | } |
383 | } | 381 | } |
384 | else | 382 | else |
@@ -386,15 +384,15 @@ public class BSCharacter : BSPhysObject | |||
386 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | 384 | if (_currentFriction != PhysicsScene.Params.avatarFriction) |
387 | { | 385 | { |
388 | _currentFriction = PhysicsScene.Params.avatarFriction; | 386 | _currentFriction = PhysicsScene.Params.avatarFriction; |
389 | BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); | 387 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); |
390 | } | 388 | } |
391 | } | 389 | } |
392 | _velocity = value; | 390 | _velocity = value; |
393 | // Remember the set velocity so we can suppress the reduction by friction, ... | 391 | // Remember the set velocity so we can suppress the reduction by friction, ... |
394 | _appliedVelocity = value; | 392 | _appliedVelocity = value; |
395 | 393 | ||
396 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); | 394 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |
397 | BulletSimAPI.Activate2(BSBody.ptr, true); | 395 | BulletSimAPI.Activate2(PhysBody.ptr, true); |
398 | } | 396 | } |
399 | } | 397 | } |
400 | public override OMV.Vector3 Torque { | 398 | public override OMV.Vector3 Torque { |
@@ -411,6 +409,11 @@ public class BSCharacter : BSPhysObject | |||
411 | get { return _acceleration; } | 409 | get { return _acceleration; } |
412 | set { _acceleration = value; } | 410 | set { _acceleration = value; } |
413 | } | 411 | } |
412 | public override OMV.Quaternion RawOrientation | ||
413 | { | ||
414 | get { return _orientation; } | ||
415 | set { _orientation = value; } | ||
416 | } | ||
414 | public override OMV.Quaternion Orientation { | 417 | public override OMV.Quaternion Orientation { |
415 | get { return _orientation; } | 418 | get { return _orientation; } |
416 | set { | 419 | set { |
@@ -419,7 +422,7 @@ public class BSCharacter : BSPhysObject | |||
419 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 422 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
420 | { | 423 | { |
421 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 424 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); |
422 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 425 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
423 | }); | 426 | }); |
424 | } | 427 | } |
425 | } | 428 | } |
@@ -428,13 +431,13 @@ public class BSCharacter : BSPhysObject | |||
428 | { | 431 | { |
429 | get | 432 | get |
430 | { | 433 | { |
431 | _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); | 434 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); |
432 | return _orientation; | 435 | return _orientation; |
433 | } | 436 | } |
434 | set | 437 | set |
435 | { | 438 | { |
436 | _orientation = value; | 439 | _orientation = value; |
437 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 440 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
438 | } | 441 | } |
439 | } | 442 | } |
440 | public override int PhysicsActorType { | 443 | public override int PhysicsActorType { |
@@ -493,9 +496,9 @@ public class BSCharacter : BSPhysObject | |||
493 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 496 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
494 | { | 497 | { |
495 | if (_floatOnWater) | 498 | if (_floatOnWater) |
496 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 499 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
497 | else | 500 | else |
498 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 501 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
499 | }); | 502 | }); |
500 | } | 503 | } |
501 | } | 504 | } |
@@ -528,7 +531,7 @@ public class BSCharacter : BSPhysObject | |||
528 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 531 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
529 | // Buoyancy is faked by changing the gravity applied to the object | 532 | // Buoyancy is faked by changing the gravity applied to the object |
530 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 533 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
531 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 534 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); |
532 | } | 535 | } |
533 | } | 536 | } |
534 | 537 | ||
@@ -574,7 +577,7 @@ public class BSCharacter : BSPhysObject | |||
574 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | 577 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() |
575 | { | 578 | { |
576 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 579 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); |
577 | BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); | 580 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); |
578 | }); | 581 | }); |
579 | } | 582 | } |
580 | else | 583 | else |
@@ -642,7 +645,7 @@ public class BSCharacter : BSPhysObject | |||
642 | // That's just the way they are defined. | 645 | // That's just the way they are defined. |
643 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); | 646 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); |
644 | _velocity = avVel; | 647 | _velocity = avVel; |
645 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); | 648 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel); |
646 | } | 649 | } |
647 | 650 | ||
648 | // Tell the linkset about value changes | 651 | // Tell the linkset about value changes |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index f017cdd..65fac00 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -42,6 +42,12 @@ public abstract class BSConstraint : IDisposable | |||
42 | protected BulletConstraint m_constraint; | 42 | protected BulletConstraint m_constraint; |
43 | protected bool m_enabled = false; | 43 | protected bool m_enabled = false; |
44 | 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 | |||
45 | public BSConstraint() | 51 | public BSConstraint() |
46 | { | 52 | { |
47 | } | 53 | } |
@@ -64,12 +70,6 @@ public abstract class BSConstraint : IDisposable | |||
64 | } | 70 | } |
65 | } | 71 | } |
66 | 72 | ||
67 | public BulletBody Body1 { get { return m_body1; } } | ||
68 | public BulletBody Body2 { get { return m_body2; } } | ||
69 | public BulletConstraint Constraint { get { return m_constraint; } } | ||
70 | public abstract ConstraintType Type { get; } | ||
71 | |||
72 | |||
73 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) | 73 | public virtual bool SetLinearLimits(Vector3 low, Vector3 high) |
74 | { | 74 | { |
75 | bool ret = false; | 75 | bool ret = false; |
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; | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | 32 | namespace OpenSim.Region.Physics.BulletSPlugin |
33 | { | 33 | { |
34 | 34 | ||
35 | public class BS6DofConstraint : BSConstraint | 35 | public 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; | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | 35 | ||
36 | public class BSConstraintCollection : IDisposable | 36 | public 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; | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | 32 | namespace OpenSim.Region.Physics.BulletSPlugin |
33 | { | 33 | { |
34 | 34 | ||
35 | class BSHingeConstraint : BSConstraint | 35 | public 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 117c878..819635a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -52,7 +52,7 @@ using OpenSim.Region.Physics.Manager; | |||
52 | 52 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 53 | namespace OpenSim.Region.Physics.BulletSPlugin |
54 | { | 54 | { |
55 | public class BSDynamics | 55 | public sealed class BSDynamics |
56 | { | 56 | { |
57 | private BSScene PhysicsScene { get; set; } | 57 | private BSScene PhysicsScene { get; set; } |
58 | // the prim this dynamic controller belongs to | 58 | // the prim this dynamic controller belongs to |
@@ -72,8 +72,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
72 | // LIMIT_ROLL_ONLY | 72 | // LIMIT_ROLL_ONLY |
73 | private Vector3 m_BlockingEndPoint = Vector3.Zero; | 73 | private Vector3 m_BlockingEndPoint = Vector3.Zero; |
74 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; | 74 | private Quaternion m_RollreferenceFrame = Quaternion.Identity; |
75 | private Quaternion m_referenceFrame = Quaternion.Identity; | ||
76 | |||
75 | // Linear properties | 77 | // Linear properties |
76 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 78 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
79 | 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 | 80 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
78 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | 81 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body |
79 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 82 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
@@ -86,7 +89,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
86 | 89 | ||
87 | //Angular properties | 90 | //Angular properties |
88 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 91 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
89 | private int m_angularMotorApply = 0; // application frame counter | 92 | // private int m_angularMotorApply = 0; // application frame counter |
90 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 93 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
91 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 94 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
92 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 95 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
@@ -95,19 +98,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
95 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 98 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
96 | 99 | ||
97 | //Deflection properties | 100 | //Deflection properties |
98 | // private float m_angularDeflectionEfficiency = 0; | 101 | private float m_angularDeflectionEfficiency = 0; |
99 | // private float m_angularDeflectionTimescale = 0; | 102 | private float m_angularDeflectionTimescale = 0; |
100 | // private float m_linearDeflectionEfficiency = 0; | 103 | private float m_linearDeflectionEfficiency = 0; |
101 | // private float m_linearDeflectionTimescale = 0; | 104 | private float m_linearDeflectionTimescale = 0; |
102 | 105 | ||
103 | //Banking properties | 106 | //Banking properties |
104 | // private float m_bankingEfficiency = 0; | 107 | private float m_bankingEfficiency = 0; |
105 | // private float m_bankingMix = 0; | 108 | private float m_bankingMix = 0; |
106 | // private float m_bankingTimescale = 0; | 109 | private float m_bankingTimescale = 0; |
107 | 110 | ||
108 | //Hover and Buoyancy properties | 111 | //Hover and Buoyancy properties |
109 | private float m_VhoverHeight = 0f; | 112 | private float m_VhoverHeight = 0f; |
110 | // private float m_VhoverEfficiency = 0f; | 113 | private float m_VhoverEfficiency = 0f; |
111 | private float m_VhoverTimescale = 0f; | 114 | private float m_VhoverTimescale = 0f; |
112 | private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height | 115 | 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. | 116 | private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. |
@@ -138,10 +141,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
138 | switch (pParam) | 141 | switch (pParam) |
139 | { | 142 | { |
140 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 143 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
141 | // m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); | 144 | m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f); |
142 | break; | 145 | break; |
143 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: | 146 | case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: |
144 | // m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 147 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
145 | break; | 148 | break; |
146 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 149 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
147 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 150 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); |
@@ -150,20 +153,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
150 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 153 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
151 | break; | 154 | break; |
152 | case Vehicle.BANKING_EFFICIENCY: | 155 | case Vehicle.BANKING_EFFICIENCY: |
153 | // m_bankingEfficiency = Math.Max(pValue, 0.01f); | 156 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); |
154 | break; | 157 | break; |
155 | case Vehicle.BANKING_MIX: | 158 | case Vehicle.BANKING_MIX: |
156 | // m_bankingMix = Math.Max(pValue, 0.01f); | 159 | m_bankingMix = Math.Max(pValue, 0.01f); |
157 | break; | 160 | break; |
158 | case Vehicle.BANKING_TIMESCALE: | 161 | case Vehicle.BANKING_TIMESCALE: |
159 | // m_bankingTimescale = Math.Max(pValue, 0.01f); | 162 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
160 | break; | 163 | break; |
161 | case Vehicle.BUOYANCY: | 164 | case Vehicle.BUOYANCY: |
162 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 165 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); |
163 | break; | 166 | break; |
164 | // case Vehicle.HOVER_EFFICIENCY: | 167 | case Vehicle.HOVER_EFFICIENCY: |
165 | // m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 168 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); |
166 | // break; | 169 | break; |
167 | case Vehicle.HOVER_HEIGHT: | 170 | case Vehicle.HOVER_HEIGHT: |
168 | m_VhoverHeight = pValue; | 171 | m_VhoverHeight = pValue; |
169 | break; | 172 | break; |
@@ -171,10 +174,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
171 | m_VhoverTimescale = Math.Max(pValue, 0.01f); | 174 | m_VhoverTimescale = Math.Max(pValue, 0.01f); |
172 | break; | 175 | break; |
173 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: | 176 | case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: |
174 | // m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); | 177 | m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f); |
175 | break; | 178 | break; |
176 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: | 179 | case Vehicle.LINEAR_DEFLECTION_TIMESCALE: |
177 | // m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 180 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
178 | break; | 181 | break; |
179 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 182 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
180 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 183 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); |
@@ -196,7 +199,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
196 | break; | 199 | break; |
197 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 200 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
198 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 201 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
199 | m_angularMotorApply = 10; | 202 | // m_angularMotorApply = 100; |
200 | break; | 203 | break; |
201 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 204 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
202 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 205 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
@@ -206,7 +209,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
206 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 209 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
207 | break; | 210 | break; |
208 | case Vehicle.LINEAR_MOTOR_OFFSET: | 211 | case Vehicle.LINEAR_MOTOR_OFFSET: |
209 | // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 212 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
210 | break; | 213 | break; |
211 | 214 | ||
212 | } | 215 | } |
@@ -221,15 +224,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
221 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 224 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
222 | break; | 225 | break; |
223 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 226 | 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 | 227 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
226 | if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; | 228 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); |
227 | if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; | 229 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); |
228 | if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; | 230 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); |
229 | if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; | 231 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
230 | if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; | 232 | // m_angularMotorApply = 100; |
231 | if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f; | ||
232 | m_angularMotorApply = 10; | ||
233 | break; | 233 | break; |
234 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 234 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
235 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 235 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -239,7 +239,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
239 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 239 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
240 | break; | 240 | break; |
241 | case Vehicle.LINEAR_MOTOR_OFFSET: | 241 | case Vehicle.LINEAR_MOTOR_OFFSET: |
242 | // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 242 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
243 | break; | 243 | break; |
244 | case Vehicle.BLOCK_EXIT: | 244 | case Vehicle.BLOCK_EXIT: |
245 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); | 245 | m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -253,7 +253,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
253 | switch (pParam) | 253 | switch (pParam) |
254 | { | 254 | { |
255 | case Vehicle.REFERENCE_FRAME: | 255 | case Vehicle.REFERENCE_FRAME: |
256 | // m_referenceFrame = pValue; | 256 | m_referenceFrame = pValue; |
257 | break; | 257 | break; |
258 | case Vehicle.ROLL_FRAME: | 258 | case Vehicle.ROLL_FRAME: |
259 | m_RollreferenceFrame = pValue; | 259 | m_RollreferenceFrame = pValue; |
@@ -265,21 +265,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
265 | { | 265 | { |
266 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); | 266 | VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); |
267 | VehicleFlag parm = (VehicleFlag)pParam; | 267 | VehicleFlag parm = (VehicleFlag)pParam; |
268 | if (remove) | 268 | if (pParam == -1) |
269 | m_flags = (VehicleFlag)0; | ||
270 | else | ||
269 | { | 271 | { |
270 | if (pParam == -1) | 272 | if (remove) |
271 | { | ||
272 | m_flags = (VehicleFlag)0; | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | m_flags &= ~parm; | 273 | m_flags &= ~parm; |
277 | } | 274 | else |
278 | } | 275 | m_flags |= parm; |
279 | else { | ||
280 | m_flags |= parm; | ||
281 | } | 276 | } |
282 | }//end ProcessVehicleFlags | 277 | } |
283 | 278 | ||
284 | internal void ProcessTypeChange(Vehicle pType) | 279 | internal void ProcessTypeChange(Vehicle pType) |
285 | { | 280 | { |
@@ -288,99 +283,142 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
288 | Type = pType; | 283 | Type = pType; |
289 | switch (pType) | 284 | switch (pType) |
290 | { | 285 | { |
291 | case Vehicle.TYPE_NONE: | 286 | 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; | 287 | m_linearMotorDirection = Vector3.Zero; |
295 | m_linearMotorTimescale = 0; | 288 | m_linearMotorTimescale = 0; |
296 | m_linearMotorDecayTimescale = 0; | 289 | m_linearMotorDecayTimescale = 0; |
290 | m_linearFrictionTimescale = new Vector3(0, 0, 0); | ||
291 | |||
297 | m_angularMotorDirection = Vector3.Zero; | 292 | m_angularMotorDirection = Vector3.Zero; |
298 | m_angularMotorTimescale = 0; | ||
299 | m_angularMotorDecayTimescale = 0; | 293 | m_angularMotorDecayTimescale = 0; |
294 | m_angularMotorTimescale = 0; | ||
295 | m_angularFrictionTimescale = new Vector3(0, 0, 0); | ||
296 | |||
300 | m_VhoverHeight = 0; | 297 | m_VhoverHeight = 0; |
298 | m_VhoverEfficiency = 0; | ||
301 | m_VhoverTimescale = 0; | 299 | m_VhoverTimescale = 0; |
302 | m_VehicleBuoyancy = 0; | 300 | m_VehicleBuoyancy = 0; |
301 | |||
302 | m_linearDeflectionEfficiency = 1; | ||
303 | m_linearDeflectionTimescale = 1; | ||
304 | |||
305 | m_angularDeflectionEfficiency = 0; | ||
306 | m_angularDeflectionTimescale = 1000; | ||
307 | |||
308 | m_verticalAttractionEfficiency = 0; | ||
309 | m_verticalAttractionTimescale = 0; | ||
310 | |||
311 | m_bankingEfficiency = 0; | ||
312 | m_bankingTimescale = 1000; | ||
313 | m_bankingMix = 1; | ||
314 | |||
315 | m_referenceFrame = Quaternion.Identity; | ||
303 | m_flags = (VehicleFlag)0; | 316 | m_flags = (VehicleFlag)0; |
304 | break; | 317 | break; |
305 | 318 | ||
306 | case Vehicle.TYPE_SLED: | 319 | 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; | 320 | m_linearMotorDirection = Vector3.Zero; |
310 | m_linearMotorTimescale = 1000; | 321 | m_linearMotorTimescale = 1000; |
311 | m_linearMotorDecayTimescale = 120; | 322 | m_linearMotorDecayTimescale = 120; |
323 | m_linearFrictionTimescale = new Vector3(30, 1, 1000); | ||
324 | |||
312 | m_angularMotorDirection = Vector3.Zero; | 325 | m_angularMotorDirection = Vector3.Zero; |
313 | m_angularMotorTimescale = 1000; | 326 | m_angularMotorTimescale = 1000; |
314 | m_angularMotorDecayTimescale = 120; | 327 | m_angularMotorDecayTimescale = 120; |
328 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
329 | |||
315 | m_VhoverHeight = 0; | 330 | m_VhoverHeight = 0; |
316 | // m_VhoverEfficiency = 1; | 331 | m_VhoverEfficiency = 10; // TODO: this looks wrong!! |
317 | m_VhoverTimescale = 10; | 332 | m_VhoverTimescale = 10; |
318 | m_VehicleBuoyancy = 0; | 333 | m_VehicleBuoyancy = 0; |
319 | // m_linearDeflectionEfficiency = 1; | 334 | |
320 | // m_linearDeflectionTimescale = 1; | 335 | m_linearDeflectionEfficiency = 1; |
321 | // m_angularDeflectionEfficiency = 1; | 336 | m_linearDeflectionTimescale = 1; |
322 | // m_angularDeflectionTimescale = 1000; | 337 | |
323 | // m_bankingEfficiency = 0; | 338 | m_angularDeflectionEfficiency = 1; |
324 | // m_bankingMix = 1; | 339 | m_angularDeflectionTimescale = 1000; |
325 | // m_bankingTimescale = 10; | 340 | |
326 | // m_referenceFrame = Quaternion.Identity; | 341 | m_verticalAttractionEfficiency = 0; |
342 | m_verticalAttractionTimescale = 0; | ||
343 | |||
344 | m_bankingEfficiency = 0; | ||
345 | m_bankingTimescale = 10; | ||
346 | m_bankingMix = 1; | ||
347 | |||
348 | m_referenceFrame = Quaternion.Identity; | ||
327 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 349 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); |
328 | m_flags &= | 350 | m_flags &= |
329 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 351 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | |
330 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 352 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); |
331 | break; | 353 | break; |
332 | case Vehicle.TYPE_CAR: | 354 | 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; | 355 | m_linearMotorDirection = Vector3.Zero; |
336 | m_linearMotorTimescale = 1; | 356 | m_linearMotorTimescale = 1; |
337 | m_linearMotorDecayTimescale = 60; | 357 | m_linearMotorDecayTimescale = 60; |
358 | m_linearFrictionTimescale = new Vector3(100, 2, 1000); | ||
359 | |||
338 | m_angularMotorDirection = Vector3.Zero; | 360 | m_angularMotorDirection = Vector3.Zero; |
339 | m_angularMotorTimescale = 1; | 361 | m_angularMotorTimescale = 1; |
340 | m_angularMotorDecayTimescale = 0.8f; | 362 | m_angularMotorDecayTimescale = 0.8f; |
363 | m_angularFrictionTimescale = new Vector3(1000, 1000, 1000); | ||
364 | |||
341 | m_VhoverHeight = 0; | 365 | m_VhoverHeight = 0; |
342 | // m_VhoverEfficiency = 0; | 366 | m_VhoverEfficiency = 0; |
343 | m_VhoverTimescale = 1000; | 367 | m_VhoverTimescale = 1000; |
344 | m_VehicleBuoyancy = 0; | 368 | m_VehicleBuoyancy = 0; |
345 | // // m_linearDeflectionEfficiency = 1; | 369 | |
346 | // // m_linearDeflectionTimescale = 2; | 370 | m_linearDeflectionEfficiency = 1; |
347 | // // m_angularDeflectionEfficiency = 0; | 371 | m_linearDeflectionTimescale = 2; |
348 | // m_angularDeflectionTimescale = 10; | 372 | |
373 | m_angularDeflectionEfficiency = 0; | ||
374 | m_angularDeflectionTimescale = 10; | ||
375 | |||
349 | m_verticalAttractionEfficiency = 1f; | 376 | m_verticalAttractionEfficiency = 1f; |
350 | m_verticalAttractionTimescale = 10f; | 377 | m_verticalAttractionTimescale = 10f; |
351 | // m_bankingEfficiency = -0.2f; | 378 | |
352 | // m_bankingMix = 1; | 379 | m_bankingEfficiency = -0.2f; |
353 | // m_bankingTimescale = 1; | 380 | m_bankingMix = 1; |
354 | // m_referenceFrame = Quaternion.Identity; | 381 | m_bankingTimescale = 1; |
382 | |||
383 | m_referenceFrame = Quaternion.Identity; | ||
384 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | ||
385 | | VehicleFlag.HOVER_TERRAIN_ONLY | ||
386 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | ||
355 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 387 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
356 | | VehicleFlag.LIMIT_ROLL_ONLY | 388 | | VehicleFlag.LIMIT_ROLL_ONLY |
357 | | VehicleFlag.LIMIT_MOTOR_UP); | 389 | | VehicleFlag.LIMIT_MOTOR_UP |
358 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 390 | | VehicleFlag.HOVER_UP_ONLY); |
359 | m_flags |= (VehicleFlag.HOVER_UP_ONLY); | ||
360 | break; | 391 | break; |
361 | case Vehicle.TYPE_BOAT: | 392 | 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; | 393 | m_linearMotorDirection = Vector3.Zero; |
365 | m_linearMotorTimescale = 5; | 394 | m_linearMotorTimescale = 5; |
366 | m_linearMotorDecayTimescale = 60; | 395 | m_linearMotorDecayTimescale = 60; |
396 | m_linearFrictionTimescale = new Vector3(10, 3, 2); | ||
397 | |||
367 | m_angularMotorDirection = Vector3.Zero; | 398 | m_angularMotorDirection = Vector3.Zero; |
368 | m_angularMotorTimescale = 4; | 399 | m_angularMotorTimescale = 4; |
369 | m_angularMotorDecayTimescale = 4; | 400 | m_angularMotorDecayTimescale = 4; |
401 | m_angularFrictionTimescale = new Vector3(10,10,10); | ||
402 | |||
370 | m_VhoverHeight = 0; | 403 | m_VhoverHeight = 0; |
371 | // m_VhoverEfficiency = 0.5f; | 404 | m_VhoverEfficiency = 0.5f; |
372 | m_VhoverTimescale = 2; | 405 | m_VhoverTimescale = 2; |
373 | m_VehicleBuoyancy = 1; | 406 | m_VehicleBuoyancy = 1; |
374 | // m_linearDeflectionEfficiency = 0.5f; | 407 | |
375 | // m_linearDeflectionTimescale = 3; | 408 | m_linearDeflectionEfficiency = 0.5f; |
376 | // m_angularDeflectionEfficiency = 0.5f; | 409 | m_linearDeflectionTimescale = 3; |
377 | // m_angularDeflectionTimescale = 5; | 410 | |
411 | m_angularDeflectionEfficiency = 0.5f; | ||
412 | m_angularDeflectionTimescale = 5; | ||
413 | |||
378 | m_verticalAttractionEfficiency = 0.5f; | 414 | m_verticalAttractionEfficiency = 0.5f; |
379 | m_verticalAttractionTimescale = 5f; | 415 | m_verticalAttractionTimescale = 5f; |
380 | // m_bankingEfficiency = -0.3f; | 416 | |
381 | // m_bankingMix = 0.8f; | 417 | m_bankingEfficiency = -0.3f; |
382 | // m_bankingTimescale = 1; | 418 | m_bankingMix = 0.8f; |
383 | // m_referenceFrame = Quaternion.Identity; | 419 | m_bankingTimescale = 1; |
420 | |||
421 | m_referenceFrame = Quaternion.Identity; | ||
384 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 422 | m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY |
385 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 423 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
386 | | VehicleFlag.LIMIT_ROLL_ONLY | 424 | | VehicleFlag.LIMIT_ROLL_ONLY |
@@ -390,28 +428,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
390 | | VehicleFlag.HOVER_WATER_ONLY); | 428 | | VehicleFlag.HOVER_WATER_ONLY); |
391 | break; | 429 | break; |
392 | case Vehicle.TYPE_AIRPLANE: | 430 | 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; | 431 | m_linearMotorDirection = Vector3.Zero; |
396 | m_linearMotorTimescale = 2; | 432 | m_linearMotorTimescale = 2; |
397 | m_linearMotorDecayTimescale = 60; | 433 | m_linearMotorDecayTimescale = 60; |
434 | m_linearFrictionTimescale = new Vector3(200, 10, 5); | ||
435 | |||
398 | m_angularMotorDirection = Vector3.Zero; | 436 | m_angularMotorDirection = Vector3.Zero; |
399 | m_angularMotorTimescale = 4; | 437 | m_angularMotorTimescale = 4; |
400 | m_angularMotorDecayTimescale = 4; | 438 | m_angularMotorDecayTimescale = 4; |
439 | m_angularFrictionTimescale = new Vector3(20, 20, 20); | ||
440 | |||
401 | m_VhoverHeight = 0; | 441 | m_VhoverHeight = 0; |
402 | // m_VhoverEfficiency = 0.5f; | 442 | m_VhoverEfficiency = 0.5f; |
403 | m_VhoverTimescale = 1000; | 443 | m_VhoverTimescale = 1000; |
404 | m_VehicleBuoyancy = 0; | 444 | m_VehicleBuoyancy = 0; |
405 | // m_linearDeflectionEfficiency = 0.5f; | 445 | |
406 | // m_linearDeflectionTimescale = 3; | 446 | m_linearDeflectionEfficiency = 0.5f; |
407 | // m_angularDeflectionEfficiency = 1; | 447 | m_linearDeflectionTimescale = 3; |
408 | // m_angularDeflectionTimescale = 2; | 448 | |
449 | m_angularDeflectionEfficiency = 1; | ||
450 | m_angularDeflectionTimescale = 2; | ||
451 | |||
409 | m_verticalAttractionEfficiency = 0.9f; | 452 | m_verticalAttractionEfficiency = 0.9f; |
410 | m_verticalAttractionTimescale = 2f; | 453 | m_verticalAttractionTimescale = 2f; |
411 | // m_bankingEfficiency = 1; | 454 | |
412 | // m_bankingMix = 0.7f; | 455 | m_bankingEfficiency = 1; |
413 | // m_bankingTimescale = 2; | 456 | m_bankingMix = 0.7f; |
414 | // m_referenceFrame = Quaternion.Identity; | 457 | m_bankingTimescale = 2; |
458 | |||
459 | m_referenceFrame = Quaternion.Identity; | ||
415 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 460 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
416 | | VehicleFlag.HOVER_TERRAIN_ONLY | 461 | | VehicleFlag.HOVER_TERRAIN_ONLY |
417 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 462 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
@@ -421,28 +466,36 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
421 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | 466 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); |
422 | break; | 467 | break; |
423 | case Vehicle.TYPE_BALLOON: | 468 | 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; | 469 | m_linearMotorDirection = Vector3.Zero; |
427 | m_linearMotorTimescale = 5; | 470 | m_linearMotorTimescale = 5; |
471 | m_linearFrictionTimescale = new Vector3(5, 5, 5); | ||
428 | m_linearMotorDecayTimescale = 60; | 472 | m_linearMotorDecayTimescale = 60; |
473 | |||
429 | m_angularMotorDirection = Vector3.Zero; | 474 | m_angularMotorDirection = Vector3.Zero; |
430 | m_angularMotorTimescale = 6; | 475 | m_angularMotorTimescale = 6; |
476 | m_angularFrictionTimescale = new Vector3(10, 10, 10); | ||
431 | m_angularMotorDecayTimescale = 10; | 477 | m_angularMotorDecayTimescale = 10; |
478 | |||
432 | m_VhoverHeight = 5; | 479 | m_VhoverHeight = 5; |
433 | // m_VhoverEfficiency = 0.8f; | 480 | m_VhoverEfficiency = 0.8f; |
434 | m_VhoverTimescale = 10; | 481 | m_VhoverTimescale = 10; |
435 | m_VehicleBuoyancy = 1; | 482 | m_VehicleBuoyancy = 1; |
436 | // m_linearDeflectionEfficiency = 0; | 483 | |
437 | // m_linearDeflectionTimescale = 5; | 484 | m_linearDeflectionEfficiency = 0; |
438 | // m_angularDeflectionEfficiency = 0; | 485 | m_linearDeflectionTimescale = 5; |
439 | // m_angularDeflectionTimescale = 5; | 486 | |
487 | m_angularDeflectionEfficiency = 0; | ||
488 | m_angularDeflectionTimescale = 5; | ||
489 | |||
440 | m_verticalAttractionEfficiency = 1f; | 490 | m_verticalAttractionEfficiency = 1f; |
441 | m_verticalAttractionTimescale = 100f; | 491 | m_verticalAttractionTimescale = 100f; |
442 | // m_bankingEfficiency = 0; | 492 | |
443 | // m_bankingMix = 0.7f; | 493 | m_bankingEfficiency = 0; |
444 | // m_bankingTimescale = 5; | 494 | m_bankingMix = 0.7f; |
445 | // m_referenceFrame = Quaternion.Identity; | 495 | m_bankingTimescale = 5; |
496 | m_referenceFrame = Quaternion.Identity; | ||
497 | |||
498 | m_referenceFrame = Quaternion.Identity; | ||
446 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 499 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
447 | | VehicleFlag.HOVER_TERRAIN_ONLY | 500 | | VehicleFlag.HOVER_TERRAIN_ONLY |
448 | | VehicleFlag.HOVER_UP_ONLY | 501 | | VehicleFlag.HOVER_UP_ONLY |
@@ -452,21 +505,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
452 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 505 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
453 | break; | 506 | break; |
454 | } | 507 | } |
455 | }//end SetDefaultsForType | 508 | } |
456 | 509 | ||
457 | // Some of the properties of this prim may have changed. | 510 | // Some of the properties of this prim may have changed. |
458 | // Do any updating needed for a vehicle | 511 | // Do any updating needed for a vehicle |
459 | public void Refresh() | 512 | public void Refresh() |
460 | { | 513 | { |
461 | if (!IsActive) | 514 | if (IsActive) |
462 | return; | 515 | { |
463 | 516 | // Friction effects are handled by this vehicle code | |
464 | // Set the prim's inertia to zero. The vehicle code handles that and this | 517 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); |
465 | // removes the motion and torque actions introduced by Bullet. | 518 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); |
466 | Vector3 inertia = Vector3.Zero; | 519 | } |
467 | // comment out for DEBUG test | ||
468 | // BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); | ||
469 | // BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); | ||
470 | } | 520 | } |
471 | 521 | ||
472 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 522 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
@@ -474,10 +524,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
474 | { | 524 | { |
475 | if (!IsActive) return; | 525 | if (!IsActive) return; |
476 | 526 | ||
527 | // DEBUG | ||
528 | // Because Bullet does apply forces to the vehicle, our last computed | ||
529 | // linear and angular velocities are not what is happening now. | ||
530 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
531 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
532 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
533 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
534 | // END DEBUG | ||
535 | |||
477 | MoveLinear(pTimestep); | 536 | MoveLinear(pTimestep); |
478 | MoveAngular(pTimestep); | 537 | MoveAngular(pTimestep); |
479 | LimitRotation(pTimestep); | 538 | LimitRotation(pTimestep); |
480 | 539 | ||
540 | // DEBUG: Trying to figure out why Bullet goes crazy when the root prim is moved. | ||
541 | // BulletSimAPI.SetInterpolationVelocity2(Prim.BSBody.ptr, m_newVelocity, m_lastAngularVelocity); // DEBUG DEBUG DEBUG | ||
542 | |||
481 | // remember the position so next step we can limit absolute movement effects | 543 | // remember the position so next step we can limit absolute movement effects |
482 | m_lastPositionVector = Prim.ForcePosition; | 544 | m_lastPositionVector = Prim.ForcePosition; |
483 | 545 | ||
@@ -489,62 +551,51 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
489 | // Also does hover and float. | 551 | // Also does hover and float. |
490 | private void MoveLinear(float pTimestep) | 552 | private void MoveLinear(float pTimestep) |
491 | { | 553 | { |
492 | // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates | 554 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates |
493 | // m_lastLinearVelocityVector is the speed we are moving in that direction | 555 | // m_lastLinearVelocityVector is the current speed we are moving in that direction |
494 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | 556 | if (m_linearMotorDirection.LengthSquared() > 0.001f) |
495 | { | 557 | { |
496 | Vector3 origDir = m_linearMotorDirection; | 558 | Vector3 origDir = m_linearMotorDirection; |
497 | Vector3 origVel = m_lastLinearVelocityVector; | 559 | Vector3 origVel = m_lastLinearVelocityVector; |
560 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
498 | 561 | ||
499 | // add drive to body | 562 | // add drive to body |
500 | // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale / pTimestep); | 563 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; |
501 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale / pTimestep); | ||
502 | // lastLinearVelocityVector is the current body velocity vector | 564 | // lastLinearVelocityVector is the current body velocity vector |
503 | // RA: Not sure what the *10 is for. A correction for pTimestep? | ||
504 | // m_lastLinearVelocityVector += (addAmount*10); | ||
505 | m_lastLinearVelocityVector += addAmount; | 565 | m_lastLinearVelocityVector += addAmount; |
506 | 566 | ||
507 | // Limit the velocity vector to less than the last set linear motor direction | 567 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; |
508 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | 568 | m_linearMotorDirection *= (1f - decayFactor); |
509 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | 569 | |
510 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | 570 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; |
511 | m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; | 571 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); |
512 | if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) | 572 | |
513 | m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; | 573 | // Rotate new object velocity from vehicle relative to world coordinates |
514 | 574 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | |
515 | /* | 575 | |
516 | // decay applied velocity | 576 | VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lmVel={8},newVel={9}", |
517 | Vector3 decayfraction = Vector3.One/(m_linearMotorDecayTimescale / pTimestep); | 577 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, |
518 | // (RA: do not know where the 0.5f comes from) | 578 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); |
519 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | ||
520 | */ | ||
521 | float keepfraction = 1.0f - (1.0f / (m_linearMotorDecayTimescale / pTimestep)); | ||
522 | m_linearMotorDirection *= keepfraction; | ||
523 | |||
524 | VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}", | ||
525 | Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector); | ||
526 | } | 579 | } |
527 | else | 580 | else |
528 | { | 581 | { |
529 | // if what remains of direction is very small, zero it. | 582 | // if what remains of direction is very small, zero it. |
530 | m_linearMotorDirection = Vector3.Zero; | 583 | m_linearMotorDirection = Vector3.Zero; |
531 | m_lastLinearVelocityVector = Vector3.Zero; | 584 | m_lastLinearVelocityVector = Vector3.Zero; |
585 | m_newVelocity = Vector3.Zero; | ||
586 | |||
532 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 587 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); |
533 | } | 588 | } |
534 | 589 | ||
535 | // convert requested object velocity to object relative vector | 590 | // m_newVelocity is velocity computed from linear motor in world coordinates |
536 | Quaternion rotq = Prim.ForceOrientation; | ||
537 | m_newVelocity = m_lastLinearVelocityVector * rotq; | ||
538 | |||
539 | // Add the various forces into m_dir which will be our new direction vector (velocity) | ||
540 | 591 | ||
541 | // add Gravity and Buoyancy | 592 | // Gravity and Buoyancy |
542 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 593 | // There is some gravity, make a gravity force vector that is applied after object velocity. |
543 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 594 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
544 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy)); | 595 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); |
545 | 596 | ||
546 | /* | 597 | /* |
547 | * RA: Not sure why one would do this | 598 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... |
548 | // Preserve the current Z velocity | 599 | // Preserve the current Z velocity |
549 | Vector3 vel_now = m_prim.Velocity; | 600 | Vector3 vel_now = m_prim.Velocity; |
550 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 601 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity |
@@ -567,6 +618,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
567 | } | 618 | } |
568 | 619 | ||
569 | // Check if hovering | 620 | // Check if hovering |
621 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | ||
622 | // m_VhoverTimescale: time to achieve height | ||
570 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 623 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
571 | { | 624 | { |
572 | // We should hover, get the target height | 625 | // We should hover, get the target height |
@@ -597,13 +650,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
597 | } | 650 | } |
598 | else | 651 | else |
599 | { | 652 | { |
600 | float herr0 = pos.Z - m_VhoverTargetHeight; | 653 | float verticalError = pos.Z - m_VhoverTargetHeight; |
654 | // RA: where does the 50 come from? | ||
655 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | ||
601 | // Replace Vertical speed with correction figure if significant | 656 | // Replace Vertical speed with correction figure if significant |
602 | if (Math.Abs(herr0) > 0.01f) | 657 | if (Math.Abs(verticalError) > 0.01f) |
603 | { | 658 | { |
604 | m_newVelocity.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); | 659 | m_newVelocity.Z += verticalCorrectionVelocity; |
605 | //KF: m_VhoverEfficiency is not yet implemented | 660 | //KF: m_VhoverEfficiency is not yet implemented |
606 | } | 661 | } |
662 | else if (verticalError < -0.01) | ||
663 | { | ||
664 | m_newVelocity.Z -= verticalCorrectionVelocity; | ||
665 | } | ||
607 | else | 666 | else |
608 | { | 667 | { |
609 | m_newVelocity.Z = 0f; | 668 | m_newVelocity.Z = 0f; |
@@ -680,19 +739,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
680 | 739 | ||
681 | // Apply velocity | 740 | // Apply velocity |
682 | Prim.ForceVelocity = m_newVelocity; | 741 | Prim.ForceVelocity = m_newVelocity; |
683 | // apply gravity force | 742 | // Prim.AddForce(m_newVelocity * Prim.Linkset.LinksetMass, false); |
684 | // Why is this set here? The physics engine already does gravity. | 743 | Prim.AddForce(grav * Prim.Linkset.LinksetMass, false); |
685 | Prim.AddForce(grav, false, true); | ||
686 | 744 | ||
687 | // Apply friction | 745 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4}", |
688 | Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); | 746 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav); |
689 | m_lastLinearVelocityVector *= keepFraction; | ||
690 | |||
691 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", | ||
692 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); | ||
693 | 747 | ||
694 | } // end MoveLinear() | 748 | } // end MoveLinear() |
695 | 749 | ||
750 | // ======================================================================= | ||
696 | // Apply the effect of the angular motor. | 751 | // Apply the effect of the angular motor. |
697 | private void MoveAngular(float pTimestep) | 752 | private void MoveAngular(float pTimestep) |
698 | { | 753 | { |
@@ -704,94 +759,150 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
704 | // m_angularFrictionTimescale // body angular velocity decay rate | 759 | // m_angularFrictionTimescale // body angular velocity decay rate |
705 | // m_lastAngularVelocity // what was last applied to body | 760 | // m_lastAngularVelocity // what was last applied to body |
706 | 761 | ||
707 | // Get what the body is doing, this includes 'external' influences | 762 | if (m_angularMotorDirection.LengthSquared() > 0.0001) |
708 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
709 | |||
710 | if (m_angularMotorApply > 0) | ||
711 | { | 763 | { |
712 | // Rather than snapping the angular motor velocity from the old value to | ||
713 | // a newly set velocity, this routine steps the value from the previous | ||
714 | // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). | ||
715 | // There are m_angularMotorApply steps. | ||
716 | Vector3 origVel = m_angularMotorVelocity; | 764 | Vector3 origVel = m_angularMotorVelocity; |
717 | Vector3 origDir = m_angularMotorDirection; | 765 | Vector3 origDir = m_angularMotorDirection; |
718 | 766 | ||
719 | // ramp up to new value | 767 | // new velocity += error / ( time to get there / step interval) |
720 | // new velocity += error / ( time to get there / step interval) | 768 | // requested speed - last motor speed |
721 | // requested speed - last motor speed | 769 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); |
722 | m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); | 770 | // decay requested direction |
723 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | 771 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); |
724 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | ||
725 | 772 | ||
726 | VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},origDir={5},vel={6}", | 773 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", |
727 | Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | 774 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); |
728 | |||
729 | m_angularMotorApply--; | ||
730 | } | 775 | } |
731 | else | 776 | else |
732 | { | 777 | { |
733 | // No motor recently applied, keep the body velocity | 778 | m_angularMotorVelocity = Vector3.Zero; |
734 | // and decay the velocity | 779 | } |
735 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | 780 | |
736 | if (m_angularMotorVelocity.LengthSquared() < 0.00001) | 781 | #region Vertical attactor |
737 | m_angularMotorVelocity = Vector3.Zero; | 782 | |
738 | } // end motor section | ||
739 | |||
740 | // Vertical attractor section | ||
741 | Vector3 vertattr = Vector3.Zero; | 783 | Vector3 vertattr = Vector3.Zero; |
742 | Vector3 deflection = Vector3.Zero; | 784 | Vector3 deflection = Vector3.Zero; |
743 | Vector3 banking = Vector3.Zero; | 785 | Vector3 banking = Vector3.Zero; |
744 | 786 | ||
745 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | 787 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) |
746 | { | 788 | { |
747 | float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); | 789 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; |
748 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 790 | if (Prim.Linkset.LinksetIsColliding) |
791 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | ||
749 | 792 | ||
750 | // get present body rotation | 793 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); |
751 | Quaternion rotq = Prim.ForceOrientation; | ||
752 | // vector pointing up | ||
753 | Vector3 verterr = Vector3.Zero; | ||
754 | verterr.Z = 1.0f; | ||
755 | 794 | ||
756 | // rotate it to Body Angle | 795 | // Create a vector of the vehicle "up" in world coordinates |
757 | verterr = verterr * rotq; | 796 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; |
758 | // 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. | 797 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no |
759 | // 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 | 798 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its |
760 | // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. | 799 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall |
800 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
801 | // modulated to prevent a stable inverted body. | ||
761 | 802 | ||
762 | // Error is 0 (no error) to +/- 2 (max error) | 803 | // Error is 0 (no error) to +/- 2 (max error) |
763 | if (verterr.Z < 0.0f) | 804 | if (verticalError.Z < 0.0f) |
764 | { | 805 | { |
765 | verterr.X = 2.0f - verterr.X; | 806 | verticalError.X = 2.0f - verticalError.X; |
766 | verterr.Y = 2.0f - verterr.Y; | 807 | verticalError.Y = 2.0f - verticalError.Y; |
767 | } | 808 | } |
768 | // scale it by VAservo | 809 | // scale it by VAservo |
769 | verterr = verterr * VAservo; | 810 | verticalError = verticalError * VAservo; |
770 | 811 | ||
771 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | 812 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y |
772 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | 813 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. |
773 | vertattr.X = verterr.Y; | 814 | // Z is not changed. |
774 | vertattr.Y = - verterr.X; | 815 | vertattr.X = verticalError.Y; |
816 | vertattr.Y = - verticalError.X; | ||
775 | vertattr.Z = 0f; | 817 | vertattr.Z = 0f; |
776 | 818 | ||
777 | // scaling appears better usingsquare-law | 819 | // scaling appears better usingsquare-law |
820 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
778 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | 821 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); |
779 | vertattr.X += bounce * angularVelocity.X; | 822 | vertattr.X += bounce * angularVelocity.X; |
780 | vertattr.Y += bounce * angularVelocity.Y; | 823 | vertattr.Y += bounce * angularVelocity.Y; |
781 | 824 | ||
782 | VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", | 825 | VDetailLog("{0},MoveAngular,verticalAttraction,verticalError={1},bounce={2},vertattr={3}", |
783 | Prim.LocalID, verterr, bounce, vertattr); | 826 | Prim.LocalID, verticalError, bounce, vertattr); |
784 | 827 | ||
785 | } // else vertical attractor is off | 828 | } |
829 | #endregion // Vertical attactor | ||
786 | 830 | ||
787 | m_lastVertAttractor = vertattr; | 831 | #region Deflection |
832 | |||
833 | //Forward is the prefered direction, but if the reference frame has changed, we need to take this into account as well | ||
834 | if (m_angularDeflectionEfficiency != 0) | ||
835 | { | ||
836 | Vector3 preferredAxisOfMotion = | ||
837 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
838 | preferredAxisOfMotion *= Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
839 | |||
840 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
841 | |||
842 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
843 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
844 | } | ||
845 | |||
846 | #endregion | ||
847 | |||
848 | #region Banking | ||
849 | |||
850 | if (m_bankingEfficiency != 0) | ||
851 | { | ||
852 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | ||
853 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | ||
854 | //Changes which way it banks in and out of turns | ||
855 | |||
856 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
857 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
858 | if (m_bankingEfficiency < 0) | ||
859 | effSquared *= -1; //Keep the negative! | ||
788 | 860 | ||
789 | // Bank section tba | 861 | float mix = Math.Abs(m_bankingMix); |
862 | if (m_angularMotorVelocity.X == 0) | ||
863 | { | ||
864 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
865 | { | ||
866 | Vector3 axisAngle; | ||
867 | float angle; | ||
868 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
869 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
870 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
871 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
872 | else | ||
873 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
874 | }*/ | ||
875 | } | ||
876 | else | ||
877 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
878 | if (!Prim.Linkset.LinksetIsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
879 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
880 | { | ||
881 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
882 | /*if(angVelZ > mix) | ||
883 | angVelZ = mix; | ||
884 | else if(angVelZ < -mix) | ||
885 | angVelZ = -mix;*/ | ||
886 | //This controls how fast and how far the banking occurs | ||
887 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
888 | if (bankingRot.X > 3) | ||
889 | bankingRot.X = 3; | ||
890 | else if (bankingRot.X < -3) | ||
891 | bankingRot.X = -3; | ||
892 | bankingRot *= Prim.ForceOrientation; | ||
893 | banking += bankingRot; | ||
894 | } | ||
895 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
896 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
897 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
898 | } | ||
899 | |||
900 | #endregion | ||
790 | 901 | ||
791 | // Deflection section tba | 902 | m_lastVertAttractor = vertattr; |
792 | 903 | ||
793 | // Sum velocities | 904 | // Sum velocities |
794 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection | 905 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; |
795 | 906 | ||
796 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 907 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
797 | { | 908 | { |
@@ -806,52 +917,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
806 | VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 917 | VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); |
807 | } | 918 | } |
808 | 919 | ||
809 | // apply friction | ||
810 | Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); | ||
811 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; | ||
812 | |||
813 | // Apply to the body | 920 | // Apply to the body |
814 | Prim.ForceRotationalVelocity = m_lastAngularVelocity; | 921 | // The above calculates the absolute angular velocity needed |
922 | // Prim.ForceRotationalVelocity = m_lastAngularVelocity; | ||
923 | |||
924 | // Apply a force to overcome current angular velocity | ||
925 | Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity) * Prim.Linkset.LinksetMass; | ||
926 | // Vector3 applyAngularForce = (m_lastAngularVelocity - Prim.ForceRotationalVelocity); | ||
927 | // Prim.AddAngularForce(applyAngularForce, false); | ||
928 | Prim.ApplyTorqueImpulse(applyAngularForce, false); | ||
929 | |||
930 | // Apply friction for next time | ||
931 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | ||
932 | m_lastAngularVelocity *= Vector3.One - decayamount; | ||
815 | 933 | ||
816 | VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); | 934 | VDetailLog("{0},MoveAngular,done,applyAForce={1},decay={2},lastAngular={3}", |
935 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | ||
817 | } //end MoveAngular | 936 | } //end MoveAngular |
818 | 937 | ||
819 | internal void LimitRotation(float timestep) | 938 | internal void LimitRotation(float timestep) |
820 | { | 939 | { |
821 | Quaternion rotq = Prim.ForceOrientation; | 940 | Quaternion rotq = Prim.ForceOrientation; |
822 | Quaternion m_rot = rotq; | 941 | Quaternion m_rot = rotq; |
823 | bool changed = false; | ||
824 | if (m_RollreferenceFrame != Quaternion.Identity) | 942 | if (m_RollreferenceFrame != Quaternion.Identity) |
825 | { | 943 | { |
826 | if (rotq.X >= m_RollreferenceFrame.X) | 944 | if (rotq.X >= m_RollreferenceFrame.X) |
827 | { | 945 | { |
828 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | 946 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); |
829 | changed = true; | ||
830 | } | 947 | } |
831 | if (rotq.Y >= m_RollreferenceFrame.Y) | 948 | if (rotq.Y >= m_RollreferenceFrame.Y) |
832 | { | 949 | { |
833 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | 950 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); |
834 | changed = true; | ||
835 | } | 951 | } |
836 | if (rotq.X <= -m_RollreferenceFrame.X) | 952 | if (rotq.X <= -m_RollreferenceFrame.X) |
837 | { | 953 | { |
838 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | 954 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); |
839 | changed = true; | ||
840 | } | 955 | } |
841 | if (rotq.Y <= -m_RollreferenceFrame.Y) | 956 | if (rotq.Y <= -m_RollreferenceFrame.Y) |
842 | { | 957 | { |
843 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | 958 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); |
844 | changed = true; | ||
845 | } | 959 | } |
846 | changed = true; | ||
847 | } | 960 | } |
848 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | 961 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) |
849 | { | 962 | { |
850 | m_rot.X = 0; | 963 | m_rot.X = 0; |
851 | m_rot.Y = 0; | 964 | m_rot.Y = 0; |
852 | changed = true; | ||
853 | } | 965 | } |
854 | if (changed) | 966 | if (rotq != m_rot) |
855 | { | 967 | { |
856 | Prim.ForceOrientation = m_rot; | 968 | Prim.ForceOrientation = m_rot; |
857 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 969 | 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 c984824..3a92f93 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -36,20 +36,29 @@ public 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 | } | ||
39 | // Create the correct type of linkset for this child | 45 | // Create the correct type of linkset for this child |
40 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | 46 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) |
41 | { | 47 | { |
42 | BSLinkset ret = null; | 48 | BSLinkset ret = null; |
43 | /* | ||
44 | if (parent.IsPhysical) | ||
45 | ret = new BSLinksetConstraints(physScene, parent); | ||
46 | else | ||
47 | ret = new BSLinksetManual(physScene, parent); | ||
48 | */ | ||
49 | |||
50 | // at the moment, there is only one | ||
51 | ret = new BSLinksetConstraints(physScene, parent); | ||
52 | 49 | ||
50 | switch ((int)physScene.Params.linksetImplementation) | ||
51 | { | ||
52 | case (int)LinksetImplementation.Compound: | ||
53 | ret = new BSLinksetCompound(physScene, parent); | ||
54 | break; | ||
55 | case (int)LinksetImplementation.Manual: | ||
56 | // ret = new BSLinksetManual(physScene, parent); | ||
57 | break; | ||
58 | default: | ||
59 | ret = new BSLinksetConstraints(physScene, parent); | ||
60 | break; | ||
61 | } | ||
53 | return ret; | 62 | return ret; |
54 | } | 63 | } |
55 | 64 | ||
@@ -61,22 +70,27 @@ public abstract class BSLinkset | |||
61 | public int LinksetID { get; private set; } | 70 | public int LinksetID { get; private set; } |
62 | 71 | ||
63 | // The children under the root in this linkset. | 72 | // The children under the root in this linkset. |
64 | // There are two lists of children: the current children at runtime | ||
65 | // and the children at taint-time. For instance, if you delink a | ||
66 | // child from the linkset, the child is removed from m_children | ||
67 | // but the constraint won't be removed until taint time. | ||
68 | // Two lists lets this track the 'current' children and | ||
69 | // the physical 'taint' children separately. | ||
70 | // After taint processing and before the simulation step, these | ||
71 | // two lists must be the same. | ||
72 | protected HashSet<BSPhysObject> m_children; | 73 | protected HashSet<BSPhysObject> m_children; |
73 | protected HashSet<BSPhysObject> m_taintChildren; | ||
74 | 74 | ||
75 | // We lock the diddling of linkset classes to prevent any badness. | 75 | // We lock the diddling of linkset classes to prevent any badness. |
76 | // This locks the modification of the instances of this class. Changes | 76 | // This locks the modification of the instances of this class. Changes |
77 | // to the physical representation is done via the tainting mechenism. | 77 | // to the physical representation is done via the tainting mechenism. |
78 | protected object m_linksetActivityLock = new Object(); | 78 | protected object m_linksetActivityLock = new Object(); |
79 | 79 | ||
80 | // Some linksets have a preferred physical shape. | ||
81 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
82 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
83 | { | ||
84 | return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
85 | } | ||
86 | |||
87 | // Linksets move around the children so the linkset might need to compute the child position | ||
88 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
89 | { return member.RawPosition; } | ||
90 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
91 | { return member.RawOrientation; } | ||
92 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
93 | |||
80 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 94 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
81 | protected float m_mass; | 95 | protected float m_mass; |
82 | public float LinksetMass | 96 | public float LinksetMass |
@@ -88,6 +102,8 @@ public abstract class BSLinkset | |||
88 | } | 102 | } |
89 | } | 103 | } |
90 | 104 | ||
105 | public virtual bool LinksetIsColliding { get { return false; } } | ||
106 | |||
91 | public OMV.Vector3 CenterOfMass | 107 | public OMV.Vector3 CenterOfMass |
92 | { | 108 | { |
93 | get { return ComputeLinksetCenterOfMass(); } | 109 | get { return ComputeLinksetCenterOfMass(); } |
@@ -108,8 +124,7 @@ public abstract class BSLinkset | |||
108 | PhysicsScene = scene; | 124 | PhysicsScene = scene; |
109 | LinksetRoot = parent; | 125 | LinksetRoot = parent; |
110 | m_children = new HashSet<BSPhysObject>(); | 126 | m_children = new HashSet<BSPhysObject>(); |
111 | m_taintChildren = new HashSet<BSPhysObject>(); | 127 | m_mass = parent.RawMass; |
112 | m_mass = parent.MassRaw; | ||
113 | } | 128 | } |
114 | 129 | ||
115 | // Link to a linkset where the child knows the parent. | 130 | // Link to a linkset where the child knows the parent. |
@@ -140,7 +155,6 @@ public abstract class BSLinkset | |||
140 | // Cannot remove the root from a linkset. | 155 | // Cannot remove the root from a linkset. |
141 | return this; | 156 | return this; |
142 | } | 157 | } |
143 | |||
144 | RemoveChildFromLinkset(child); | 158 | RemoveChildFromLinkset(child); |
145 | } | 159 | } |
146 | 160 | ||
@@ -165,9 +179,8 @@ public abstract class BSLinkset | |||
165 | bool ret = false; | 179 | bool ret = false; |
166 | lock (m_linksetActivityLock) | 180 | lock (m_linksetActivityLock) |
167 | { | 181 | { |
168 | if (m_children.Contains(child)) | 182 | ret = m_children.Contains(child); |
169 | ret = true; | 183 | /* Safer version but the above should work |
170 | /* | ||
171 | foreach (BSPhysObject bp in m_children) | 184 | foreach (BSPhysObject bp in m_children) |
172 | { | 185 | { |
173 | if (child.LocalID == bp.LocalID) | 186 | if (child.LocalID == bp.LocalID) |
@@ -181,10 +194,36 @@ public abstract class BSLinkset | |||
181 | return ret; | 194 | return ret; |
182 | } | 195 | } |
183 | 196 | ||
197 | // Perform an action on each member of the linkset including root prim. | ||
198 | // Depends on the action on whether this should be done at taint time. | ||
199 | public delegate bool ForEachMemberAction(BSPhysObject obj); | ||
200 | public virtual bool ForEachMember(ForEachMemberAction action) | ||
201 | { | ||
202 | bool ret = false; | ||
203 | lock (m_linksetActivityLock) | ||
204 | { | ||
205 | action(LinksetRoot); | ||
206 | foreach (BSPhysObject po in m_children) | ||
207 | { | ||
208 | if (action(po)) | ||
209 | break; | ||
210 | } | ||
211 | } | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | // I am the root of a linkset and a new child is being added | ||
216 | // Called while LinkActivity is locked. | ||
217 | protected abstract void AddChildToLinkset(BSPhysObject child); | ||
218 | |||
219 | // I am the root of a linkset and one of my children is being removed. | ||
220 | // Safe to call even if the child is not really in my linkset. | ||
221 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | ||
222 | |||
184 | // When physical properties are changed the linkset needs to recalculate | 223 | // When physical properties are changed the linkset needs to recalculate |
185 | // its internal properties. | 224 | // its internal properties. |
186 | // May be called at runtime or taint-time (just pass the appropriate flag). | 225 | // May be called at runtime or taint-time. |
187 | public abstract void Refresh(BSPhysObject requestor, bool inTaintTime); | 226 | public abstract void Refresh(BSPhysObject requestor); |
188 | 227 | ||
189 | // The object is going dynamic (physical). Do any setup necessary | 228 | // The object is going dynamic (physical). Do any setup necessary |
190 | // for a dynamic linkset. | 229 | // for a dynamic linkset. |
@@ -218,17 +257,17 @@ public abstract class BSLinkset | |||
218 | public abstract void RestoreBodyDependencies(BSPrim child); | 257 | public abstract void RestoreBodyDependencies(BSPrim child); |
219 | 258 | ||
220 | // ================================================================ | 259 | // ================================================================ |
221 | // Below this point is internal magic | ||
222 | |||
223 | protected virtual float ComputeLinksetMass() | 260 | protected virtual float ComputeLinksetMass() |
224 | { | 261 | { |
225 | float mass; | 262 | float mass = LinksetRoot.RawMass; |
226 | lock (m_linksetActivityLock) | 263 | if (HasAnyChildren) |
227 | { | 264 | { |
228 | mass = LinksetRoot.MassRaw; | 265 | lock (m_linksetActivityLock) |
229 | foreach (BSPhysObject bp in m_taintChildren) | ||
230 | { | 266 | { |
231 | mass += bp.MassRaw; | 267 | foreach (BSPhysObject bp in m_children) |
268 | { | ||
269 | mass += bp.RawMass; | ||
270 | } | ||
232 | } | 271 | } |
233 | } | 272 | } |
234 | return mass; | 273 | return mass; |
@@ -239,13 +278,13 @@ public abstract class BSLinkset | |||
239 | OMV.Vector3 com; | 278 | OMV.Vector3 com; |
240 | lock (m_linksetActivityLock) | 279 | lock (m_linksetActivityLock) |
241 | { | 280 | { |
242 | com = LinksetRoot.Position * LinksetRoot.MassRaw; | 281 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
243 | float totalMass = LinksetRoot.MassRaw; | 282 | float totalMass = LinksetRoot.RawMass; |
244 | 283 | ||
245 | foreach (BSPhysObject bp in m_taintChildren) | 284 | foreach (BSPhysObject bp in m_children) |
246 | { | 285 | { |
247 | com += bp.Position * bp.MassRaw; | 286 | com += bp.Position * bp.RawMass; |
248 | totalMass += bp.MassRaw; | 287 | totalMass += bp.RawMass; |
249 | } | 288 | } |
250 | if (totalMass != 0f) | 289 | if (totalMass != 0f) |
251 | com /= totalMass; | 290 | com /= totalMass; |
@@ -261,31 +300,16 @@ public abstract class BSLinkset | |||
261 | { | 300 | { |
262 | com = LinksetRoot.Position; | 301 | com = LinksetRoot.Position; |
263 | 302 | ||
264 | foreach (BSPhysObject bp in m_taintChildren) | 303 | foreach (BSPhysObject bp in m_children) |
265 | { | 304 | { |
266 | com += bp.Position * bp.MassRaw; | 305 | com += bp.Position * bp.RawMass; |
267 | } | 306 | } |
268 | com /= (m_taintChildren.Count + 1); | 307 | com /= (m_children.Count + 1); |
269 | } | 308 | } |
270 | 309 | ||
271 | return com; | 310 | return com; |
272 | } | 311 | } |
273 | 312 | ||
274 | // I am the root of a linkset and a new child is being added | ||
275 | // Called while LinkActivity is locked. | ||
276 | protected abstract void AddChildToLinkset(BSPhysObject child); | ||
277 | |||
278 | // Forcefully removing a child from a linkset. | ||
279 | // This is not being called by the child so we have to make sure the child doesn't think | ||
280 | // it's still connected to the linkset. | ||
281 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information | ||
282 | // also has to be updated (like pointer to prim's parent). | ||
283 | protected abstract void RemoveChildFromOtherLinkset(BSPhysObject pchild); | ||
284 | |||
285 | // I am the root of a linkset and one of my children is being removed. | ||
286 | // Safe to call even if the child is not really in my linkset. | ||
287 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | ||
288 | |||
289 | // Invoke the detailed logger and output something if it's enabled. | 313 | // Invoke the detailed logger and output something if it's enabled. |
290 | protected void DetailLog(string msg, params Object[] args) | 314 | protected void DetailLog(string msg, params Object[] args) |
291 | { | 315 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs new file mode 100755 index 0000000..12c6d7a --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -0,0 +1,273 @@ | |||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public 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 ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
46 | { | ||
47 | ShapeData.PhysicsShapeType ret = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
48 | if (IsRoot(requestor) && HasAnyChildren) | ||
49 | { | ||
50 | ret = ShapeData.PhysicsShapeType.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 | // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. | ||
268 | // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, | ||
269 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); | ||
270 | |||
271 | } | ||
272 | } | ||
273 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 8a750b5..d2387fb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -32,7 +32,7 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | public class BSLinksetConstraints : BSLinkset | 35 | public sealed class BSLinksetConstraints : BSLinkset |
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
@@ -43,23 +43,16 @@ public class BSLinksetConstraints : BSLinkset | |||
43 | 43 | ||
44 | // When physical properties are changed the linkset needs to recalculate | 44 | // When physical properties are changed the linkset needs to recalculate |
45 | // its internal properties. | 45 | // its internal properties. |
46 | // May be called at runtime or taint-time (just pass the appropriate flag). | 46 | // This is queued in the 'post taint' queue so the |
47 | public override void Refresh(BSPhysObject requestor, bool inTaintTime) | 47 | // refresh will happen once after all the other taints are applied. |
48 | public override void Refresh(BSPhysObject requestor) | ||
48 | { | 49 | { |
49 | // If there are no children or not root, I am not the one that recomputes the constraints | 50 | // Queue to happen after all the other taint processing |
50 | if (!HasAnyChildren || !IsRoot(requestor)) | 51 | PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
51 | return; | ||
52 | |||
53 | BSScene.TaintCallback refreshOperation = delegate() | ||
54 | { | 52 | { |
55 | RecomputeLinksetConstraintVariables(); | 53 | if (HasAnyChildren && IsRoot(requestor)) |
56 | DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}", | 54 | RecomputeLinksetConstraints(); |
57 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); | 55 | }); |
58 | }; | ||
59 | if (inTaintTime) | ||
60 | refreshOperation(); | ||
61 | else | ||
62 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation); | ||
63 | } | 56 | } |
64 | 57 | ||
65 | // The object is going dynamic (physical). Do any setup necessary | 58 | // The object is going dynamic (physical). Do any setup necessary |
@@ -74,9 +67,10 @@ public class BSLinksetConstraints : BSLinkset | |||
74 | return false; | 67 | return false; |
75 | } | 68 | } |
76 | 69 | ||
77 | // The object is going static (non-physical). Do any setup necessary | 70 | // The object is going static (non-physical). Do any setup necessary for a static linkset. |
78 | // for a static linkset. | ||
79 | // Return 'true' if any properties updated on the passed object. | 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. | ||
80 | // Called at taint-time! | 74 | // Called at taint-time! |
81 | public override bool MakeStatic(BSPhysObject child) | 75 | public override bool MakeStatic(BSPhysObject child) |
82 | { | 76 | { |
@@ -90,35 +84,36 @@ public class BSLinksetConstraints : BSLinkset | |||
90 | // Nothing to do for constraints on property updates | 84 | // Nothing to do for constraints on property updates |
91 | } | 85 | } |
92 | 86 | ||
93 | // Routine used when rebuilding the body of the root of the linkset | 87 | // The children of the linkset are moved around by the constraints. |
94 | // Destroy all the constraints have have been made to root. | 88 | // Just grab the current values of wherever it is right now. |
95 | // This is called when the root body is changing. | 89 | public override OMV.Vector3 Position(BSPhysObject member) |
96 | // Returns 'true' of something eas actually removed and would need restoring | 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 | ||
97 | // Called at taint-time!! | 103 | // Called at taint-time!! |
98 | public override bool RemoveBodyDependencies(BSPrim child) | 104 | public override bool RemoveBodyDependencies(BSPrim child) |
99 | { | 105 | { |
100 | bool ret = false; | 106 | bool ret = false; |
101 | 107 | ||
108 | DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | ||
109 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); | ||
110 | |||
102 | lock (m_linksetActivityLock) | 111 | lock (m_linksetActivityLock) |
103 | { | 112 | { |
104 | if (IsRoot(child)) | 113 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. |
105 | { | 114 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
106 | // If the one with the dependency is root, must undo all children | 115 | // Cause the constraints, et al to be rebuilt before the next simulation step. |
107 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", | 116 | Refresh(LinksetRoot); |
108 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); | ||
109 | |||
110 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
111 | } | ||
112 | else | ||
113 | { | ||
114 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}", | ||
115 | child.LocalID, | ||
116 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | ||
117 | child.LocalID, child.BSBody.ptr.ToString("X")); | ||
118 | // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child); | ||
119 | // Despite the function name, this removes any link to the specified object. | ||
120 | ret = PhysicallyUnlinkAllChildrenFromRoot(child); | ||
121 | } | ||
122 | } | 117 | } |
123 | return ret; | 118 | return ret; |
124 | } | 119 | } |
@@ -128,32 +123,12 @@ public class BSLinksetConstraints : BSLinkset | |||
128 | // Called at taint-time!! | 123 | // Called at taint-time!! |
129 | public override void RestoreBodyDependencies(BSPrim child) | 124 | public override void RestoreBodyDependencies(BSPrim child) |
130 | { | 125 | { |
131 | lock (m_linksetActivityLock) | 126 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. |
132 | { | ||
133 | if (IsRoot(child)) | ||
134 | { | ||
135 | DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}", | ||
136 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); | ||
137 | foreach (BSPhysObject bpo in m_taintChildren) | ||
138 | { | ||
139 | PhysicallyLinkAChildToRoot(LinksetRoot, bpo); | ||
140 | } | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}", | ||
145 | LinksetRoot.LocalID, | ||
146 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | ||
147 | child.LocalID, child.BSBody.ptr.ToString("X")); | ||
148 | PhysicallyLinkAChildToRoot(LinksetRoot, child); | ||
149 | } | ||
150 | } | ||
151 | } | 127 | } |
152 | 128 | ||
153 | // ================================================================ | 129 | // ================================================================ |
154 | // Below this point is internal magic | ||
155 | 130 | ||
156 | // I am the root of a linkset and a new child is being added | 131 | // Add a new child to the linkset. |
157 | // Called while LinkActivity is locked. | 132 | // Called while LinkActivity is locked. |
158 | protected override void AddChildToLinkset(BSPhysObject child) | 133 | protected override void AddChildToLinkset(BSPhysObject child) |
159 | { | 134 | { |
@@ -161,39 +136,15 @@ public class BSLinksetConstraints : BSLinkset | |||
161 | { | 136 | { |
162 | m_children.Add(child); | 137 | m_children.Add(child); |
163 | 138 | ||
164 | BSPhysObject rootx = LinksetRoot; // capture the root as of now | 139 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
165 | BSPhysObject childx = child; | ||
166 | |||
167 | DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
168 | 140 | ||
169 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() | 141 | // Cause constraints and assorted properties to be recomputed before the next simulation step. |
170 | { | 142 | Refresh(LinksetRoot); |
171 | DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}", | ||
172 | rootx.LocalID, | ||
173 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | ||
174 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | ||
175 | // Since this is taint-time, the body and shape could have changed for the child | ||
176 | rootx.ForcePosition = rootx.Position; // DEBUG | ||
177 | childx.ForcePosition = childx.Position; // DEBUG | ||
178 | PhysicallyLinkAChildToRoot(rootx, childx); | ||
179 | m_taintChildren.Add(child); | ||
180 | }); | ||
181 | } | 143 | } |
182 | return; | 144 | return; |
183 | } | 145 | } |
184 | 146 | ||
185 | // Forcefully removing a child from a linkset. | 147 | // Remove the specified child from the linkset. |
186 | // This is not being called by the child so we have to make sure the child doesn't think | ||
187 | // it's still connected to the linkset. | ||
188 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information | ||
189 | // also has to be updated (like pointer to prim's parent). | ||
190 | protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild) | ||
191 | { | ||
192 | pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild); | ||
193 | RemoveChildFromLinkset(pchild); | ||
194 | } | ||
195 | |||
196 | // I am the root of a linkset and one of my children is being removed. | ||
197 | // Safe to call even if the child is not really in my linkset. | 148 | // Safe to call even if the child is not really in my linkset. |
198 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 149 | protected override void RemoveChildFromLinkset(BSPhysObject child) |
199 | { | 150 | { |
@@ -202,22 +153,21 @@ public class BSLinksetConstraints : BSLinkset | |||
202 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | 153 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now |
203 | BSPhysObject childx = child; | 154 | BSPhysObject childx = child; |
204 | 155 | ||
205 | DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 156 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
206 | childx.LocalID, | 157 | childx.LocalID, |
207 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | 158 | rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), |
208 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | 159 | childx.LocalID, childx.PhysBody.ptr.ToString("X")); |
209 | 160 | ||
210 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | 161 | PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
211 | { | 162 | { |
212 | m_taintChildren.Remove(child); | ||
213 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 163 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
214 | RecomputeLinksetConstraintVariables(); | ||
215 | }); | 164 | }); |
216 | 165 | // See that the linkset parameters are recomputed at the end of the taint time. | |
166 | Refresh(LinksetRoot); | ||
217 | } | 167 | } |
218 | else | 168 | else |
219 | { | 169 | { |
220 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | 170 | // Non-fatal occurance. |
221 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | 171 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); |
222 | } | 172 | } |
223 | return; | 173 | return; |
@@ -227,6 +177,12 @@ public class BSLinksetConstraints : BSLinkset | |||
227 | // Called at taint time! | 177 | // Called at taint time! |
228 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 178 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
229 | { | 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 | { | ||
230 | // Zero motion for children so they don't interpolate | 186 | // Zero motion for children so they don't interpolate |
231 | childPrim.ZeroMotion(); | 187 | childPrim.ZeroMotion(); |
232 | 188 | ||
@@ -237,22 +193,23 @@ public class BSLinksetConstraints : BSLinkset | |||
237 | // real world coordinate of midpoint between the two objects | 193 | // real world coordinate of midpoint between the two objects |
238 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | 194 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); |
239 | 195 | ||
240 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 196 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", |
241 | rootPrim.LocalID, | 197 | rootPrim.LocalID, |
242 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), | 198 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), |
243 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"), | 199 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), |
244 | rootPrim.Position, childPrim.Position, midPoint); | 200 | rootPrim.Position, childPrim.Position, midPoint); |
245 | 201 | ||
246 | // create a constraint that allows no freedom of movement between the two objects | 202 | // create a constraint that allows no freedom of movement between the two objects |
247 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 203 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
248 | 204 | ||
249 | BS6DofConstraint constrain = new BS6DofConstraint( | 205 | BSConstraint6Dof constrain = new BSConstraint6Dof( |
250 | PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true ); | 206 | PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true ); |
207 | // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true ); | ||
251 | 208 | ||
252 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 209 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
253 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | 210 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms |
254 | * of the objects. | 211 | * of the objects. |
255 | * Code left as a warning to future programmers. | 212 | * Code left for future programmers. |
256 | // ================================================================================== | 213 | // ================================================================================== |
257 | // relative position normalized to the root prim | 214 | // relative position normalized to the root prim |
258 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | 215 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); |
@@ -262,20 +219,13 @@ public class BSLinksetConstraints : BSLinkset | |||
262 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | 219 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; |
263 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | 220 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); |
264 | 221 | ||
265 | // create a constraint that allows no freedom of movement between the two objects | 222 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
266 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
267 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
268 | BS6DofConstraint constrain = new BS6DofConstraint( | 223 | BS6DofConstraint constrain = new BS6DofConstraint( |
269 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | 224 | PhysicsScene.World, rootPrim.Body, childPrim.Body, |
270 | OMV.Vector3.Zero, | 225 | OMV.Vector3.Zero, |
271 | OMV.Quaternion.Inverse(rootPrim.Orientation), | 226 | OMV.Quaternion.Inverse(rootPrim.Orientation), |
272 | OMV.Vector3.Zero, | 227 | OMV.Vector3.Zero, |
273 | OMV.Quaternion.Inverse(childPrim.Orientation), | 228 | OMV.Quaternion.Inverse(childPrim.Orientation), |
274 | // A point half way between the parent and child | ||
275 | // childRelativePosition/2, | ||
276 | // childRelativeRotation, | ||
277 | // childRelativePosition/2, | ||
278 | // inverseChildRelativeRotation, | ||
279 | true, | 229 | true, |
280 | true | 230 | true |
281 | ); | 231 | ); |
@@ -298,25 +248,26 @@ public class BSLinksetConstraints : BSLinkset | |||
298 | { | 248 | { |
299 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | 249 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); |
300 | } | 250 | } |
251 | return constrain; | ||
301 | } | 252 | } |
302 | 253 | ||
303 | // Remove linkage between myself and a particular child | 254 | // Remove linkage between the linkset root and a particular child |
304 | // The root and child bodies are passed in because we need to remove the constraint between | 255 | // The root and child bodies are passed in because we need to remove the constraint between |
305 | // the bodies that were at unlink time. | 256 | // the bodies that were present at unlink time. |
306 | // Called at taint time! | 257 | // Called at taint time! |
307 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) | 258 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
308 | { | 259 | { |
309 | bool ret = false; | 260 | bool ret = false; |
310 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 261 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", |
311 | rootPrim.LocalID, | 262 | rootPrim.LocalID, |
312 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), | 263 | rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), |
313 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X")); | 264 | childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); |
314 | 265 | ||
315 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 266 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
316 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody)) | 267 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) |
317 | { | 268 | { |
318 | // Make the child refresh its location | 269 | // Make the child refresh its location |
319 | BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); | 270 | BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); |
320 | ret = true; | 271 | ret = true; |
321 | } | 272 | } |
322 | 273 | ||
@@ -324,62 +275,53 @@ public class BSLinksetConstraints : BSLinkset | |||
324 | } | 275 | } |
325 | 276 | ||
326 | // Remove linkage between myself and any possible children I might have. | 277 | // Remove linkage between myself and any possible children I might have. |
278 | // Returns 'true' of any constraints were destroyed. | ||
327 | // Called at taint time! | 279 | // Called at taint time! |
328 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | 280 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) |
329 | { | 281 | { |
330 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 282 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
331 | bool ret = false; | ||
332 | 283 | ||
333 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody)) | 284 | return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); |
334 | { | ||
335 | ret = true; | ||
336 | } | ||
337 | return ret; | ||
338 | } | 285 | } |
339 | 286 | ||
340 | // Call each of the constraints that make up this linkset and recompute the | 287 | // Call each of the constraints that make up this linkset and recompute the |
341 | // various transforms and variables. Used when objects are added or removed | 288 | // various transforms and variables. Create constraints of not created yet. |
342 | // from a linkset to make sure the constraints know about the new mass and | 289 | // Called before the simulation step to make sure the constraint based linkset |
343 | // geometry. | 290 | // is all initialized. |
344 | // Must only be called at taint time!! | 291 | // Called at taint time!! |
345 | private void RecomputeLinksetConstraintVariables() | 292 | private void RecomputeLinksetConstraints() |
346 | { | 293 | { |
347 | float linksetMass = LinksetMass; | 294 | float linksetMass = LinksetMass; |
348 | foreach (BSPhysObject child in m_taintChildren) | 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) | ||
349 | { | 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 | |||
350 | BSConstraint constrain; | 310 | BSConstraint constrain; |
351 | if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain)) | 311 | if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) |
352 | { | ||
353 | // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", | ||
354 | // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); | ||
355 | constrain.RecomputeConstraintVariables(linksetMass); | ||
356 | } | ||
357 | else | ||
358 | { | 312 | { |
359 | // Non-fatal error that happens when children are being added to the linkset but | 313 | // If constraint doesn't exist yet, create it. |
360 | // their constraints have not been created yet. | 314 | constrain = BuildConstraint(LinksetRoot, child); |
361 | break; | ||
362 | } | 315 | } |
363 | } | 316 | constrain.RecomputeConstraintVariables(linksetMass); |
364 | 317 | ||
365 | // If the whole linkset is not here, doesn't make sense to recompute linkset wide values | 318 | // DEBUG: see of inter-linkset collisions are causing problems |
366 | if (m_children.Count == m_taintChildren.Count) | 319 | // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr, |
367 | { | 320 | // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); |
368 | // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass | ||
369 | OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); | ||
370 | BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, | ||
371 | centerOfMass, OMV.Quaternion.Identity); | ||
372 | DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}", | ||
373 | LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X")); | ||
374 | foreach (BSPhysObject child in m_taintChildren) | ||
375 | { | ||
376 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, | ||
377 | centerOfMass, OMV.Quaternion.Identity); | ||
378 | } | ||
379 | 321 | ||
380 | // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG | 322 | // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG |
381 | } | 323 | } |
382 | return; | 324 | |
383 | } | 325 | } |
384 | } | 326 | } |
385 | } | 327 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 538f905..7127aaf 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -63,12 +63,14 @@ public abstract class BSPhysObject : PhysicsActor | |||
63 | public BSLinkset Linkset { get; set; } | 63 | public BSLinkset Linkset { get; set; } |
64 | 64 | ||
65 | // Return the object mass without calculating it or having side effects | 65 | // Return the object mass without calculating it or having side effects |
66 | public abstract float MassRaw { get; } | 66 | public abstract float RawMass { get; } |
67 | // Set the raw mass but also update physical mass properties (inertia, ...) | ||
68 | public abstract void UpdatePhysicalMassProperties(float mass); | ||
67 | 69 | ||
68 | // Reference to the physical body (btCollisionObject) of this object | 70 | // Reference to the physical body (btCollisionObject) of this object |
69 | public BulletBody BSBody; | 71 | public BulletBody PhysBody; |
70 | // Reference to the physical shape (btCollisionShape) of this object | 72 | // Reference to the physical shape (btCollisionShape) of this object |
71 | public BulletShape BSShape; | 73 | public BulletShape PhysShape; |
72 | 74 | ||
73 | // 'true' if the mesh's underlying asset failed to build. | 75 | // 'true' if the mesh's underlying asset failed to build. |
74 | // This will keep us from looping after the first time the build failed. | 76 | // This will keep us from looping after the first time the build failed. |
@@ -76,6 +78,12 @@ public abstract class BSPhysObject : PhysicsActor | |||
76 | 78 | ||
77 | // The objects base shape information. Null if not a prim type shape. | 79 | // The objects base shape information. Null if not a prim type shape. |
78 | public PrimitiveBaseShape BaseShape { get; protected set; } | 80 | public PrimitiveBaseShape BaseShape { get; protected set; } |
81 | // Some types of objects have preferred physical representations. | ||
82 | // Returns SHAPE_UNKNOWN if there is no preference. | ||
83 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape | ||
84 | { | ||
85 | get { return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; } | ||
86 | } | ||
79 | 87 | ||
80 | // When the physical properties are updated, an EntityProperty holds the update values. | 88 | // When the physical properties are updated, an EntityProperty holds the update values. |
81 | // Keep the current and last EntityProperties to enable computation of differences | 89 | // Keep the current and last EntityProperties to enable computation of differences |
@@ -99,8 +107,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
99 | // Tell the object to clean up. | 107 | // Tell the object to clean up. |
100 | public abstract void Destroy(); | 108 | public abstract void Destroy(); |
101 | 109 | ||
110 | public abstract OMV.Vector3 RawPosition { get; set; } | ||
102 | public abstract OMV.Vector3 ForcePosition { get; set; } | 111 | public abstract OMV.Vector3 ForcePosition { get; set; } |
103 | 112 | ||
113 | public abstract OMV.Quaternion RawOrientation { get; set; } | ||
104 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 114 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
105 | 115 | ||
106 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 116 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
@@ -204,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
204 | 214 | ||
205 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 215 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
206 | { | 216 | { |
207 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 217 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
208 | }); | 218 | }); |
209 | } | 219 | } |
210 | else | 220 | else |
@@ -218,7 +228,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
218 | SubscribedEventsMs = 0; | 228 | SubscribedEventsMs = 0; |
219 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 229 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
220 | { | 230 | { |
221 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 231 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
222 | }); | 232 | }); |
223 | } | 233 | } |
224 | // Return 'true' if the simulator wants collision events | 234 | // Return 'true' if the simulator wants collision events |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 38ab3de..aaa0d93 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -111,8 +111,8 @@ public sealed class BSPrim : BSPhysObject | |||
111 | _mass = CalculateMass(); | 111 | _mass = CalculateMass(); |
112 | 112 | ||
113 | // No body or shape yet | 113 | // No body or shape yet |
114 | BSBody = new BulletBody(LocalID, IntPtr.Zero); | 114 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); |
115 | BSShape = new BulletShape(IntPtr.Zero); | 115 | PhysShape = new BulletShape(IntPtr.Zero); |
116 | 116 | ||
117 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 117 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
118 | // do the actual object creation at taint time | 118 | // do the actual object creation at taint time |
@@ -120,7 +120,7 @@ public sealed class BSPrim : BSPhysObject | |||
120 | { | 120 | { |
121 | CreateGeomAndObject(true); | 121 | CreateGeomAndObject(true); |
122 | 122 | ||
123 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr); | 123 | CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); |
124 | }); | 124 | }); |
125 | } | 125 | } |
126 | 126 | ||
@@ -145,8 +145,8 @@ public sealed class BSPrim : BSPhysObject | |||
145 | { | 145 | { |
146 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 146 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
147 | // If there are physical body and shape, release my use of same. | 147 | // If there are physical body and shape, release my use of same. |
148 | PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); | 148 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
149 | PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); | 149 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
150 | }); | 150 | }); |
151 | } | 151 | } |
152 | 152 | ||
@@ -171,18 +171,18 @@ public sealed class BSPrim : BSPhysObject | |||
171 | ForceBodyShapeRebuild(false); | 171 | ForceBodyShapeRebuild(false); |
172 | } | 172 | } |
173 | } | 173 | } |
174 | // Whatever the linkset wants is what I want. | ||
175 | public override ShapeData.PhysicsShapeType PreferredPhysicalShape | ||
176 | { get { return Linkset.PreferredPhysicalShape(this); } } | ||
177 | |||
174 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | 178 | public override bool ForceBodyShapeRebuild(bool inTaintTime) |
175 | { | 179 | { |
176 | LastAssetBuildFailed = false; | 180 | LastAssetBuildFailed = false; |
177 | BSScene.TaintCallback rebuildOperation = delegate() | 181 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate() |
178 | { | 182 | { |
179 | _mass = CalculateMass(); // changing the shape changes the mass | 183 | _mass = CalculateMass(); // changing the shape changes the mass |
180 | CreateGeomAndObject(true); | 184 | CreateGeomAndObject(true); |
181 | }; | 185 | }); |
182 | if (inTaintTime) | ||
183 | rebuildOperation(); | ||
184 | else | ||
185 | PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation); | ||
186 | return true; | 186 | return true; |
187 | } | 187 | } |
188 | public override bool Grabbed { | 188 | public override bool Grabbed { |
@@ -242,8 +242,8 @@ public sealed class BSPrim : BSPhysObject | |||
242 | _acceleration = OMV.Vector3.Zero; | 242 | _acceleration = OMV.Vector3.Zero; |
243 | _rotationalVelocity = OMV.Vector3.Zero; | 243 | _rotationalVelocity = OMV.Vector3.Zero; |
244 | 244 | ||
245 | // Zero some other properties directly into the physics engine | 245 | // Zero some other properties in the physics engine |
246 | BulletSimAPI.ClearForces2(BSBody.ptr); | 246 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); |
247 | } | 247 | } |
248 | 248 | ||
249 | public override void LockAngularMotion(OMV.Vector3 axis) | 249 | public override void LockAngularMotion(OMV.Vector3 axis) |
@@ -252,11 +252,16 @@ public sealed class BSPrim : BSPhysObject | |||
252 | return; | 252 | return; |
253 | } | 253 | } |
254 | 254 | ||
255 | public override OMV.Vector3 RawPosition | ||
256 | { | ||
257 | get { return _position; } | ||
258 | set { _position = value; } | ||
259 | } | ||
255 | public override OMV.Vector3 Position { | 260 | public override OMV.Vector3 Position { |
256 | get { | 261 | get { |
262 | // child prims move around based on their parent. Need to get the latest location | ||
257 | if (!Linkset.IsRoot(this)) | 263 | if (!Linkset.IsRoot(this)) |
258 | // child prims move around based on their parent. Need to get the latest location | 264 | _position = Linkset.Position(this); |
259 | _position = BulletSimAPI.GetPosition2(BSBody.ptr); | ||
260 | 265 | ||
261 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | 266 | // don't do the GetObjectPosition for root elements because this function is called a zillion times |
262 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 267 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
@@ -274,19 +279,21 @@ public sealed class BSPrim : BSPhysObject | |||
274 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 279 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
275 | { | 280 | { |
276 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 281 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
277 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 282 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
283 | ActivateIfPhysical(false); | ||
278 | }); | 284 | }); |
279 | } | 285 | } |
280 | } | 286 | } |
281 | public override OMV.Vector3 ForcePosition { | 287 | public override OMV.Vector3 ForcePosition { |
282 | get { | 288 | get { |
283 | _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 289 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); |
284 | return _position; | 290 | return _position; |
285 | } | 291 | } |
286 | set { | 292 | set { |
287 | _position = value; | 293 | _position = value; |
288 | PositionSanityCheck(); | 294 | PositionSanityCheck(); |
289 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 295 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
296 | ActivateIfPhysical(false); | ||
290 | } | 297 | } |
291 | } | 298 | } |
292 | 299 | ||
@@ -311,6 +318,7 @@ public sealed class BSPrim : BSPhysObject | |||
311 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 318 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
312 | { | 319 | { |
313 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 320 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); |
321 | // TODO: a floating motor so object will bob in the water | ||
314 | if (Position.Z < waterHeight) | 322 | if (Position.Z < waterHeight) |
315 | { | 323 | { |
316 | _position.Z = waterHeight; | 324 | _position.Z = waterHeight; |
@@ -332,16 +340,11 @@ public sealed class BSPrim : BSPhysObject | |||
332 | { | 340 | { |
333 | // The new position value must be pushed into the physics engine but we can't | 341 | // The new position value must be pushed into the physics engine but we can't |
334 | // just assign to "Position" because of potential call loops. | 342 | // just assign to "Position" because of potential call loops. |
335 | BSScene.TaintCallback sanityOperation = delegate() | 343 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck", delegate() |
336 | { | 344 | { |
337 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 345 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
338 | ForcePosition = _position; | 346 | ForcePosition = _position; |
339 | }; | 347 | }); |
340 | if (inTaintTime) | ||
341 | sanityOperation(); | ||
342 | else | ||
343 | PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); | ||
344 | |||
345 | ret = true; | 348 | ret = true; |
346 | } | 349 | } |
347 | return ret; | 350 | return ret; |
@@ -353,13 +356,34 @@ public sealed class BSPrim : BSPhysObject | |||
353 | { | 356 | { |
354 | get | 357 | get |
355 | { | 358 | { |
356 | // return Linkset.LinksetMass; | 359 | return Linkset.LinksetMass; |
357 | return _mass; | 360 | // return _mass; |
358 | } | 361 | } |
359 | } | 362 | } |
360 | 363 | ||
361 | // used when we only want this prim's mass and not the linkset thing | 364 | // used when we only want this prim's mass and not the linkset thing |
362 | public override float MassRaw { get { return _mass; } } | 365 | public override float RawMass { |
366 | get { return _mass; } | ||
367 | } | ||
368 | // Set the physical mass to the passed mass. | ||
369 | // Note that this does not change _mass! | ||
370 | public override void UpdatePhysicalMassProperties(float physMass) | ||
371 | { | ||
372 | if (IsStatic) | ||
373 | { | ||
374 | BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, OMV.Vector3.Zero); | ||
375 | BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
380 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
381 | // center of mass is at the zero of the object | ||
382 | BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); | ||
383 | // BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | ||
384 | DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, localInertia); | ||
385 | } | ||
386 | } | ||
363 | 387 | ||
364 | // Is this used? | 388 | // Is this used? |
365 | public override OMV.Vector3 CenterOfMass | 389 | public override OMV.Vector3 CenterOfMass |
@@ -380,7 +404,7 @@ public sealed class BSPrim : BSPhysObject | |||
380 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 404 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |
381 | { | 405 | { |
382 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 406 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
383 | BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); | 407 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); |
384 | }); | 408 | }); |
385 | } | 409 | } |
386 | } | 410 | } |
@@ -400,6 +424,7 @@ public sealed class BSPrim : BSPhysObject | |||
400 | // Done at taint time so we're sure the physics engine is not using the variables | 424 | // Done at taint time so we're sure the physics engine is not using the variables |
401 | // Vehicle code changes the parameters for this vehicle type. | 425 | // Vehicle code changes the parameters for this vehicle type. |
402 | _vehicle.ProcessTypeChange(type); | 426 | _vehicle.ProcessTypeChange(type); |
427 | ActivateIfPhysical(false); | ||
403 | }); | 428 | }); |
404 | } | 429 | } |
405 | } | 430 | } |
@@ -408,6 +433,7 @@ public sealed class BSPrim : BSPhysObject | |||
408 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() | 433 | PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate() |
409 | { | 434 | { |
410 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 435 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); |
436 | ActivateIfPhysical(false); | ||
411 | }); | 437 | }); |
412 | } | 438 | } |
413 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 439 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
@@ -415,6 +441,7 @@ public sealed class BSPrim : BSPhysObject | |||
415 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() | 441 | PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate() |
416 | { | 442 | { |
417 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 443 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); |
444 | ActivateIfPhysical(false); | ||
418 | }); | 445 | }); |
419 | } | 446 | } |
420 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 447 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
@@ -422,6 +449,7 @@ public sealed class BSPrim : BSPhysObject | |||
422 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() | 449 | PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate() |
423 | { | 450 | { |
424 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 451 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); |
452 | ActivateIfPhysical(false); | ||
425 | }); | 453 | }); |
426 | } | 454 | } |
427 | public override void VehicleFlags(int param, bool remove) | 455 | public override void VehicleFlags(int param, bool remove) |
@@ -436,9 +464,16 @@ public sealed class BSPrim : BSPhysObject | |||
436 | // Called from Scene when doing simulation step so we're in taint processing time. | 464 | // Called from Scene when doing simulation step so we're in taint processing time. |
437 | public override void StepVehicle(float timeStep) | 465 | public override void StepVehicle(float timeStep) |
438 | { | 466 | { |
439 | if (IsPhysical) | 467 | if (IsPhysical && _vehicle.IsActive) |
440 | { | 468 | { |
441 | _vehicle.Step(timeStep); | 469 | _vehicle.Step(timeStep); |
470 | /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step | ||
471 | PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate() | ||
472 | { | ||
473 | // This resets the interpolation values and recomputes the tensor variables | ||
474 | BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation); | ||
475 | }); | ||
476 | */ | ||
442 | } | 477 | } |
443 | } | 478 | } |
444 | 479 | ||
@@ -463,7 +498,7 @@ public sealed class BSPrim : BSPhysObject | |||
463 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 498 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
464 | { | 499 | { |
465 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 500 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
466 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); | 501 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |
467 | }); | 502 | }); |
468 | } | 503 | } |
469 | } | 504 | } |
@@ -471,12 +506,14 @@ public sealed class BSPrim : BSPhysObject | |||
471 | get { return _velocity; } | 506 | get { return _velocity; } |
472 | set { | 507 | set { |
473 | _velocity = value; | 508 | _velocity = value; |
474 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); | 509 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); |
475 | } | 510 | } |
476 | } | 511 | } |
477 | public override OMV.Vector3 Torque { | 512 | public override OMV.Vector3 Torque { |
478 | get { return _torque; } | 513 | get { return _torque; } |
479 | set { _torque = value; | 514 | set { |
515 | _torque = value; | ||
516 | AddAngularForce(_torque, false, false); | ||
480 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); | 517 | // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); |
481 | } | 518 | } |
482 | } | 519 | } |
@@ -489,12 +526,17 @@ public sealed class BSPrim : BSPhysObject | |||
489 | get { return _acceleration; } | 526 | get { return _acceleration; } |
490 | set { _acceleration = value; } | 527 | set { _acceleration = value; } |
491 | } | 528 | } |
529 | public override OMV.Quaternion RawOrientation | ||
530 | { | ||
531 | get { return _orientation; } | ||
532 | set { _orientation = value; } | ||
533 | } | ||
492 | public override OMV.Quaternion Orientation { | 534 | public override OMV.Quaternion Orientation { |
493 | get { | 535 | get { |
536 | // Children move around because tied to parent. Get a fresh value. | ||
494 | if (!Linkset.IsRoot(this)) | 537 | if (!Linkset.IsRoot(this)) |
495 | { | 538 | { |
496 | // Children move around because tied to parent. Get a fresh value. | 539 | _orientation = Linkset.Orientation(this); |
497 | _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); | ||
498 | } | 540 | } |
499 | return _orientation; | 541 | return _orientation; |
500 | } | 542 | } |
@@ -507,7 +549,7 @@ public sealed class BSPrim : BSPhysObject | |||
507 | { | 549 | { |
508 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 550 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
509 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 551 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
510 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 552 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
511 | }); | 553 | }); |
512 | } | 554 | } |
513 | } | 555 | } |
@@ -516,13 +558,13 @@ public sealed class BSPrim : BSPhysObject | |||
516 | { | 558 | { |
517 | get | 559 | get |
518 | { | 560 | { |
519 | _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr); | 561 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); |
520 | return _orientation; | 562 | return _orientation; |
521 | } | 563 | } |
522 | set | 564 | set |
523 | { | 565 | { |
524 | _orientation = value; | 566 | _orientation = value; |
525 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 567 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
526 | } | 568 | } |
527 | } | 569 | } |
528 | public override int PhysicsActorType { | 570 | public override int PhysicsActorType { |
@@ -539,6 +581,8 @@ public sealed class BSPrim : BSPhysObject | |||
539 | { | 581 | { |
540 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); | 582 | // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); |
541 | SetObjectDynamic(true); | 583 | SetObjectDynamic(true); |
584 | // whether phys-to-static or static-to-phys, the object is not moving. | ||
585 | ZeroMotion(); | ||
542 | }); | 586 | }); |
543 | } | 587 | } |
544 | } | 588 | } |
@@ -576,7 +620,7 @@ public sealed class BSPrim : BSPhysObject | |||
576 | 620 | ||
577 | // Mangling all the physical properties requires the object not be in the physical world. | 621 | // Mangling all the physical properties requires the object not be in the physical world. |
578 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). | 622 | // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). |
579 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); | 623 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
580 | 624 | ||
581 | // Set up the object physicalness (does gravity and collisions move this object) | 625 | // Set up the object physicalness (does gravity and collisions move this object) |
582 | MakeDynamic(IsStatic); | 626 | MakeDynamic(IsStatic); |
@@ -590,24 +634,24 @@ public sealed class BSPrim : BSPhysObject | |||
590 | // Make solid or not (do things bounce off or pass through this object). | 634 | // Make solid or not (do things bounce off or pass through this object). |
591 | MakeSolid(IsSolid); | 635 | MakeSolid(IsSolid); |
592 | 636 | ||
593 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); | 637 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); |
594 | 638 | ||
595 | // Rebuild its shape | 639 | // Rebuild its shape |
596 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); | 640 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
597 | 641 | ||
598 | // Collision filter can be set only when the object is in the world | 642 | // Collision filter can be set only when the object is in the world |
599 | if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0) | 643 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) |
600 | { | 644 | { |
601 | BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask); | 645 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); |
602 | } | 646 | } |
603 | 647 | ||
604 | // Recompute any linkset parameters. | 648 | // Recompute any linkset parameters. |
605 | // When going from non-physical to physical, this re-enables the constraints that | 649 | // When going from non-physical to physical, this re-enables the constraints that |
606 | // had been automatically disabled when the mass was set to zero. | 650 | // had been automatically disabled when the mass was set to zero. |
607 | Linkset.Refresh(this, true); | 651 | Linkset.Refresh(this); |
608 | 652 | ||
609 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | 653 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", |
610 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); | 654 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); |
611 | } | 655 | } |
612 | 656 | ||
613 | // "Making dynamic" means changing to and from static. | 657 | // "Making dynamic" means changing to and from static. |
@@ -620,75 +664,74 @@ public sealed class BSPrim : BSPhysObject | |||
620 | if (makeStatic) | 664 | if (makeStatic) |
621 | { | 665 | { |
622 | // Become a Bullet 'static' object type | 666 | // Become a Bullet 'static' object type |
623 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 667 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
624 | // Stop all movement | 668 | // Stop all movement |
625 | BulletSimAPI.ClearAllForces2(BSBody.ptr); | 669 | ZeroMotion(); |
626 | // Center of mass is at the center of the object | 670 | // Center of mass is at the center of the object |
627 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation); | 671 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); |
628 | // Mass is zero which disables a bunch of physics stuff in Bullet | 672 | // Mass is zero which disables a bunch of physics stuff in Bullet |
629 | BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); | 673 | UpdatePhysicalMassProperties(0f); |
630 | // There is no inertia in a static object | ||
631 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | ||
632 | // Set collision detection parameters | 674 | // Set collision detection parameters |
633 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 675 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) |
634 | { | 676 | { |
635 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 677 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |
636 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 678 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |
637 | } | 679 | } |
638 | // There can be special things needed for implementing linksets | 680 | // There can be special things needed for implementing linksets |
639 | Linkset.MakeStatic(this); | 681 | Linkset.MakeStatic(this); |
640 | // The activation state is 'disabled' so Bullet will not try to act on it. | 682 | // The activation state is 'disabled' so Bullet will not try to act on it. |
641 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); | 683 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
642 | // Start it out sleeping and physical actions could wake it up. | 684 | // Start it out sleeping and physical actions could wake it up. |
643 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 685 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); |
644 | 686 | ||
645 | BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 687 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; |
646 | BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 688 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; |
647 | } | 689 | } |
648 | else | 690 | else |
649 | { | 691 | { |
650 | // Not a Bullet static object | 692 | // Not a Bullet static object |
651 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 693 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
652 | 694 | ||
653 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | 695 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set |
654 | BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction); | 696 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); |
655 | BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution); | 697 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); |
656 | 698 | ||
657 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 699 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
658 | BulletSimAPI.ClearAllForces2(BSBody.ptr); | 700 | // Since this can be called multiple times, only zero forces when becoming physical |
701 | // BulletSimAPI.ClearAllForces2(BSBody.ptr); | ||
659 | 702 | ||
660 | // For good measure, make sure the transform is set through to the motion state | 703 | // For good measure, make sure the transform is set through to the motion state |
661 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | 704 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
705 | |||
706 | // Center of mass is at the center of the object | ||
707 | BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | ||
662 | 708 | ||
663 | // A dynamic object has mass | 709 | // A dynamic object has mass |
664 | IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); | 710 | UpdatePhysicalMassProperties(RawMass); |
665 | OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); | ||
666 | BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); | ||
667 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | ||
668 | 711 | ||
669 | // Set collision detection parameters | 712 | // Set collision detection parameters |
670 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | 713 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) |
671 | { | 714 | { |
672 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 715 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |
673 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 716 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |
674 | } | 717 | } |
675 | 718 | ||
676 | // Various values for simulation limits | 719 | // Various values for simulation limits |
677 | BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | 720 | BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); |
678 | BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); | 721 | BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); |
679 | BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 722 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |
680 | BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 723 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |
681 | 724 | ||
682 | // There might be special things needed for implementing linksets. | 725 | // There might be special things needed for implementing linksets. |
683 | Linkset.MakeDynamic(this); | 726 | Linkset.MakeDynamic(this); |
684 | 727 | ||
685 | // Force activation of the object so Bullet will act on it. | 728 | // Force activation of the object so Bullet will act on it. |
686 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 729 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
687 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | 730 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); |
688 | // BulletSimAPI.Activate2(BSBody.ptr, true); | 731 | // BulletSimAPI.Activate2(BSBody.ptr, true); |
689 | 732 | ||
690 | BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 733 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; |
691 | BSBody.collisionMask = CollisionFilterGroups.ObjectMask; | 734 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; |
692 | } | 735 | } |
693 | } | 736 | } |
694 | 737 | ||
@@ -698,7 +741,7 @@ public sealed class BSPrim : BSPhysObject | |||
698 | // the functions after this one set up the state of a possibly newly created collision body. | 741 | // the functions after this one set up the state of a possibly newly created collision body. |
699 | private void MakeSolid(bool makeSolid) | 742 | private void MakeSolid(bool makeSolid) |
700 | { | 743 | { |
701 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr); | 744 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); |
702 | if (makeSolid) | 745 | if (makeSolid) |
703 | { | 746 | { |
704 | // Verify the previous code created the correct shape for this type of thing. | 747 | // Verify the previous code created the correct shape for this type of thing. |
@@ -706,7 +749,7 @@ public sealed class BSPrim : BSPhysObject | |||
706 | { | 749 | { |
707 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); | 750 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); |
708 | } | 751 | } |
709 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 752 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
710 | } | 753 | } |
711 | else | 754 | else |
712 | { | 755 | { |
@@ -714,22 +757,31 @@ public sealed class BSPrim : BSPhysObject | |||
714 | { | 757 | { |
715 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 758 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
716 | } | 759 | } |
717 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 760 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
718 | BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 761 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; |
719 | BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 762 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; |
720 | } | 763 | } |
721 | } | 764 | } |
722 | 765 | ||
766 | // Enable physical actions. Bullet will keep sleeping non-moving physical objects so | ||
767 | // they need waking up when parameters are changed. | ||
768 | // Called in taint-time!! | ||
769 | private void ActivateIfPhysical(bool forceIt) | ||
770 | { | ||
771 | if (IsPhysical) | ||
772 | BulletSimAPI.Activate2(PhysBody.ptr, forceIt); | ||
773 | } | ||
774 | |||
723 | // Turn on or off the flag controlling whether collision events are returned to the simulator. | 775 | // Turn on or off the flag controlling whether collision events are returned to the simulator. |
724 | private void EnableCollisions(bool wantsCollisionEvents) | 776 | private void EnableCollisions(bool wantsCollisionEvents) |
725 | { | 777 | { |
726 | if (wantsCollisionEvents) | 778 | if (wantsCollisionEvents) |
727 | { | 779 | { |
728 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 780 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
729 | } | 781 | } |
730 | else | 782 | else |
731 | { | 783 | { |
732 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 784 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
733 | } | 785 | } |
734 | } | 786 | } |
735 | 787 | ||
@@ -774,9 +826,9 @@ public sealed class BSPrim : BSPhysObject | |||
774 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() | 826 | PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() |
775 | { | 827 | { |
776 | if (_floatOnWater) | 828 | if (_floatOnWater) |
777 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 829 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
778 | else | 830 | else |
779 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 831 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
780 | }); | 832 | }); |
781 | } | 833 | } |
782 | } | 834 | } |
@@ -798,8 +850,8 @@ public sealed class BSPrim : BSPhysObject | |||
798 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 850 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
799 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 851 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
800 | { | 852 | { |
801 | // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 853 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
802 | BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); | 854 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |
803 | }); | 855 | }); |
804 | } | 856 | } |
805 | } | 857 | } |
@@ -809,7 +861,7 @@ public sealed class BSPrim : BSPhysObject | |||
809 | } | 861 | } |
810 | set { | 862 | set { |
811 | _rotationalVelocity = value; | 863 | _rotationalVelocity = value; |
812 | BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); | 864 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |
813 | } | 865 | } |
814 | } | 866 | } |
815 | public override bool Kinematic { | 867 | public override bool Kinematic { |
@@ -835,7 +887,7 @@ public sealed class BSPrim : BSPhysObject | |||
835 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 887 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
836 | // Buoyancy is faked by changing the gravity applied to the object | 888 | // Buoyancy is faked by changing the gravity applied to the object |
837 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 889 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
838 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 890 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); |
839 | } | 891 | } |
840 | } | 892 | } |
841 | 893 | ||
@@ -888,7 +940,7 @@ public sealed class BSPrim : BSPhysObject | |||
888 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 940 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
889 | return; | 941 | return; |
890 | } | 942 | } |
891 | BSScene.TaintCallback addForceOperation = delegate() | 943 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate() |
892 | { | 944 | { |
893 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 945 | OMV.Vector3 fSum = OMV.Vector3.Zero; |
894 | lock (m_accumulatedForces) | 946 | lock (m_accumulatedForces) |
@@ -900,20 +952,60 @@ public sealed class BSPrim : BSPhysObject | |||
900 | } | 952 | } |
901 | m_accumulatedForces.Clear(); | 953 | m_accumulatedForces.Clear(); |
902 | } | 954 | } |
903 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); | 955 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); |
904 | // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. | 956 | if (fSum != OMV.Vector3.Zero) |
905 | BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); | 957 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); |
906 | }; | 958 | }); |
907 | if (inTaintTime) | ||
908 | addForceOperation(); | ||
909 | else | ||
910 | PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation); | ||
911 | } | 959 | } |
912 | 960 | ||
961 | private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>(); | ||
913 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 962 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
914 | // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); | 963 | AddAngularForce(force, pushforce, false); |
915 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | ||
916 | } | 964 | } |
965 | public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) | ||
966 | { | ||
967 | if (force.IsFinite()) | ||
968 | { | ||
969 | // _force += force; | ||
970 | lock (m_accumulatedAngularForces) | ||
971 | m_accumulatedAngularForces.Add(new OMV.Vector3(force)); | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | ||
976 | return; | ||
977 | } | ||
978 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate() | ||
979 | { | ||
980 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
981 | lock (m_accumulatedAngularForces) | ||
982 | { | ||
983 | // Sum the accumulated additional forces for one big force to apply once. | ||
984 | foreach (OMV.Vector3 v in m_accumulatedAngularForces) | ||
985 | { | ||
986 | fSum += v; | ||
987 | } | ||
988 | m_accumulatedAngularForces.Clear(); | ||
989 | } | ||
990 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | ||
991 | if (fSum != OMV.Vector3.Zero) | ||
992 | { | ||
993 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | ||
994 | _torque = fSum; | ||
995 | } | ||
996 | }); | ||
997 | } | ||
998 | // A torque impulse. | ||
999 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | ||
1000 | { | ||
1001 | OMV.Vector3 applyImpulse = impulse; | ||
1002 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | ||
1003 | { | ||
1004 | DetailLog("{0},BSPrim.ApplyTorqueImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | ||
1005 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1006 | }); | ||
1007 | } | ||
1008 | |||
917 | public override void SetMomentum(OMV.Vector3 momentum) { | 1009 | public override void SetMomentum(OMV.Vector3 momentum) { |
918 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); | 1010 | // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); |
919 | } | 1011 | } |
@@ -1195,9 +1287,7 @@ public sealed class BSPrim : BSPhysObject | |||
1195 | 1287 | ||
1196 | returnMass = _density * volume; | 1288 | returnMass = _density * volume; |
1197 | 1289 | ||
1198 | /* | 1290 | /* Comment out code that computes the mass of the linkset. That is done in the Linkset class. |
1199 | * This change means each object keeps its own mass and the Mass property | ||
1200 | * will return the sum if we're part of a linkset. | ||
1201 | if (IsRootOfLinkset) | 1291 | if (IsRootOfLinkset) |
1202 | { | 1292 | { |
1203 | foreach (BSPrim prim in _childrenPrims) | 1293 | foreach (BSPrim prim in _childrenPrims) |
@@ -1217,34 +1307,11 @@ public sealed class BSPrim : BSPhysObject | |||
1217 | }// end CalculateMass | 1307 | }// end CalculateMass |
1218 | #endregion Mass Calculation | 1308 | #endregion Mass Calculation |
1219 | 1309 | ||
1220 | // Copy prim's info into the BulletSim shape description structure | ||
1221 | public void FillShapeInfo(out ShapeData shape) | ||
1222 | { | ||
1223 | shape.ID = LocalID; | ||
1224 | shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
1225 | shape.Position = _position; | ||
1226 | shape.Rotation = _orientation; | ||
1227 | shape.Velocity = _velocity; | ||
1228 | shape.Size = _size; | ||
1229 | shape.Scale = Scale; | ||
1230 | shape.Mass = _isPhysical ? _mass : 0f; | ||
1231 | shape.Buoyancy = _buoyancy; | ||
1232 | shape.HullKey = 0; | ||
1233 | shape.MeshKey = 0; | ||
1234 | shape.Friction = _friction; | ||
1235 | shape.Restitution = _restitution; | ||
1236 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | ||
1237 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1238 | shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; | ||
1239 | } | ||
1240 | // Rebuild the geometry and object. | 1310 | // Rebuild the geometry and object. |
1241 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1311 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1242 | // Called at taint-time!!! | 1312 | // Called at taint-time!!! |
1243 | private void CreateGeomAndObject(bool forceRebuild) | 1313 | private void CreateGeomAndObject(bool forceRebuild) |
1244 | { | 1314 | { |
1245 | ShapeData shapeData; | ||
1246 | FillShapeInfo(out shapeData); | ||
1247 | |||
1248 | // If this prim is part of a linkset, we must remove and restore the physical | 1315 | // If this prim is part of a linkset, we must remove and restore the physical |
1249 | // links if the body is rebuilt. | 1316 | // links if the body is rebuilt. |
1250 | bool needToRestoreLinkset = false; | 1317 | bool needToRestoreLinkset = false; |
@@ -1253,8 +1320,7 @@ public sealed class BSPrim : BSPhysObject | |||
1253 | // Updates BSBody and BSShape with the new information. | 1320 | // Updates BSBody and BSShape with the new information. |
1254 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1321 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1255 | // Returns 'true' if either the body or the shape was changed. | 1322 | // Returns 'true' if either the body or the shape was changed. |
1256 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, | 1323 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1257 | null, delegate(BulletBody dBody) | ||
1258 | { | 1324 | { |
1259 | // Called if the current prim body is about to be destroyed. | 1325 | // Called if the current prim body is about to be destroyed. |
1260 | // Remove all the physical dependencies on the old body. | 1326 | // Remove all the physical dependencies on the old body. |
@@ -1353,8 +1419,9 @@ public sealed class BSPrim : BSPhysObject | |||
1353 | 1419 | ||
1354 | PositionSanityCheck(true); | 1420 | PositionSanityCheck(true); |
1355 | 1421 | ||
1356 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1422 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; |
1357 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 1423 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1424 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | ||
1358 | 1425 | ||
1359 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | 1426 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG |
1360 | 1427 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index db0c99e..740f339 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -62,7 +62,7 @@ using OpenMetaverse; | |||
62 | // | 62 | // |
63 | namespace OpenSim.Region.Physics.BulletSPlugin | 63 | namespace OpenSim.Region.Physics.BulletSPlugin |
64 | { | 64 | { |
65 | public class BSScene : PhysicsScene, IPhysicsParameters | 65 | public 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 | ||
@@ -475,23 +486,21 @@ 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; | 494 | numTaints += _taintOperations.Count; |
484 | ProcessTaints(); // the vehicles might have added taints | 495 | ProcessTaints(); // the vehicles might have added taints |
485 | 496 | ||
486 | // step the physical world one interval | 497 | // step the physical world one interval |
487 | m_simulationStep++; | 498 | m_simulationStep++; |
488 | int numSubSteps = 0; | 499 | int numSubSteps = 0; |
489 | 500 | ||
490 | // DEBUG | ||
491 | // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep); | ||
492 | |||
493 | try | 501 | try |
494 | { | 502 | { |
503 | // DumpVehicles(); // DEBUG | ||
495 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 504 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
496 | 505 | ||
497 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 506 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
@@ -500,6 +509,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
500 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 509 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
501 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 510 | 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); | 511 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); |
512 | // DumpVehicles(); // DEBUG | ||
503 | } | 513 | } |
504 | catch (Exception e) | 514 | catch (Exception e) |
505 | { | 515 | { |
@@ -575,6 +585,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
575 | } | 585 | } |
576 | } | 586 | } |
577 | 587 | ||
588 | ProcessPostStepTaints(); | ||
589 | |||
578 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 590 | // 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. | 591 | // Only enable this in a limited test world with few objects. |
580 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 592 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG |
@@ -670,6 +682,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
670 | 682 | ||
671 | public override bool IsThreaded { get { return false; } } | 683 | public override bool IsThreaded { get { return false; } } |
672 | 684 | ||
685 | #region Taints | ||
686 | |||
673 | // Calls to the PhysicsActors can't directly call into the physics engine | 687 | // 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. | 688 | // 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. | 689 | // We rely on C#'s closure to save and restore the context for the delegate. |
@@ -679,30 +693,48 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
679 | 693 | ||
680 | lock (_taintLock) | 694 | lock (_taintLock) |
681 | { | 695 | { |
682 | _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); | 696 | _taintOperations.Add(new TaintCallbackEntry(ident, callback)); |
683 | } | 697 | } |
684 | 698 | ||
685 | return; | 699 | return; |
686 | } | 700 | } |
687 | 701 | ||
702 | // Sometimes a potentially tainted operation can be used in and out of taint time. | ||
703 | // This routine executes the command immediately if in taint-time otherwise it is queued. | ||
704 | public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback) | ||
705 | { | ||
706 | if (inTaintTime) | ||
707 | callback(); | ||
708 | else | ||
709 | TaintedObject(ident, callback); | ||
710 | } | ||
711 | |||
688 | // When someone tries to change a property on a BSPrim or BSCharacter, the object queues | 712 | // 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 | 713 | // 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. | 714 | // here just before the physics engine is called to step the simulation. |
691 | public void ProcessTaints() | 715 | public void ProcessTaints() |
692 | { | 716 | { |
693 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process | 717 | InTaintTime = true; |
718 | ProcessRegularTaints(); | ||
719 | ProcessPostTaintTaints(); | ||
720 | InTaintTime = false; | ||
721 | } | ||
722 | |||
723 | private void ProcessRegularTaints() | ||
724 | { | ||
725 | if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process | ||
694 | { | 726 | { |
695 | int taintCount = m_taintsToProcessPerStep; | 727 | int taintCount = m_taintsToProcessPerStep; |
696 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | 728 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); |
697 | while (_taintedObjects.Count > 0 && taintCount-- > 0) | 729 | while (_taintOperations.Count > 0 && taintCount-- > 0) |
698 | { | 730 | { |
699 | bool gotOne = false; | 731 | bool gotOne = false; |
700 | lock (_taintLock) | 732 | lock (_taintLock) |
701 | { | 733 | { |
702 | if (_taintedObjects.Count > 0) | 734 | if (_taintOperations.Count > 0) |
703 | { | 735 | { |
704 | oneCallback = _taintedObjects[0]; | 736 | oneCallback = _taintOperations[0]; |
705 | _taintedObjects.RemoveAt(0); | 737 | _taintOperations.RemoveAt(0); |
706 | gotOne = true; | 738 | gotOne = true; |
707 | } | 739 | } |
708 | } | 740 | } |
@@ -746,6 +778,101 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
746 | } | 778 | } |
747 | } | 779 | } |
748 | 780 | ||
781 | // Schedule an update to happen after all the regular taints are processed. | ||
782 | // Note that new requests for the same operation ("ident") for the same object ("ID") | ||
783 | // will replace any previous operation by the same object. | ||
784 | public void PostTaintObject(String ident, uint ID, TaintCallback callback) | ||
785 | { | ||
786 | if (!m_initialized) return; | ||
787 | |||
788 | string uniqueIdent = ident + "-" + ID.ToString(); | ||
789 | lock (_taintLock) | ||
790 | { | ||
791 | _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback); | ||
792 | } | ||
793 | |||
794 | return; | ||
795 | } | ||
796 | |||
797 | private void ProcessPostTaintTaints() | ||
798 | { | ||
799 | if (_postTaintOperations.Count > 0) | ||
800 | { | ||
801 | Dictionary<string, TaintCallbackEntry> oldList; | ||
802 | lock (_taintLock) | ||
803 | { | ||
804 | oldList = _postTaintOperations; | ||
805 | _postTaintOperations = new Dictionary<string, TaintCallbackEntry>(); | ||
806 | } | ||
807 | |||
808 | foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList) | ||
809 | { | ||
810 | try | ||
811 | { | ||
812 | DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG | ||
813 | kvp.Value.callback(); | ||
814 | } | ||
815 | catch (Exception e) | ||
816 | { | ||
817 | m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e); | ||
818 | } | ||
819 | } | ||
820 | oldList.Clear(); | ||
821 | } | ||
822 | } | ||
823 | |||
824 | public void PostStepTaintObject(String ident, TaintCallback callback) | ||
825 | { | ||
826 | if (!m_initialized) return; | ||
827 | |||
828 | lock (_taintLock) | ||
829 | { | ||
830 | _postStepOperations.Add(new TaintCallbackEntry(ident, callback)); | ||
831 | } | ||
832 | |||
833 | return; | ||
834 | } | ||
835 | |||
836 | private void ProcessPostStepTaints() | ||
837 | { | ||
838 | if (_postStepOperations.Count > 0) | ||
839 | { | ||
840 | List<TaintCallbackEntry> oldList; | ||
841 | lock (_taintLock) | ||
842 | { | ||
843 | oldList = _postStepOperations; | ||
844 | _postStepOperations = new List<TaintCallbackEntry>(); | ||
845 | } | ||
846 | |||
847 | foreach (TaintCallbackEntry tcbe in oldList) | ||
848 | { | ||
849 | try | ||
850 | { | ||
851 | DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
852 | tcbe.callback(); | ||
853 | } | ||
854 | catch (Exception e) | ||
855 | { | ||
856 | m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); | ||
857 | } | ||
858 | } | ||
859 | oldList.Clear(); | ||
860 | } | ||
861 | } | ||
862 | |||
863 | public bool AssertInTaintTime(string whereFrom) | ||
864 | { | ||
865 | if (!InTaintTime) | ||
866 | { | ||
867 | DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); | ||
868 | m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); | ||
869 | Util.PrintCallStack(); | ||
870 | } | ||
871 | return InTaintTime; | ||
872 | } | ||
873 | |||
874 | #endregion // Taints | ||
875 | |||
749 | #region Vehicles | 876 | #region Vehicles |
750 | 877 | ||
751 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) | 878 | public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) |
@@ -970,49 +1097,49 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
970 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | 1097 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |
971 | (s) => { return s.m_params[0].linearDamping; }, | 1098 | (s) => { return s.m_params[0].linearDamping; }, |
972 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); }, | 1099 | (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); } ), | 1100 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), |
974 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 1101 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
975 | 0f, | 1102 | 0f, |
976 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | 1103 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |
977 | (s) => { return s.m_params[0].angularDamping; }, | 1104 | (s) => { return s.m_params[0].angularDamping; }, |
978 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); }, | 1105 | (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); } ), | 1106 | (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, v); } ), |
980 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 1107 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |
981 | 0.2f, | 1108 | 0.2f, |
982 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | 1109 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |
983 | (s) => { return s.m_params[0].deactivationTime; }, | 1110 | (s) => { return s.m_params[0].deactivationTime; }, |
984 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); }, | 1111 | (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); } ), | 1112 | (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ), |
986 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 1113 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
987 | 0.8f, | 1114 | 0.8f, |
988 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | 1115 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |
989 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | 1116 | (s) => { return s.m_params[0].linearSleepingThreshold; }, |
990 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); }, | 1117 | (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); } ), | 1118 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), |
992 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 1119 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
993 | 1.0f, | 1120 | 1.0f, |
994 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | 1121 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |
995 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | 1122 | (s) => { return s.m_params[0].angularSleepingThreshold; }, |
996 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); }, | 1123 | (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); } ), | 1124 | (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ), |
998 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 1125 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
999 | 0f, // set to zero to disable | 1126 | 0f, // set to zero to disable |
1000 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | 1127 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |
1001 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | 1128 | (s) => { return s.m_params[0].ccdMotionThreshold; }, |
1002 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); }, | 1129 | (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); } ), | 1130 | (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ), |
1004 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 1131 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
1005 | 0f, | 1132 | 0f, |
1006 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | 1133 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |
1007 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | 1134 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |
1008 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); }, | 1135 | (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); } ), | 1136 | (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ), |
1010 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 1137 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |
1011 | 0.1f, | 1138 | 0.1f, |
1012 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | 1139 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |
1013 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | 1140 | (s) => { return s.m_params[0].contactProcessingThreshold; }, |
1014 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); }, | 1141 | (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); } ), | 1142 | (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ), |
1016 | 1143 | ||
1017 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1144 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1018 | 0.5f, | 1145 | 0.5f, |
@@ -1107,6 +1234,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1107 | (s) => { return s.m_params[0].numberOfSolverIterations; }, | 1234 | (s) => { return s.m_params[0].numberOfSolverIterations; }, |
1108 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), | 1235 | (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), |
1109 | 1236 | ||
1237 | new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", | ||
1238 | (float)BSLinkset.LinksetImplementation.Compound, | ||
1239 | (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, | ||
1240 | (s) => { return s.m_params[0].linksetImplementation; }, | ||
1241 | (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.", | 1242 | new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", |
1111 | ConfigurationParameters.numericFalse, | 1243 | ConfigurationParameters.numericFalse, |
1112 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, | 1244 | (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, |
@@ -1128,12 +1260,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1128 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | 1260 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |
1129 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | 1261 | (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", | 1262 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
1131 | 0.001f, | 1263 | 0.1f, |
1132 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | 1264 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |
1133 | (s) => { return s.m_params[0].linkConstraintCFM; }, | 1265 | (s) => { return s.m_params[0].linkConstraintCFM; }, |
1134 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | 1266 | (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", | 1267 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
1136 | 0.8f, | 1268 | 0.1f, |
1137 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | 1269 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |
1138 | (s) => { return s.m_params[0].linkConstraintERP; }, | 1270 | (s) => { return s.m_params[0].linkConstraintERP; }, |
1139 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | 1271 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |
@@ -1259,7 +1391,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1259 | // If the local ID is APPLY_TO_NONE, just change the default value | 1391 | // 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 | 1392 | // 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 | 1393 | // 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) | 1394 | private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) |
1263 | { | 1395 | { |
1264 | List<uint> objectIDs = new List<uint>(); | 1396 | List<uint> objectIDs = new List<uint>(); |
1265 | switch (localID) | 1397 | switch (localID) |
@@ -1284,7 +1416,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1284 | } | 1416 | } |
1285 | 1417 | ||
1286 | // schedule the actual updating of the paramter to when the phys engine is not busy | 1418 | // 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) | 1419 | private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) |
1288 | { | 1420 | { |
1289 | float xval = val; | 1421 | float xval = val; |
1290 | List<uint> xlIDs = lIDs; | 1422 | List<uint> xlIDs = lIDs; |
@@ -1326,12 +1458,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1326 | 1458 | ||
1327 | #endregion Runtime settable parameters | 1459 | #endregion Runtime settable parameters |
1328 | 1460 | ||
1461 | // Debugging routine for dumping detailed physical information for vehicle prims | ||
1462 | private void DumpVehicles() | ||
1463 | { | ||
1464 | foreach (BSPrim prim in m_vehicles) | ||
1465 | { | ||
1466 | BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr); | ||
1467 | BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr); | ||
1468 | } | ||
1469 | } | ||
1470 | |||
1329 | // Invoke the detailed logger and output something if it's enabled. | 1471 | // Invoke the detailed logger and output something if it's enabled. |
1330 | public void DetailLog(string msg, params Object[] args) | 1472 | public void DetailLog(string msg, params Object[] args) |
1331 | { | 1473 | { |
1332 | PhysicsLogging.Write(msg, args); | 1474 | PhysicsLogging.Write(msg, args); |
1333 | // Add the Flush() if debugging crashes to get all the messages written out. | 1475 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1334 | // PhysicsLogging.Flush(); | 1476 | PhysicsLogging.Flush(); |
1335 | } | 1477 | } |
1336 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1478 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1337 | public const string DetailLogZero = "0000000000"; | 1479 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 30fa50a..29a23c0 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 | ||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | public class BSShapeCollection : IDisposable | 37 | public sealed class BSShapeCollection : IDisposable |
38 | { | 38 | { |
39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; | 39 | private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; |
40 | 40 | ||
41 | 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. |
@@ -90,9 +92,10 @@ public class BSShapeCollection : IDisposable | |||
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 |
111 | // Returns 'true' if BSBody was changed. | ||
108 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, | 112 | bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World, |
109 | prim.BSShape, shapeData, bodyCallback); | 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,7 +173,7 @@ 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) |
@@ -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}", |
@@ -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); |
@@ -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 | { |
@@ -261,6 +261,9 @@ public class BSShapeCollection : IDisposable | |||
261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | 261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
262 | DereferenceMesh(shape, shapeCallback); | 262 | DereferenceMesh(shape, shapeCallback); |
263 | break; | 263 | break; |
264 | case ShapeData.PhysicsShapeType.SHAPE_COMPOUND: | ||
265 | DereferenceCompound(shape, shapeCallback); | ||
266 | break; | ||
264 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | 267 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: |
265 | break; | 268 | break; |
266 | default: | 269 | default: |
@@ -268,18 +271,7 @@ public class BSShapeCollection : IDisposable | |||
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 = ShapeData.PhysicsShapeType.SHAPE_MESH; | ||
356 | shapeInfo.shapeKey = meshDesc.shapeKey; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | if (TryGetHullByPtr(cShape, out hullDesc)) | ||
361 | { | ||
362 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_HULL; | ||
363 | shapeInfo.shapeKey = hullDesc.shapeKey; | ||
364 | } | ||
365 | else | ||
366 | { | ||
367 | if (BulletSimAPI.IsCompound2(cShape)) | ||
368 | { | ||
369 | shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_COMPOUND; | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | if (BulletSimAPI.IsNativeShape2(cShape)) | ||
374 | { | ||
375 | shapeInfo.isNativeShape = true; | ||
376 | shapeInfo.type = ShapeData.PhysicsShapeType.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 != ShapeData.PhysicsShapeType.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,22 +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 == ShapeData.PhysicsShapeType.SHAPE_AVATAR) |
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, ShapeData.PhysicsShapeType.SHAPE_AVATAR, |
339 | ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); | 412 | ShapeData.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); |
341 | ret = true; | 414 | ret = true; |
342 | haveShape = true; | 415 | haveShape = true; |
343 | } | 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 == ShapeData.PhysicsShapeType.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 | |||
344 | // 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 |
345 | if (!haveShape | 444 | if (!haveShape |
346 | && pbs != null | 445 | && pbs != null |
@@ -354,98 +453,110 @@ public class BSShapeCollection : IDisposable | |||
354 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
355 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
356 | { | 455 | { |
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | ||
357 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
358 | && 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) |
359 | { | 459 | { |
360 | haveShape = true; | 460 | haveShape = true; |
361 | if (forceRebuild | 461 | if (forceRebuild |
362 | || prim.Scale != shapeData.Size | 462 | || prim.Scale != prim.Size |
363 | || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE | 463 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_SPHERE |
364 | ) | 464 | ) |
365 | { | 465 | { |
366 | ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_SPHERE, | 466 | ret = GetReferenceToNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_SPHERE, |
367 | ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); | 467 | ShapeData.FixedShapeKey.KEY_SPHERE, shapeCallback); |
368 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
369 | prim.LocalID, forceRebuild, prim.BSShape); | 469 | prim.LocalID, forceRebuild, prim.PhysShape); |
370 | } | 470 | } |
371 | } | 471 | } |
372 | if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) | 472 | if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
373 | { | 473 | { |
374 | haveShape = true; | 474 | haveShape = true; |
375 | if (forceRebuild | 475 | if (forceRebuild |
376 | || prim.Scale != shapeData.Size | 476 | || prim.Scale != prim.Size |
377 | || prim.BSShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX | 477 | || prim.PhysShape.type != ShapeData.PhysicsShapeType.SHAPE_BOX |
378 | ) | 478 | ) |
379 | { | 479 | { |
380 | ret = GetReferenceToNativeShape( prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_BOX, | 480 | ret = GetReferenceToNativeShape( prim, ShapeData.PhysicsShapeType.SHAPE_BOX, |
381 | ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); | 481 | ShapeData.FixedShapeKey.KEY_BOX, shapeCallback); |
382 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
383 | prim.LocalID, forceRebuild, prim.BSShape); | 483 | prim.LocalID, forceRebuild, prim.PhysShape); |
384 | } | 484 | } |
385 | } | 485 | } |
386 | } | 486 | } |
487 | |||
387 | // 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. |
388 | // Note that if it's a native shape, the check for physical/non-physical is not | ||
389 | // made. Native shapes are best used in either case. | ||
390 | if (!haveShape && pbs != null) | 489 | if (!haveShape && pbs != null) |
391 | { | 490 | { |
392 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) | 491 | ret = CreateGeomMeshOrHull(prim, shapeCallback); |
393 | { | 492 | } |
394 | // Update prim.BSShape to reference a hull of this shape. | 493 | |
395 | ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); | 494 | return ret; |
396 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 495 | } |
397 | shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); | 496 | |
398 | } | 497 | public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
399 | else | 498 | { |
400 | { | 499 | |
401 | ret = GetReferenceToMesh(prim, shapeData, pbs, shapeCallback); | 500 | bool ret = false; |
402 | 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 |
403 | shapeData.ID, prim.BSShape, prim.BSShape.shapeKey.ToString("X")); | 502 | // made. Native shapes work in either case. |
404 | } | 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")); | ||
405 | } | 515 | } |
406 | return ret; | 516 | return ret; |
407 | } | 517 | } |
408 | 518 | ||
409 | // Creates a native shape and assignes it to prim.BSShape. | 519 | // Creates a native shape and assignes it to prim.BSShape. |
410 | // "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(). |
411 | private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, | 521 | private bool GetReferenceToNativeShape(BSPhysObject prim, |
412 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | 522 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, |
413 | ShapeDestructionCallback shapeCallback) | 523 | ShapeDestructionCallback shapeCallback) |
414 | { | 524 | { |
415 | // release any previous shape | 525 | // release any previous shape |
416 | DereferenceShape(prim.BSShape, true, shapeCallback); | 526 | DereferenceShape(prim.PhysShape, true, shapeCallback); |
417 | 527 | ||
418 | shapeData.Type = shapeType; | ||
419 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 528 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
420 | prim.Scale = shapeData.Size; | 529 | prim.Scale = prim.Size; |
421 | shapeData.Scale = shapeData.Size; | ||
422 | 530 | ||
423 | BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); | 531 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
424 | 532 | ||
425 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 533 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
426 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 534 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
427 | shapeData.ID, newShape, shapeData.Scale); | 535 | prim.LocalID, newShape, prim.Scale); |
428 | 536 | ||
429 | prim.BSShape = newShape; | 537 | prim.PhysShape = newShape; |
430 | return true; | 538 | return true; |
431 | } | 539 | } |
432 | 540 | ||
433 | private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, | 541 | private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, ShapeData.PhysicsShapeType shapeType, |
434 | ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) | 542 | ShapeData.FixedShapeKey shapeKey) |
435 | { | 543 | { |
436 | BulletShape newShape; | 544 | BulletShape newShape; |
437 | // Need to make sure the passed shape information is for the native type. | 545 | // Need to make sure the passed shape information is for the native type. |
438 | ShapeData nativeShapeData = shapeData; | 546 | ShapeData nativeShapeData = new ShapeData(); |
439 | nativeShapeData.Type = shapeType; | 547 | nativeShapeData.Type = shapeType; |
548 | nativeShapeData.ID = prim.LocalID; | ||
549 | nativeShapeData.Scale = prim.Scale; | ||
550 | nativeShapeData.Size = prim.Scale; | ||
440 | nativeShapeData.MeshKey = (ulong)shapeKey; | 551 | nativeShapeData.MeshKey = (ulong)shapeKey; |
441 | nativeShapeData.HullKey = (ulong)shapeKey; | 552 | nativeShapeData.HullKey = (ulong)shapeKey; |
442 | 553 | ||
443 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | 554 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) |
444 | { | 555 | { |
445 | newShape = new BulletShape( | 556 | newShape = new BulletShape( |
446 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, nativeShapeData.Scale) | 557 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) |
447 | , shapeType); | 558 | , shapeType); |
448 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", nativeShapeData.ID, nativeShapeData.Scale); | 559 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
449 | } | 560 | } |
450 | else | 561 | else |
451 | { | 562 | { |
@@ -454,7 +565,7 @@ public class BSShapeCollection : IDisposable | |||
454 | if (newShape.ptr == IntPtr.Zero) | 565 | if (newShape.ptr == IntPtr.Zero) |
455 | { | 566 | { |
456 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 567 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
457 | LogHeader, nativeShapeData.ID, nativeShapeData.Type); | 568 | LogHeader, prim.LocalID, shapeType); |
458 | } | 569 | } |
459 | newShape.shapeKey = (System.UInt64)shapeKey; | 570 | newShape.shapeKey = (System.UInt64)shapeKey; |
460 | newShape.isNativeShape = true; | 571 | newShape.isNativeShape = true; |
@@ -466,33 +577,32 @@ public class BSShapeCollection : IDisposable | |||
466 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | 577 | // Dereferences previous shape in BSShape and adds a reference for this new shape. |
467 | // Returns 'true' of a mesh was actually built. Otherwise . | 578 | // Returns 'true' of a mesh was actually built. Otherwise . |
468 | // Called at taint-time! | 579 | // Called at taint-time! |
469 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 580 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
470 | ShapeDestructionCallback shapeCallback) | ||
471 | { | 581 | { |
472 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 582 | BulletShape newShape = new BulletShape(IntPtr.Zero); |
473 | 583 | ||
474 | float lod; | 584 | float lod; |
475 | System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); | 585 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
476 | 586 | ||
477 | // if this new shape is the same as last time, don't recreate the mesh | 587 | // if this new shape is the same as last time, don't recreate the mesh |
478 | if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | 588 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) |
479 | return false; | 589 | return false; |
480 | 590 | ||
481 | DetailLog("{0},BSShapeCollection.CreateGeomMesh,create,oldKey={1},newKey={2}", | 591 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
482 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 592 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
483 | 593 | ||
484 | // Since we're recreating new, get rid of the reference to the previous shape | 594 | // Since we're recreating new, get rid of the reference to the previous shape |
485 | DereferenceShape(prim.BSShape, true, shapeCallback); | 595 | DereferenceShape(prim.PhysShape, true, shapeCallback); |
486 | 596 | ||
487 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); | 597 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod); |
488 | // Take evasive action if the mesh was not constructed. | 598 | // Take evasive action if the mesh was not constructed. |
489 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | 599 | newShape = VerifyMeshCreated(newShape, prim); |
490 | 600 | ||
491 | ReferenceShape(newShape); | 601 | ReferenceShape(newShape); |
492 | 602 | ||
493 | // meshes are already scaled by the meshmerizer | 603 | // meshes are already scaled by the meshmerizer |
494 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | 604 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); |
495 | prim.BSShape = newShape; | 605 | prim.PhysShape = newShape; |
496 | 606 | ||
497 | return true; // 'true' means a new shape has been added to this prim | 607 | return true; // 'true' means a new shape has been added to this prim |
498 | } | 608 | } |
@@ -526,7 +636,7 @@ public class BSShapeCollection : IDisposable | |||
526 | verticesAsFloats[vi++] = vv.Z; | 636 | verticesAsFloats[vi++] = vv.Z; |
527 | } | 637 | } |
528 | 638 | ||
529 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 639 | // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
530 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 640 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
531 | 641 | ||
532 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 642 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
@@ -541,32 +651,31 @@ public class BSShapeCollection : IDisposable | |||
541 | 651 | ||
542 | // See that hull shape exists in the physical world and update prim.BSShape. | 652 | // See that hull shape exists in the physical world and update prim.BSShape. |
543 | // We could be creating the hull because scale changed or whatever. | 653 | // We could be creating the hull because scale changed or whatever. |
544 | private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 654 | private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
545 | ShapeDestructionCallback shapeCallback) | ||
546 | { | 655 | { |
547 | BulletShape newShape; | 656 | BulletShape newShape; |
548 | 657 | ||
549 | float lod; | 658 | float lod; |
550 | System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); | 659 | System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
551 | 660 | ||
552 | // if the hull hasn't changed, don't rebuild it | 661 | // if the hull hasn't changed, don't rebuild it |
553 | if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | 662 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) |
554 | return false; | 663 | return false; |
555 | 664 | ||
556 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", | 665 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
557 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 666 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
558 | 667 | ||
559 | // Remove usage of the previous shape. | 668 | // Remove usage of the previous shape. |
560 | DereferenceShape(prim.BSShape, true, shapeCallback); | 669 | DereferenceShape(prim.PhysShape, true, shapeCallback); |
561 | 670 | ||
562 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); | 671 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod); |
563 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | 672 | newShape = VerifyMeshCreated(newShape, prim); |
564 | 673 | ||
565 | ReferenceShape(newShape); | 674 | ReferenceShape(newShape); |
566 | 675 | ||
567 | // hulls are already scaled by the meshmerizer | 676 | // hulls are already scaled by the meshmerizer |
568 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | 677 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); |
569 | prim.BSShape = newShape; | 678 | prim.PhysShape = newShape; |
570 | return true; // 'true' means a new shape has been added to this prim | 679 | return true; // 'true' means a new shape has been added to this prim |
571 | } | 680 | } |
572 | 681 | ||
@@ -685,9 +794,31 @@ public class BSShapeCollection : IDisposable | |||
685 | return; | 794 | return; |
686 | } | 795 | } |
687 | 796 | ||
797 | // Compound shapes are always built from scratch. | ||
798 | // This shouldn't be to bad since most of the parts will be meshes that had been built previously. | ||
799 | private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | ||
800 | { | ||
801 | // Remove reference to the old shape | ||
802 | // Don't need to do this as the shape is freed when the new root shape is created below. | ||
803 | // DereferenceShape(prim.PhysShape, true, shapeCallback); | ||
804 | |||
805 | BulletShape cShape = new BulletShape( | ||
806 | BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); | ||
807 | |||
808 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | ||
809 | CreateGeomMeshOrHull(prim, shapeCallback); | ||
810 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | ||
811 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | ||
812 | prim.LocalID, cShape, prim.PhysShape); | ||
813 | |||
814 | prim.PhysShape = cShape; | ||
815 | |||
816 | return true; | ||
817 | } | ||
818 | |||
688 | // Create a hash of all the shape parameters to be used as a key | 819 | // Create a hash of all the shape parameters to be used as a key |
689 | // for this particular shape. | 820 | // for this particular shape. |
690 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) | 821 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) |
691 | { | 822 | { |
692 | // level of detail based on size and type of the object | 823 | // level of detail based on size and type of the object |
693 | float lod = PhysicsScene.MeshLOD; | 824 | float lod = PhysicsScene.MeshLOD; |
@@ -695,40 +826,40 @@ public class BSShapeCollection : IDisposable | |||
695 | lod = PhysicsScene.SculptLOD; | 826 | lod = PhysicsScene.SculptLOD; |
696 | 827 | ||
697 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | 828 | // Mega prims usually get more detail because one can interact with shape approximations at this size. |
698 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); | 829 | float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); |
699 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 830 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) |
700 | lod = PhysicsScene.MeshMegaPrimLOD; | 831 | lod = PhysicsScene.MeshMegaPrimLOD; |
701 | 832 | ||
702 | retLod = lod; | 833 | retLod = lod; |
703 | return pbs.GetMeshKey(shapeData.Size, lod); | 834 | return pbs.GetMeshKey(size, lod); |
704 | } | 835 | } |
705 | // For those who don't want the LOD | 836 | // For those who don't want the LOD |
706 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) | 837 | private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs) |
707 | { | 838 | { |
708 | float lod; | 839 | float lod; |
709 | return ComputeShapeKey(shapeData, pbs, out lod); | 840 | return ComputeShapeKey(size, pbs, out lod); |
710 | } | 841 | } |
711 | 842 | ||
712 | // The creation of a mesh or hull can fail if an underlying asset is not available. | 843 | // The creation of a mesh or hull can fail if an underlying asset is not available. |
713 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; | 844 | // There are two cases: 1) the asset is not in the cache and it needs to be fetched; |
714 | // and 2) the asset cannot be converted (like decompressing JPEG2000s). | 845 | // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). |
715 | // The first case causes the asset to be fetched. The second case just requires | 846 | // The first case causes the asset to be fetched. The second case requires |
716 | // us to not loop forever. | 847 | // us to not loop forever. |
717 | // Called after creating a physical mesh or hull. If the physical shape was created, | 848 | // Called after creating a physical mesh or hull. If the physical shape was created, |
718 | // just return. | 849 | // just return. |
719 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) | 850 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
720 | { | 851 | { |
721 | // If the shape was successfully created, nothing more to do | 852 | // If the shape was successfully created, nothing more to do |
722 | if (newShape.ptr != IntPtr.Zero) | 853 | if (newShape.ptr != IntPtr.Zero) |
723 | return newShape; | 854 | return newShape; |
724 | 855 | ||
725 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 856 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
726 | if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) | 857 | if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero) |
727 | { | 858 | { |
728 | prim.LastAssetBuildFailed = true; | 859 | prim.LastAssetBuildFailed = true; |
729 | BSPhysObject xprim = prim; | 860 | BSPhysObject xprim = prim; |
730 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", | 861 | DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}", |
731 | LogHeader, shapeData.ID.ToString("X"), prim.LastAssetBuildFailed); | 862 | LogHeader, prim.LocalID, prim.LastAssetBuildFailed); |
732 | Util.FireAndForget(delegate | 863 | Util.FireAndForget(delegate |
733 | { | 864 | { |
734 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | 865 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; |
@@ -745,7 +876,7 @@ public class BSShapeCollection : IDisposable | |||
745 | yprim.BaseShape.SculptData = asset.Data; | 876 | yprim.BaseShape.SculptData = asset.Data; |
746 | // This will cause the prim to see that the filler shape is not the right | 877 | // This will cause the prim to see that the filler shape is not the right |
747 | // one and try again to build the object. | 878 | // one and try again to build the object. |
748 | // No race condition with the native sphere setting since the rebuild is at taint time. | 879 | // No race condition with the normal shape setting since the rebuild is at taint time. |
749 | yprim.ForceBodyShapeRebuild(false); | 880 | yprim.ForceBodyShapeRebuild(false); |
750 | 881 | ||
751 | }); | 882 | }); |
@@ -757,13 +888,13 @@ public class BSShapeCollection : IDisposable | |||
757 | if (prim.LastAssetBuildFailed) | 888 | if (prim.LastAssetBuildFailed) |
758 | { | 889 | { |
759 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", | 890 | PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}", |
760 | LogHeader, shapeData.ID, pbs.SculptTexture); | 891 | LogHeader, prim.LocalID, prim.BaseShape.SculptTexture); |
761 | } | 892 | } |
762 | } | 893 | } |
763 | 894 | ||
764 | // While we figure out the real problem, stick a simple native shape on the object. | 895 | // While we figure out the real problem, stick a simple native shape on the object. |
765 | BulletShape fillinShape = | 896 | BulletShape fillinShape = |
766 | BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_BOX, shapeData, ShapeData.FixedShapeKey.KEY_BOX); | 897 | BuildPhysicalNativeShape(prim, ShapeData.PhysicsShapeType.SHAPE_BOX, ShapeData.FixedShapeKey.KEY_BOX); |
767 | 898 | ||
768 | return fillinShape; | 899 | return fillinShape; |
769 | } | 900 | } |
@@ -773,18 +904,18 @@ public class BSShapeCollection : IDisposable | |||
773 | // Returns 'true' if an object was actually created. | 904 | // Returns 'true' if an object was actually created. |
774 | // Called at taint-time. | 905 | // Called at taint-time. |
775 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, | 906 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, |
776 | ShapeData shapeData, BodyDestructionCallback bodyCallback) | 907 | BodyDestructionCallback bodyCallback) |
777 | { | 908 | { |
778 | bool ret = false; | 909 | bool ret = false; |
779 | 910 | ||
780 | // the mesh, hull or native shape must have already been created in Bullet | 911 | // the mesh, hull or native shape must have already been created in Bullet |
781 | bool mustRebuild = (prim.BSBody.ptr == IntPtr.Zero); | 912 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); |
782 | 913 | ||
783 | // If there is an existing body, verify it's of an acceptable type. | 914 | // If there is an existing body, verify it's of an acceptable type. |
784 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 915 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
785 | if (!mustRebuild) | 916 | if (!mustRebuild) |
786 | { | 917 | { |
787 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.BSBody.ptr); | 918 | CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); |
788 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY | 919 | if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY |
789 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) | 920 | || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) |
790 | { | 921 | { |
@@ -796,27 +927,27 @@ public class BSShapeCollection : IDisposable | |||
796 | if (mustRebuild || forceRebuild) | 927 | if (mustRebuild || forceRebuild) |
797 | { | 928 | { |
798 | // Free any old body | 929 | // Free any old body |
799 | DereferenceBody(prim.BSBody, true, bodyCallback); | 930 | DereferenceBody(prim.PhysBody, true, bodyCallback); |
800 | 931 | ||
801 | BulletBody aBody; | 932 | BulletBody aBody; |
802 | IntPtr bodyPtr = IntPtr.Zero; | 933 | IntPtr bodyPtr = IntPtr.Zero; |
803 | if (prim.IsSolid) | 934 | if (prim.IsSolid) |
804 | { | 935 | { |
805 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 936 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
806 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 937 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
807 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 938 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
808 | } | 939 | } |
809 | else | 940 | else |
810 | { | 941 | { |
811 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 942 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
812 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 943 | prim.LocalID, prim.ForcePosition, prim.ForceOrientation); |
813 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 944 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
814 | } | 945 | } |
815 | aBody = new BulletBody(shapeData.ID, bodyPtr); | 946 | aBody = new BulletBody(prim.LocalID, bodyPtr); |
816 | 947 | ||
817 | ReferenceBody(aBody, true); | 948 | ReferenceBody(aBody, true); |
818 | 949 | ||
819 | prim.BSBody = aBody; | 950 | prim.PhysBody = aBody; |
820 | 951 | ||
821 | ret = true; | 952 | ret = true; |
822 | } | 953 | } |
@@ -824,6 +955,42 @@ public class BSShapeCollection : IDisposable | |||
824 | return ret; | 955 | return ret; |
825 | } | 956 | } |
826 | 957 | ||
958 | private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) | ||
959 | { | ||
960 | bool ret = false; | ||
961 | MeshDesc foundDesc = new MeshDesc(); | ||
962 | foreach (MeshDesc md in Meshes.Values) | ||
963 | { | ||
964 | if (md.ptr == addr) | ||
965 | { | ||
966 | foundDesc = md; | ||
967 | ret = true; | ||
968 | break; | ||
969 | } | ||
970 | |||
971 | } | ||
972 | outDesc = foundDesc; | ||
973 | return ret; | ||
974 | } | ||
975 | |||
976 | private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) | ||
977 | { | ||
978 | bool ret = false; | ||
979 | HullDesc foundDesc = new HullDesc(); | ||
980 | foreach (HullDesc hd in Hulls.Values) | ||
981 | { | ||
982 | if (hd.ptr == addr) | ||
983 | { | ||
984 | foundDesc = hd; | ||
985 | ret = true; | ||
986 | break; | ||
987 | } | ||
988 | |||
989 | } | ||
990 | outDesc = foundDesc; | ||
991 | return ret; | ||
992 | } | ||
993 | |||
827 | private void DetailLog(string msg, params Object[] args) | 994 | private void DetailLog(string msg, params Object[] args) |
828 | { | 995 | { |
829 | if (PhysicsScene.PhysicsLogging.Enabled) | 996 | if (PhysicsScene.PhysicsLogging.Enabled) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 880859a..7c34af2 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -40,7 +40,7 @@ using OpenMetaverse; | |||
40 | 40 | ||
41 | namespace OpenSim.Region.Physics.BulletSPlugin | 41 | namespace OpenSim.Region.Physics.BulletSPlugin |
42 | { | 42 | { |
43 | public class BSTerrainManager | 43 | public sealed class BSTerrainManager |
44 | { | 44 | { |
45 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 45 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
46 | 46 | ||
@@ -238,7 +238,7 @@ public class BSTerrainManager | |||
238 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", | 238 | DetailLog("{0},UpdateOrCreateTerrain:UpdateExisting,call,terrainBase={1},minC={2}, maxC={3}, szX={4}, szY={5}", |
239 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); | 239 | BSScene.DetailLogZero, terrainRegionBase, mapInfo.minCoords, mapInfo.maxCoords, mapInfo.sizeX, mapInfo.sizeY); |
240 | 240 | ||
241 | BSScene.TaintCallback rebuildOperation = delegate() | 241 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:UpdateExisting", delegate() |
242 | { | 242 | { |
243 | if (MegaRegionParentPhysicsScene != null) | 243 | if (MegaRegionParentPhysicsScene != null) |
244 | { | 244 | { |
@@ -337,14 +337,7 @@ public class BSTerrainManager | |||
337 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 337 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); |
338 | 338 | ||
339 | m_terrainModified = true; | 339 | m_terrainModified = true; |
340 | }; | 340 | }); |
341 | |||
342 | // There is the option to do the changes now (we're already in 'taint time'), or | ||
343 | // to do the Bullet operations later. | ||
344 | if (inTaintTime) | ||
345 | rebuildOperation(); | ||
346 | else | ||
347 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); | ||
348 | } | 341 | } |
349 | else | 342 | else |
350 | { | 343 | { |
@@ -364,7 +357,7 @@ public class BSTerrainManager | |||
364 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 357 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
365 | 358 | ||
366 | // Code that must happen at taint-time | 359 | // Code that must happen at taint-time |
367 | BSScene.TaintCallback createOperation = delegate() | 360 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateOrCreateTerrain:NewTerrain", delegate() |
368 | { | 361 | { |
369 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); | 362 | DetailLog("{0},UpdateOrCreateTerrain:NewTerrain,taint,baseX={1},baseY={2}", BSScene.DetailLogZero, minCoords.X, minCoords.Y); |
370 | // Create a new mapInfo that will be filled with the new info | 363 | // Create a new mapInfo that will be filled with the new info |
@@ -377,13 +370,7 @@ public class BSTerrainManager | |||
377 | UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true); | 370 | UpdateOrCreateTerrain(newTerrainID, heightMap, minCoords, maxCoords, true); |
378 | 371 | ||
379 | m_terrainModified = true; | 372 | m_terrainModified = true; |
380 | }; | 373 | }); |
381 | |||
382 | // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. | ||
383 | if (inTaintTime) | ||
384 | createOperation(); | ||
385 | else | ||
386 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); | ||
387 | } | 374 | } |
388 | } | 375 | } |
389 | 376 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 5ffd591..702bd77 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -194,6 +194,7 @@ public struct ShapeData | |||
194 | // following defined by BulletSim | 194 | // following defined by BulletSim |
195 | SHAPE_GROUNDPLANE = 20, | 195 | SHAPE_GROUNDPLANE = 20, |
196 | SHAPE_TERRAIN = 21, | 196 | SHAPE_TERRAIN = 21, |
197 | SHAPE_COMPOUND = 22, | ||
197 | }; | 198 | }; |
198 | public uint ID; | 199 | public uint ID; |
199 | public PhysicsShapeType Type; | 200 | public PhysicsShapeType Type; |
@@ -299,6 +300,7 @@ public struct ConfigurationParameters | |||
299 | public float shouldEnableFrictionCaching; | 300 | public float shouldEnableFrictionCaching; |
300 | public float numberOfSolverIterations; | 301 | public float numberOfSolverIterations; |
301 | 302 | ||
303 | public float linksetImplementation; | ||
302 | public float linkConstraintUseFrameOffset; | 304 | public float linkConstraintUseFrameOffset; |
303 | public float linkConstraintEnableTransMotor; | 305 | public float linkConstraintEnableTransMotor; |
304 | public float linkConstraintTransMotorMaxVel; | 306 | public float linkConstraintTransMotorMaxVel; |
@@ -378,6 +380,7 @@ public enum CollisionFilterGroups : uint | |||
378 | BTerrainFilter = 1 << 11, | 380 | BTerrainFilter = 1 << 11, |
379 | BRaycastFilter = 1 << 12, | 381 | BRaycastFilter = 1 << 12, |
380 | BSolidFilter = 1 << 13, | 382 | BSolidFilter = 1 << 13, |
383 | BLinksetFilter = 1 << 14, | ||
381 | 384 | ||
382 | // The collsion filters and masked are defined in one place -- don't want them scattered | 385 | // The collsion filters and masked are defined in one place -- don't want them scattered |
383 | AvatarFilter = BCharacterFilter, | 386 | AvatarFilter = BCharacterFilter, |
@@ -386,6 +389,8 @@ public enum CollisionFilterGroups : uint | |||
386 | ObjectMask = BAllFilter, | 389 | ObjectMask = BAllFilter, |
387 | StaticObjectFilter = BStaticFilter, | 390 | StaticObjectFilter = BStaticFilter, |
388 | StaticObjectMask = BAllFilter, | 391 | StaticObjectMask = BAllFilter, |
392 | LinksetFilter = BLinksetFilter, | ||
393 | LinksetMask = BAllFilter & ~BLinksetFilter, | ||
389 | VolumeDetectFilter = BSensorTrigger, | 394 | VolumeDetectFilter = BSensorTrigger, |
390 | VolumeDetectMask = ~BSensorTrigger, | 395 | VolumeDetectMask = ~BSensorTrigger, |
391 | TerrainFilter = BTerrainFilter, | 396 | TerrainFilter = BTerrainFilter, |
@@ -395,8 +400,6 @@ public enum CollisionFilterGroups : uint | |||
395 | 400 | ||
396 | }; | 401 | }; |
397 | 402 | ||
398 | |||
399 | |||
400 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | 403 | // 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. | 404 | // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. |
402 | public enum ConstraintParams : int | 405 | public enum ConstraintParams : int |
@@ -611,13 +614,22 @@ public static extern bool IsNativeShape2(IntPtr shape); | |||
611 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 614 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); |
612 | 615 | ||
613 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 616 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
614 | public static extern IntPtr CreateCompoundShape2(IntPtr sim); | 617 | public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); |
618 | |||
619 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
620 | public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); | ||
621 | |||
622 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
623 | public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | ||
624 | |||
625 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
626 | public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); | ||
615 | 627 | ||
616 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 628 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
617 | public static extern void AddChildToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); | 629 | public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); |
618 | 630 | ||
619 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 631 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
620 | public static extern void RemoveChildFromCompoundShape2(IntPtr cShape, IntPtr removeShape); | 632 | public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); |
621 | 633 | ||
622 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 634 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
623 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); | 635 | public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); |
@@ -881,10 +893,10 @@ public static extern float GetCcdMotionThreshold2(IntPtr obj); | |||
881 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); | 893 | public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); |
882 | 894 | ||
883 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 895 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
884 | public static extern float GetCcdSweepSphereRadius2(IntPtr obj); | 896 | public static extern float GetCcdSweptSphereRadius2(IntPtr obj); |
885 | 897 | ||
886 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 898 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
887 | public static extern void SetCcdSweepSphereRadius2(IntPtr obj, float val); | 899 | public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); |
888 | 900 | ||
889 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 901 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
890 | public static extern IntPtr GetUserPointer2(IntPtr obj); | 902 | public static extern IntPtr GetUserPointer2(IntPtr obj); |