diff options
author | BlueWall | 2012-10-20 05:25:58 -0400 |
---|---|---|
committer | BlueWall | 2012-10-20 05:25:58 -0400 |
commit | 07f1d44174f5e2b4e3d5ffdec3619bb84f357af2 (patch) | |
tree | 83cc0442b2c1b89a5b3dd94cff23d5098415777e /OpenSim/Region/Physics/BulletSPlugin | |
parent | Merge branch 'master' into connector_plugin (diff) | |
parent | Fix: invinite loading for Viewer3 : parcelinfo request of traffic-value (impl... (diff) | |
download | opensim-SC_OLD-07f1d44174f5e2b4e3d5ffdec3619bb84f357af2.zip opensim-SC_OLD-07f1d44174f5e2b4e3d5ffdec3619bb84f357af2.tar.gz opensim-SC_OLD-07f1d44174f5e2b4e3d5ffdec3619bb84f357af2.tar.bz2 opensim-SC_OLD-07f1d44174f5e2b4e3d5ffdec3619bb84f357af2.tar.xz |
Merge branch 'master' into connector_plugin
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 229 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | 13 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 16 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 185 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 45 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 220 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 232 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | 479 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | 27 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | 44 |
10 files changed, 911 insertions, 579 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 2a52e01..623ac8f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -41,8 +41,6 @@ public class BSCharacter : BSPhysObject | |||
41 | 41 | ||
42 | // private bool _stopped; | 42 | // private bool _stopped; |
43 | private OMV.Vector3 _size; | 43 | private OMV.Vector3 _size; |
44 | private OMV.Vector3 _scale; | ||
45 | private PrimitiveBaseShape _pbs; | ||
46 | private bool _grabbed; | 44 | private bool _grabbed; |
47 | private bool _selected; | 45 | private bool _selected; |
48 | private OMV.Vector3 _position; | 46 | private OMV.Vector3 _position; |
@@ -67,6 +65,10 @@ public class BSCharacter : BSPhysObject | |||
67 | private bool _kinematic; | 65 | private bool _kinematic; |
68 | private float _buoyancy; | 66 | private float _buoyancy; |
69 | 67 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | ||
69 | private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | ||
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | ||
71 | |||
70 | private OMV.Vector3 _PIDTarget; | 72 | private OMV.Vector3 _PIDTarget; |
71 | private bool _usePID; | 73 | private bool _usePID; |
72 | private float _PIDTau; | 74 | private float _PIDTau; |
@@ -84,14 +86,18 @@ public class BSCharacter : BSPhysObject | |||
84 | _flying = isFlying; | 86 | _flying = isFlying; |
85 | _orientation = OMV.Quaternion.Identity; | 87 | _orientation = OMV.Quaternion.Identity; |
86 | _velocity = OMV.Vector3.Zero; | 88 | _velocity = OMV.Vector3.Zero; |
89 | _appliedVelocity = OMV.Vector3.Zero; | ||
87 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
91 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | ||
92 | _avatarDensity = PhysicsScene.Params.avatarDensity; | ||
88 | 93 | ||
89 | // The dimensions of the avatar capsule are kept in the scale. | 94 | // The dimensions of the avatar capsule are kept in the scale. |
90 | // Physics creates a unit capsule which is scaled by the physics engine. | 95 | // Physics creates a unit capsule which is scaled by the physics engine. |
91 | ComputeAvatarScale(_size); | 96 | ComputeAvatarScale(_size); |
92 | _avatarDensity = PhysicsScene.Params.avatarDensity; | 97 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
93 | // set _avatarVolume and _mass based on capsule size, _density and _scale | ||
94 | ComputeAvatarVolumeAndMass(); | 98 | ComputeAvatarVolumeAndMass(); |
99 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
100 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, MassRaw); | ||
95 | 101 | ||
96 | ShapeData shapeData = new ShapeData(); | 102 | ShapeData shapeData = new ShapeData(); |
97 | shapeData.ID = LocalID; | 103 | shapeData.ID = LocalID; |
@@ -99,28 +105,22 @@ public class BSCharacter : BSPhysObject | |||
99 | shapeData.Position = _position; | 105 | shapeData.Position = _position; |
100 | shapeData.Rotation = _orientation; | 106 | shapeData.Rotation = _orientation; |
101 | shapeData.Velocity = _velocity; | 107 | shapeData.Velocity = _velocity; |
102 | shapeData.Scale = _scale; | 108 | shapeData.Size = Scale; |
109 | shapeData.Scale = Scale; | ||
103 | shapeData.Mass = _mass; | 110 | shapeData.Mass = _mass; |
104 | shapeData.Buoyancy = _buoyancy; | 111 | shapeData.Buoyancy = _buoyancy; |
105 | shapeData.Static = ShapeData.numericFalse; | 112 | shapeData.Static = ShapeData.numericFalse; |
106 | shapeData.Friction = PhysicsScene.Params.avatarFriction; | 113 | shapeData.Friction = PhysicsScene.Params.avatarStandingFriction; |
107 | shapeData.Restitution = PhysicsScene.Params.avatarRestitution; | 114 | shapeData.Restitution = PhysicsScene.Params.avatarRestitution; |
108 | 115 | ||
109 | // do actual create at taint time | 116 | // do actual create at taint time |
110 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 117 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
111 | { | 118 | { |
112 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 119 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
113 | BulletSimAPI.CreateObject(PhysicsScene.WorldID, shapeData); | 120 | // New body and shape into BSBody and BSShape |
114 | 121 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, shapeData, null, null, null); | |
115 | // Set the buoyancy for flying. This will be refactored when all the settings happen in C#. | ||
116 | // If not set at creation, the avatar will stop flying when created after crossing a region boundry. | ||
117 | BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy); | ||
118 | 122 | ||
119 | BSBody = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(PhysicsScene.World.ptr, LocalID)); | 123 | SetPhysicalProperties(); |
120 | |||
121 | // This works here because CreateObject has already put the character into the physical world. | ||
122 | BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, | ||
123 | (uint)CollisionFilterGroups.AvatarFilter, (uint)CollisionFilterGroups.AvatarMask); | ||
124 | }); | 124 | }); |
125 | return; | 125 | return; |
126 | } | 126 | } |
@@ -131,53 +131,85 @@ public class BSCharacter : BSPhysObject | |||
131 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 131 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
132 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 132 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
133 | { | 133 | { |
134 | BulletSimAPI.DestroyObject(PhysicsScene.WorldID, LocalID); | 134 | PhysicsScene.Shapes.DereferenceBody(BSBody, true, null); |
135 | PhysicsScene.Shapes.DereferenceShape(BSShape, true, null); | ||
135 | }); | 136 | }); |
136 | } | 137 | } |
137 | 138 | ||
139 | private void SetPhysicalProperties() | ||
140 | { | ||
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr); | ||
142 | |||
143 | ZeroMotion(); | ||
144 | ForcePosition = _position; | ||
145 | // Set the velocity and compute the proper friction | ||
146 | ForceVelocity = _velocity; | ||
147 | BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.avatarRestitution); | ||
148 | BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); | ||
149 | BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | ||
150 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
151 | { | ||
152 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
153 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
154 | } | ||
155 | |||
156 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); | ||
157 | BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); | ||
158 | |||
159 | BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | ||
160 | |||
161 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr); | ||
162 | |||
163 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | ||
164 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr); | ||
165 | |||
166 | // Do this after the object has been added to the world | ||
167 | BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, | ||
168 | (uint)CollisionFilterGroups.AvatarFilter, | ||
169 | (uint)CollisionFilterGroups.AvatarMask); | ||
170 | } | ||
171 | |||
138 | public override void RequestPhysicsterseUpdate() | 172 | public override void RequestPhysicsterseUpdate() |
139 | { | 173 | { |
140 | base.RequestPhysicsterseUpdate(); | 174 | base.RequestPhysicsterseUpdate(); |
141 | } | 175 | } |
142 | // No one calls this method so I don't know what it could possibly mean | 176 | // No one calls this method so I don't know what it could possibly mean |
143 | public override bool Stopped { | 177 | public override bool Stopped { get { return false; } } |
144 | get { return false; } | ||
145 | } | ||
146 | public override OMV.Vector3 Size { | 178 | public override OMV.Vector3 Size { |
147 | get | 179 | get |
148 | { | 180 | { |
149 | // Avatar capsule size is kept in the scale parameter. | 181 | // Avatar capsule size is kept in the scale parameter. |
150 | return new OMV.Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); | 182 | return _size; |
151 | } | 183 | } |
152 | 184 | ||
153 | set { | 185 | set { |
154 | // When an avatar's size is set, only the height is changed | 186 | // When an avatar's size is set, only the height is changed. |
155 | // and that really only depends on the radius. | ||
156 | _size = value; | 187 | _size = value; |
157 | ComputeAvatarScale(_size); | 188 | ComputeAvatarScale(_size); |
158 | |||
159 | // TODO: something has to be done with the avatar's vertical position | ||
160 | |||
161 | ComputeAvatarVolumeAndMass(); | 189 | ComputeAvatarVolumeAndMass(); |
190 | DetailLog("{0},BSCharacter.setSize,call,scale={1},density={2},volume={3},mass={4}", | ||
191 | LocalID, Scale, _avatarDensity, _avatarVolume, MassRaw); | ||
162 | 192 | ||
163 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 193 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
164 | { | 194 | { |
165 | BulletSimAPI.SetObjectScaleMass(PhysicsScene.WorldID, LocalID, _scale, _mass, true); | 195 | BulletSimAPI.SetLocalScaling2(BSShape.ptr, Scale); |
196 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(BSShape.ptr, MassRaw); | ||
197 | BulletSimAPI.SetMassProps2(BSBody.ptr, MassRaw, localInertia); | ||
166 | }); | 198 | }); |
167 | 199 | ||
168 | } | 200 | } |
169 | } | 201 | } |
170 | public override PrimitiveBaseShape Shape { | 202 | public override OMV.Vector3 Scale { get; set; } |
171 | set { _pbs = value; | 203 | public override PrimitiveBaseShape Shape |
172 | } | 204 | { |
205 | set { BaseShape = value; } | ||
173 | } | 206 | } |
207 | |||
174 | public override bool Grabbed { | 208 | public override bool Grabbed { |
175 | set { _grabbed = value; | 209 | set { _grabbed = value; } |
176 | } | ||
177 | } | 210 | } |
178 | public override bool Selected { | 211 | public override bool Selected { |
179 | set { _selected = value; | 212 | set { _selected = value; } |
180 | } | ||
181 | } | 213 | } |
182 | public override void CrossingFailure() { return; } | 214 | public override void CrossingFailure() { return; } |
183 | public override void link(PhysicsActor obj) { return; } | 215 | public override void link(PhysicsActor obj) { return; } |
@@ -204,7 +236,7 @@ public class BSCharacter : BSPhysObject | |||
204 | 236 | ||
205 | public override OMV.Vector3 Position { | 237 | public override OMV.Vector3 Position { |
206 | get { | 238 | get { |
207 | // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); | 239 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); |
208 | return _position; | 240 | return _position; |
209 | } | 241 | } |
210 | set { | 242 | set { |
@@ -214,7 +246,7 @@ public class BSCharacter : BSPhysObject | |||
214 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 246 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
215 | { | 247 | { |
216 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 248 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
217 | BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); | 249 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); |
218 | }); | 250 | }); |
219 | } | 251 | } |
220 | } | 252 | } |
@@ -263,7 +295,7 @@ public class BSCharacter : BSPhysObject | |||
263 | // A version of the sanity check that also makes sure a new position value is | 295 | // A version of the sanity check that also makes sure a new position value is |
264 | // pushed back to the physics engine. This routine would be used by anyone | 296 | // pushed back to the physics engine. This routine would be used by anyone |
265 | // who is not already pushing the value. | 297 | // who is not already pushing the value. |
266 | private bool PositionSanityCheck2(bool atTaintTime) | 298 | private bool PositionSanityCheck(bool inTaintTime) |
267 | { | 299 | { |
268 | bool ret = false; | 300 | bool ret = false; |
269 | if (PositionSanityCheck()) | 301 | if (PositionSanityCheck()) |
@@ -273,9 +305,9 @@ public class BSCharacter : BSPhysObject | |||
273 | BSScene.TaintCallback sanityOperation = delegate() | 305 | BSScene.TaintCallback sanityOperation = delegate() |
274 | { | 306 | { |
275 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 307 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
276 | BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); | 308 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); |
277 | }; | 309 | }; |
278 | if (atTaintTime) | 310 | if (inTaintTime) |
279 | sanityOperation(); | 311 | sanityOperation(); |
280 | else | 312 | else |
281 | PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); | 313 | PhysicsScene.TaintedObject("BSCharacter.PositionSanityCheck", sanityOperation); |
@@ -284,11 +316,7 @@ public class BSCharacter : BSPhysObject | |||
284 | return ret; | 316 | return ret; |
285 | } | 317 | } |
286 | 318 | ||
287 | public override float Mass { | 319 | public override float Mass { get { return _mass; } } |
288 | get { | ||
289 | return _mass; | ||
290 | } | ||
291 | } | ||
292 | 320 | ||
293 | // used when we only want this prim's mass and not the linkset thing | 321 | // used when we only want this prim's mass and not the linkset thing |
294 | public override float MassRaw { get {return _mass; } } | 322 | public override float MassRaw { get {return _mass; } } |
@@ -301,15 +329,13 @@ public class BSCharacter : BSPhysObject | |||
301 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 329 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
302 | { | 330 | { |
303 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 331 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
304 | BulletSimAPI.SetObjectForce(PhysicsScene.WorldID, LocalID, _force); | 332 | BulletSimAPI.SetObjectForce2(BSBody.ptr, _force); |
305 | }); | 333 | }); |
306 | } | 334 | } |
307 | } | 335 | } |
308 | 336 | ||
309 | public override int VehicleType { | 337 | // Avatars don't do vehicles |
310 | get { return 0; } | 338 | public override int VehicleType { get { return 0; } set { return; } } |
311 | set { return; } | ||
312 | } | ||
313 | public override void VehicleFloatParam(int param, float value) { } | 339 | public override void VehicleFloatParam(int param, float value) { } |
314 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | 340 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} |
315 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | 341 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } |
@@ -328,10 +354,39 @@ public class BSCharacter : BSPhysObject | |||
328 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 354 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() |
329 | { | 355 | { |
330 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | 356 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); |
331 | BulletSimAPI.SetObjectVelocity(PhysicsScene.WorldID, LocalID, _velocity); | 357 | ForceVelocity = _velocity; |
332 | }); | 358 | }); |
333 | } | 359 | } |
334 | } | 360 | } |
361 | public override OMV.Vector3 ForceVelocity { | ||
362 | get { return _velocity; } | ||
363 | set { | ||
364 | // Depending on whether the avatar is moving or not, change the friction | ||
365 | // to keep the avatar from slipping around | ||
366 | if (_velocity.Length() == 0) | ||
367 | { | ||
368 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | ||
369 | { | ||
370 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | ||
371 | BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); | ||
372 | } | ||
373 | } | ||
374 | else | ||
375 | { | ||
376 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | ||
377 | { | ||
378 | _currentFriction = PhysicsScene.Params.avatarFriction; | ||
379 | BulletSimAPI.SetFriction2(BSBody.ptr, _currentFriction); | ||
380 | } | ||
381 | } | ||
382 | _velocity = value; | ||
383 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
384 | _appliedVelocity = value; | ||
385 | |||
386 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); | ||
387 | BulletSimAPI.Activate2(BSBody.ptr, true); | ||
388 | } | ||
389 | } | ||
335 | public override OMV.Vector3 Torque { | 390 | public override OMV.Vector3 Torque { |
336 | get { return _torque; } | 391 | get { return _torque; } |
337 | set { _torque = value; | 392 | set { _torque = value; |
@@ -353,8 +408,8 @@ public class BSCharacter : BSPhysObject | |||
353 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 408 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); |
354 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 409 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
355 | { | 410 | { |
356 | // _position = BulletSimAPI.GetObjectPosition(Scene.WorldID, _localID); | 411 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); |
357 | BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); | 412 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); |
358 | }); | 413 | }); |
359 | } | 414 | } |
360 | } | 415 | } |
@@ -382,12 +437,18 @@ public class BSCharacter : BSPhysObject | |||
382 | set { _isPhysical = value; | 437 | set { _isPhysical = value; |
383 | } | 438 | } |
384 | } | 439 | } |
440 | public override bool IsSolid { | ||
441 | get { return true; } | ||
442 | } | ||
443 | public override bool IsStatic { | ||
444 | get { return false; } | ||
445 | } | ||
385 | public override bool Flying { | 446 | public override bool Flying { |
386 | get { return _flying; } | 447 | get { return _flying; } |
387 | set { | 448 | set { |
388 | _flying = value; | 449 | _flying = value; |
389 | // simulate flying by changing the effect of gravity | 450 | // simulate flying by changing the effect of gravity |
390 | this.Buoyancy = ComputeBuoyancyFromFlying(_flying); | 451 | Buoyancy = ComputeBuoyancyFromFlying(_flying); |
391 | } | 452 | } |
392 | } | 453 | } |
393 | // Flying is implimented by changing the avatar's buoyancy. | 454 | // Flying is implimented by changing the avatar's buoyancy. |
@@ -432,6 +493,10 @@ public class BSCharacter : BSPhysObject | |||
432 | get { return _rotationalVelocity; } | 493 | get { return _rotationalVelocity; } |
433 | set { _rotationalVelocity = value; } | 494 | set { _rotationalVelocity = value; } |
434 | } | 495 | } |
496 | public override OMV.Vector3 ForceRotationalVelocity { | ||
497 | get { return _rotationalVelocity; } | ||
498 | set { _rotationalVelocity = value; } | ||
499 | } | ||
435 | public override bool Kinematic { | 500 | public override bool Kinematic { |
436 | get { return _kinematic; } | 501 | get { return _kinematic; } |
437 | set { _kinematic = value; } | 502 | set { _kinematic = value; } |
@@ -443,10 +508,19 @@ public class BSCharacter : BSPhysObject | |||
443 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 508 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() |
444 | { | 509 | { |
445 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 510 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
446 | BulletSimAPI.SetObjectBuoyancy(PhysicsScene.WorldID, LocalID, _buoyancy); | 511 | ForceBuoyancy = _buoyancy; |
447 | }); | 512 | }); |
448 | } | 513 | } |
449 | } | 514 | } |
515 | public override float ForceBuoyancy { | ||
516 | get { return _buoyancy; } | ||
517 | set { _buoyancy = value; | ||
518 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
519 | // Buoyancy is faked by changing the gravity applied to the object | ||
520 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
521 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
522 | } | ||
523 | } | ||
450 | 524 | ||
451 | // Used for MoveTo | 525 | // Used for MoveTo |
452 | public override OMV.Vector3 PIDTarget { | 526 | public override OMV.Vector3 PIDTarget { |
@@ -507,27 +581,32 @@ public class BSCharacter : BSPhysObject | |||
507 | 581 | ||
508 | private void ComputeAvatarScale(OMV.Vector3 size) | 582 | private void ComputeAvatarScale(OMV.Vector3 size) |
509 | { | 583 | { |
510 | _scale.X = PhysicsScene.Params.avatarCapsuleRadius; | 584 | // The 'size' given by the simulator is the mid-point of the avatar |
511 | _scale.Y = PhysicsScene.Params.avatarCapsuleRadius; | 585 | // and X and Y are unspecified. |
586 | |||
587 | OMV.Vector3 newScale = OMV.Vector3.Zero; | ||
588 | newScale.X = PhysicsScene.Params.avatarCapsuleRadius; | ||
589 | newScale.Y = PhysicsScene.Params.avatarCapsuleRadius; | ||
512 | 590 | ||
513 | // The 1.15 came from ODE but it seems to cause the avatar to float off the ground | 591 | // From the total height, remote the capsule half spheres that are at each end |
514 | // _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); | 592 | newScale.Z = (size.Z * 2f) - Math.Min(newScale.X, newScale.Y); |
515 | _scale.Z = (_size.Z) - (_scale.X + _scale.Y); | 593 | // newScale.Z = (size.Z * 2f); |
594 | Scale = newScale; | ||
516 | } | 595 | } |
517 | 596 | ||
518 | // set _avatarVolume and _mass based on capsule size, _density and _scale | 597 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
519 | private void ComputeAvatarVolumeAndMass() | 598 | private void ComputeAvatarVolumeAndMass() |
520 | { | 599 | { |
521 | _avatarVolume = (float)( | 600 | _avatarVolume = (float)( |
522 | Math.PI | 601 | Math.PI |
523 | * _scale.X | 602 | * Scale.X |
524 | * _scale.Y // the area of capsule cylinder | 603 | * Scale.Y // the area of capsule cylinder |
525 | * _scale.Z // times height of capsule cylinder | 604 | * Scale.Z // times height of capsule cylinder |
526 | + 1.33333333f | 605 | + 1.33333333f |
527 | * Math.PI | 606 | * Math.PI |
528 | * _scale.X | 607 | * Scale.X |
529 | * Math.Min(_scale.X, _scale.Y) | 608 | * Math.Min(Scale.X, Scale.Y) |
530 | * _scale.Y // plus the volume of the capsule end caps | 609 | * Scale.Y // plus the volume of the capsule end caps |
531 | ); | 610 | ); |
532 | _mass = _avatarDensity * _avatarVolume; | 611 | _mass = _avatarDensity * _avatarVolume; |
533 | } | 612 | } |
@@ -542,7 +621,23 @@ public class BSCharacter : BSPhysObject | |||
542 | _acceleration = entprop.Acceleration; | 621 | _acceleration = entprop.Acceleration; |
543 | _rotationalVelocity = entprop.RotationalVelocity; | 622 | _rotationalVelocity = entprop.RotationalVelocity; |
544 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 623 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
545 | PositionSanityCheck2(true); | 624 | PositionSanityCheck(true); |
625 | |||
626 | // remember the current and last set values | ||
627 | LastEntityProperties = CurrentEntityProperties; | ||
628 | CurrentEntityProperties = entprop; | ||
629 | |||
630 | if (entprop.Velocity != LastEntityProperties.Velocity) | ||
631 | { | ||
632 | // Changes in the velocity are suppressed in avatars. | ||
633 | // That's just the way they are defined. | ||
634 | OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z); | ||
635 | _velocity = avVel; | ||
636 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, avVel); | ||
637 | } | ||
638 | |||
639 | // Tell the linkset about this | ||
640 | Linkset.UpdateProperties(this); | ||
546 | 641 | ||
547 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 642 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
548 | // base.RequestPhysicsterseUpdate(); | 643 | // base.RequestPhysicsterseUpdate(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 63a4127..a20be3a 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -49,9 +49,16 @@ public abstract class BSConstraint : IDisposable | |||
49 | if (m_enabled) | 49 | if (m_enabled) |
50 | { | 50 | { |
51 | m_enabled = false; | 51 | m_enabled = false; |
52 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | 52 | if (m_constraint.ptr != IntPtr.Zero) |
53 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success); | 53 | { |
54 | m_constraint.ptr = System.IntPtr.Zero; | 54 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); |
55 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | ||
56 | BSScene.DetailLogZero, | ||
57 | m_body1.ID, m_body1.ptr.ToString("X"), | ||
58 | m_body2.ID, m_body2.ptr.ToString("X"), | ||
59 | success); | ||
60 | m_constraint.ptr = System.IntPtr.Zero; | ||
61 | } | ||
55 | } | 62 | } |
56 | } | 63 | } |
57 | 64 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 4ba2f62..56342b8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -462,7 +462,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
462 | return; | 462 | return; |
463 | 463 | ||
464 | // Set the prim's inertia to zero. The vehicle code handles that and this | 464 | // Set the prim's inertia to zero. The vehicle code handles that and this |
465 | // removes the torque action introduced by Bullet. | 465 | // removes the motion and torque actions introduced by Bullet. |
466 | Vector3 inertia = Vector3.Zero; | 466 | Vector3 inertia = Vector3.Zero; |
467 | BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); | 467 | BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia); |
468 | BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); | 468 | BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr); |
@@ -481,7 +481,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
481 | m_lastPositionVector = Prim.ForcePosition; | 481 | m_lastPositionVector = Prim.ForcePosition; |
482 | 482 | ||
483 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 483 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
484 | Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity); | 484 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); |
485 | }// end Step | 485 | }// end Step |
486 | 486 | ||
487 | // Apply the effect of the linear motor. | 487 | // Apply the effect of the linear motor. |
@@ -540,7 +540,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
540 | // add Gravity and Buoyancy | 540 | // add Gravity and Buoyancy |
541 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 541 | // There is some gravity, make a gravity force vector that is applied after object velocity. |
542 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 542 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
543 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy)); | 543 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Linkset.LinksetMass * (1f - m_VehicleBuoyancy)); |
544 | 544 | ||
545 | /* | 545 | /* |
546 | * RA: Not sure why one would do this | 546 | * RA: Not sure why one would do this |
@@ -678,10 +678,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
678 | m_newVelocity.Z = 0; | 678 | m_newVelocity.Z = 0; |
679 | 679 | ||
680 | // Apply velocity | 680 | // Apply velocity |
681 | Prim.Velocity = m_newVelocity; | 681 | Prim.ForceVelocity = m_newVelocity; |
682 | // apply gravity force | 682 | // apply gravity force |
683 | // Why is this set here? The physics engine already does gravity. | 683 | // Why is this set here? The physics engine already does gravity. |
684 | // m_prim.AddForce(grav, false); | 684 | Prim.AddForce(grav, false, true); |
685 | 685 | ||
686 | // Apply friction | 686 | // Apply friction |
687 | Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); | 687 | Vector3 keepFraction = Vector3.One - (Vector3.One / (m_linearFrictionTimescale / pTimestep)); |
@@ -704,7 +704,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
704 | // m_lastAngularVelocity // what was last applied to body | 704 | // m_lastAngularVelocity // what was last applied to body |
705 | 705 | ||
706 | // Get what the body is doing, this includes 'external' influences | 706 | // Get what the body is doing, this includes 'external' influences |
707 | Vector3 angularVelocity = Prim.RotationalVelocity; | 707 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; |
708 | 708 | ||
709 | if (m_angularMotorApply > 0) | 709 | if (m_angularMotorApply > 0) |
710 | { | 710 | { |
@@ -810,7 +810,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
810 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; | 810 | m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; |
811 | 811 | ||
812 | // Apply to the body | 812 | // Apply to the body |
813 | Prim.RotationalVelocity = m_lastAngularVelocity; | 813 | Prim.ForceRotationalVelocity = m_lastAngularVelocity; |
814 | 814 | ||
815 | VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); | 815 | VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity); |
816 | } //end MoveAngular | 816 | } //end MoveAngular |
@@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
862 | private void VDetailLog(string msg, params Object[] args) | 862 | private void VDetailLog(string msg, params Object[] args) |
863 | { | 863 | { |
864 | if (Prim.PhysicsScene.VehicleLoggingEnabled) | 864 | if (Prim.PhysicsScene.VehicleLoggingEnabled) |
865 | Prim.PhysicsScene.PhysicsLogging.Write(msg, args); | 865 | Prim.PhysicsScene.DetailLog(msg, args); |
866 | } | 866 | } |
867 | } | 867 | } |
868 | } | 868 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 3e82642..43b1262 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -52,8 +52,8 @@ public class BSLinkset | |||
52 | // the physical 'taint' children separately. | 52 | // the physical 'taint' children separately. |
53 | // After taint processing and before the simulation step, these | 53 | // After taint processing and before the simulation step, these |
54 | // two lists must be the same. | 54 | // two lists must be the same. |
55 | private List<BSPhysObject> m_children; | 55 | private HashSet<BSPhysObject> m_children; |
56 | private List<BSPhysObject> m_taintChildren; | 56 | private HashSet<BSPhysObject> m_taintChildren; |
57 | 57 | ||
58 | // We lock the diddling of linkset classes to prevent any badness. | 58 | // We lock the diddling of linkset classes to prevent any badness. |
59 | // This locks the modification of the instances of this class. Changes | 59 | // This locks the modification of the instances of this class. Changes |
@@ -90,8 +90,8 @@ public class BSLinkset | |||
90 | m_nextLinksetID = 1; | 90 | m_nextLinksetID = 1; |
91 | PhysicsScene = scene; | 91 | PhysicsScene = scene; |
92 | LinksetRoot = parent; | 92 | LinksetRoot = parent; |
93 | m_children = new List<BSPhysObject>(); | 93 | m_children = new HashSet<BSPhysObject>(); |
94 | m_taintChildren = new List<BSPhysObject>(); | 94 | m_taintChildren = new HashSet<BSPhysObject>(); |
95 | m_mass = parent.MassRaw; | 95 | m_mass = parent.MassRaw; |
96 | } | 96 | } |
97 | 97 | ||
@@ -160,6 +160,28 @@ public class BSLinkset | |||
160 | return ret; | 160 | return ret; |
161 | } | 161 | } |
162 | 162 | ||
163 | // When physical properties are changed the linkset needs to recalculate | ||
164 | // its internal properties. | ||
165 | // May be called at runtime or taint-time (just pass the appropriate flag). | ||
166 | public void Refresh(BSPhysObject requestor, bool inTaintTime) | ||
167 | { | ||
168 | // If there are no children, not physical or not root, I am not the one that recomputes the constraints | ||
169 | // (For the moment, static linksets do create constraints so remove the test for physical.) | ||
170 | if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor)) | ||
171 | return; | ||
172 | |||
173 | BSScene.TaintCallback refreshOperation = delegate() | ||
174 | { | ||
175 | RecomputeLinksetConstraintVariables(); | ||
176 | DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}", | ||
177 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); | ||
178 | }; | ||
179 | if (inTaintTime) | ||
180 | refreshOperation(); | ||
181 | else | ||
182 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation); | ||
183 | } | ||
184 | |||
163 | // The object is going dynamic (physical). Do any setup necessary | 185 | // The object is going dynamic (physical). Do any setup necessary |
164 | // for a dynamic linkset. | 186 | // for a dynamic linkset. |
165 | // Only the state of the passed object can be modified. The rest of the linkset | 187 | // Only the state of the passed object can be modified. The rest of the linkset |
@@ -182,22 +204,19 @@ public class BSLinkset | |||
182 | return false; | 204 | return false; |
183 | } | 205 | } |
184 | 206 | ||
185 | // When physical properties are changed the linkset needs to recalculate | 207 | // If the software is handling the movement of all the objects in a linkset |
186 | // its internal properties. | 208 | // (like if one doesn't use constraints for static linksets), this is called |
187 | // Called at runtime. | 209 | // when an update for the root of the linkset is received. |
188 | public void Refresh(BSPhysObject requestor) | 210 | // Called at taint-time!! |
211 | public void UpdateProperties(BSPhysObject physObject) | ||
189 | { | 212 | { |
190 | // If there are no children, there can't be any constraints to recompute | 213 | // The root local properties have been updated. Apply to the children if appropriate. |
191 | if (!HasAnyChildren) | 214 | if (IsRoot(physObject) && HasAnyChildren) |
192 | return; | ||
193 | |||
194 | // Only the root does the recomputation | ||
195 | if (IsRoot(requestor)) | ||
196 | { | 215 | { |
197 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() | 216 | if (!physObject.IsPhysical) |
198 | { | 217 | { |
199 | RecomputeLinksetConstraintVariables(); | 218 | // TODO: implement software linkset update for static object linksets |
200 | }); | 219 | } |
201 | } | 220 | } |
202 | } | 221 | } |
203 | 222 | ||
@@ -215,13 +234,10 @@ public class BSLinkset | |||
215 | if (IsRoot(child)) | 234 | if (IsRoot(child)) |
216 | { | 235 | { |
217 | // If the one with the dependency is root, must undo all children | 236 | // If the one with the dependency is root, must undo all children |
218 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}", | 237 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
219 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); | 238 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); |
220 | foreach (BSPhysObject bpo in m_taintChildren) | 239 | |
221 | { | 240 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
222 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); | ||
223 | ret = true; | ||
224 | } | ||
225 | } | 241 | } |
226 | else | 242 | else |
227 | { | 243 | { |
@@ -229,20 +245,16 @@ public class BSLinkset | |||
229 | child.LocalID, | 245 | child.LocalID, |
230 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | 246 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), |
231 | child.LocalID, child.BSBody.ptr.ToString("X")); | 247 | child.LocalID, child.BSBody.ptr.ToString("X")); |
232 | // Remove the dependency on the body of this one | 248 | // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child); |
233 | if (m_taintChildren.Contains(child)) | 249 | // Despite the function name, this removes any link to the specified object. |
234 | { | 250 | ret = PhysicallyUnlinkAllChildrenFromRoot(child); |
235 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); | ||
236 | ret = true; | ||
237 | } | ||
238 | } | 251 | } |
239 | } | 252 | } |
240 | return ret; | 253 | return ret; |
241 | } | 254 | } |
242 | 255 | ||
243 | // Routine used when rebuilding the body of the root of the linkset | 256 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
244 | // This is called after RemoveAllLinksToRoot() to restore all the constraints. | 257 | // this routine will restore the removed constraints. |
245 | // This is called when the root body has been changed. | ||
246 | // Called at taint-time!! | 258 | // Called at taint-time!! |
247 | public void RestoreBodyDependencies(BSPrim child) | 259 | public void RestoreBodyDependencies(BSPrim child) |
248 | { | 260 | { |
@@ -254,7 +266,7 @@ public class BSLinkset | |||
254 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); | 266 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); |
255 | foreach (BSPhysObject bpo in m_taintChildren) | 267 | foreach (BSPhysObject bpo in m_taintChildren) |
256 | { | 268 | { |
257 | PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); | 269 | PhysicallyLinkAChildToRoot(LinksetRoot, bpo); |
258 | } | 270 | } |
259 | } | 271 | } |
260 | else | 272 | else |
@@ -263,7 +275,7 @@ public class BSLinkset | |||
263 | LinksetRoot.LocalID, | 275 | LinksetRoot.LocalID, |
264 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | 276 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), |
265 | child.LocalID, child.BSBody.ptr.ToString("X")); | 277 | child.LocalID, child.BSBody.ptr.ToString("X")); |
266 | PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); | 278 | PhysicallyLinkAChildToRoot(LinksetRoot, child); |
267 | } | 279 | } |
268 | } | 280 | } |
269 | } | 281 | } |
@@ -330,22 +342,22 @@ public class BSLinkset | |||
330 | { | 342 | { |
331 | m_children.Add(child); | 343 | m_children.Add(child); |
332 | 344 | ||
333 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | 345 | BSPhysObject rootx = LinksetRoot; // capture the root as of now |
334 | BSPhysObject childx = child; | 346 | BSPhysObject childx = child; |
335 | 347 | ||
336 | DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 348 | DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
337 | rootx.LocalID, | ||
338 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | ||
339 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | ||
340 | 349 | ||
341 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() | 350 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() |
342 | { | 351 | { |
343 | DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); | 352 | DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}", |
344 | // build the physical binding between me and the child | 353 | rootx.LocalID, |
345 | m_taintChildren.Add(childx); | 354 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), |
346 | 355 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | |
347 | // Since this is taint-time, the body and shape could have changed for the child | 356 | // Since this is taint-time, the body and shape could have changed for the child |
348 | PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); | 357 | rootx.ForcePosition = rootx.Position; // DEBUG |
358 | childx.ForcePosition = childx.Position; // DEBUG | ||
359 | PhysicallyLinkAChildToRoot(rootx, childx); | ||
360 | m_taintChildren.Add(child); | ||
349 | }); | 361 | }); |
350 | } | 362 | } |
351 | return; | 363 | return; |
@@ -378,10 +390,8 @@ public class BSLinkset | |||
378 | 390 | ||
379 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | 391 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() |
380 | { | 392 | { |
381 | if (m_taintChildren.Contains(childx)) | 393 | m_taintChildren.Remove(child); |
382 | m_taintChildren.Remove(childx); | 394 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
383 | |||
384 | PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody); | ||
385 | RecomputeLinksetConstraintVariables(); | 395 | RecomputeLinksetConstraintVariables(); |
386 | }); | 396 | }); |
387 | 397 | ||
@@ -396,8 +406,7 @@ public class BSLinkset | |||
396 | 406 | ||
397 | // Create a constraint between me (root of linkset) and the passed prim (the child). | 407 | // Create a constraint between me (root of linkset) and the passed prim (the child). |
398 | // Called at taint time! | 408 | // Called at taint time! |
399 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, | 409 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
400 | BSPhysObject childPrim, BulletBody childBody) | ||
401 | { | 410 | { |
402 | // Zero motion for children so they don't interpolate | 411 | // Zero motion for children so they don't interpolate |
403 | childPrim.ZeroMotion(); | 412 | childPrim.ZeroMotion(); |
@@ -409,33 +418,17 @@ public class BSLinkset | |||
409 | // real world coordinate of midpoint between the two objects | 418 | // real world coordinate of midpoint between the two objects |
410 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | 419 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); |
411 | 420 | ||
412 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 421 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", |
413 | rootPrim.LocalID, | 422 | rootPrim.LocalID, |
414 | rootPrim.LocalID, rootBody.ptr.ToString("X"), | 423 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), |
415 | childPrim.LocalID, childBody.ptr.ToString("X"), | 424 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"), |
416 | rootPrim.Position, childPrim.Position, midPoint); | 425 | rootPrim.Position, childPrim.Position, midPoint); |
417 | 426 | ||
418 | // create a constraint that allows no freedom of movement between the two objects | 427 | // create a constraint that allows no freedom of movement between the two objects |
419 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 428 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
420 | 429 | ||
421 | // There is great subtlty in these paramters. Notice the check for a ptr of zero. | ||
422 | // We pass the BulletBody structure into the taint in order to capture the pointer | ||
423 | // of the body at the time of constraint creation. This doesn't work for the very first | ||
424 | // construction because there is no body yet. The body | ||
425 | // is constructed later at taint time. Thus we use the body address at time of the | ||
426 | // taint creation but, if it is zero, use what's in the prim at the moment. | ||
427 | // There is a possible race condition since shape can change without a taint call | ||
428 | // (like changing to a mesh that is already constructed). The fix for that would be | ||
429 | // to only change BSShape at taint time thus syncronizing these operations at | ||
430 | // the cost of efficiency and lag. | ||
431 | BS6DofConstraint constrain = new BS6DofConstraint( | 430 | BS6DofConstraint constrain = new BS6DofConstraint( |
432 | PhysicsScene.World, | 431 | PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true ); |
433 | rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody, | ||
434 | childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody, | ||
435 | midPoint, | ||
436 | true, | ||
437 | true | ||
438 | ); | ||
439 | 432 | ||
440 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 433 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
441 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | 434 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms |
@@ -452,7 +445,7 @@ public class BSLinkset | |||
452 | 445 | ||
453 | // create a constraint that allows no freedom of movement between the two objects | 446 | // create a constraint that allows no freedom of movement between the two objects |
454 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 447 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
455 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | 448 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
456 | BS6DofConstraint constrain = new BS6DofConstraint( | 449 | BS6DofConstraint constrain = new BS6DofConstraint( |
457 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | 450 | PhysicsScene.World, rootPrim.Body, childPrim.Body, |
458 | OMV.Vector3.Zero, | 451 | OMV.Vector3.Zero, |
@@ -486,39 +479,44 @@ public class BSLinkset | |||
486 | { | 479 | { |
487 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | 480 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); |
488 | } | 481 | } |
489 | |||
490 | RecomputeLinksetConstraintVariables(); | ||
491 | } | 482 | } |
492 | 483 | ||
493 | // Remove linkage between myself and a particular child | 484 | // Remove linkage between myself and a particular child |
494 | // The root and child bodies are passed in because we need to remove the constraint between | 485 | // The root and child bodies are passed in because we need to remove the constraint between |
495 | // the bodies that were at unlink time. | 486 | // the bodies that were at unlink time. |
496 | // Called at taint time! | 487 | // Called at taint time! |
497 | private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, | 488 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
498 | BSPhysObject childPrim, BulletBody childBody) | ||
499 | { | 489 | { |
500 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 490 | bool ret = false; |
491 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
501 | rootPrim.LocalID, | 492 | rootPrim.LocalID, |
502 | rootPrim.LocalID, rootBody.ptr.ToString("X"), | 493 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), |
503 | childPrim.LocalID, childBody.ptr.ToString("X")); | 494 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X")); |
504 | 495 | ||
505 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 496 | // Find the constraint for this link and get rid of it from the overall collection and from my list |
506 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); | 497 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody)) |
498 | { | ||
499 | // Make the child refresh its location | ||
500 | BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); | ||
501 | ret = true; | ||
502 | } | ||
507 | 503 | ||
508 | // Make the child refresh its location | 504 | return ret; |
509 | BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); | ||
510 | } | 505 | } |
511 | 506 | ||
512 | /* | ||
513 | // Remove linkage between myself and any possible children I might have. | 507 | // Remove linkage between myself and any possible children I might have. |
514 | // Called at taint time! | 508 | // Called at taint time! |
515 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | 509 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) |
516 | { | 510 | { |
517 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 511 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
512 | bool ret = false; | ||
518 | 513 | ||
519 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); | 514 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody)) |
515 | { | ||
516 | ret = true; | ||
517 | } | ||
518 | return ret; | ||
520 | } | 519 | } |
521 | */ | ||
522 | 520 | ||
523 | // Call each of the constraints that make up this linkset and recompute the | 521 | // Call each of the constraints that make up this linkset and recompute the |
524 | // various transforms and variables. Used when objects are added or removed | 522 | // various transforms and variables. Used when objects are added or removed |
@@ -550,11 +548,17 @@ public class BSLinkset | |||
550 | { | 548 | { |
551 | // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass | 549 | // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass |
552 | OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); | 550 | OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); |
553 | BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | 551 | BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, |
552 | centerOfMass, OMV.Quaternion.Identity); | ||
553 | DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}", | ||
554 | LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X")); | ||
554 | foreach (BSPhysObject child in m_taintChildren) | 555 | foreach (BSPhysObject child in m_taintChildren) |
555 | { | 556 | { |
556 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | 557 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, |
558 | centerOfMass, OMV.Quaternion.Identity); | ||
557 | } | 559 | } |
560 | |||
561 | // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG | ||
558 | } | 562 | } |
559 | return; | 563 | return; |
560 | } | 564 | } |
@@ -563,7 +567,8 @@ public class BSLinkset | |||
563 | // Invoke the detailed logger and output something if it's enabled. | 567 | // Invoke the detailed logger and output something if it's enabled. |
564 | private void DetailLog(string msg, params Object[] args) | 568 | private void DetailLog(string msg, params Object[] args) |
565 | { | 569 | { |
566 | PhysicsScene.PhysicsLogging.Write(msg, args); | 570 | if (PhysicsScene.PhysicsLogging.Enabled) |
571 | PhysicsScene.DetailLog(msg, args); | ||
567 | } | 572 | } |
568 | 573 | ||
569 | } | 574 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index 1ac8c59..ead6a08 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -47,6 +47,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
47 | TypeName = typeName; | 47 | TypeName = typeName; |
48 | 48 | ||
49 | Linkset = new BSLinkset(PhysicsScene, this); | 49 | Linkset = new BSLinkset(PhysicsScene, this); |
50 | LastAssetBuildFailed = false; | ||
50 | 51 | ||
51 | CollisionCollection = new CollisionEventUpdate(); | 52 | CollisionCollection = new CollisionEventUpdate(); |
52 | SubscribedEventsMs = 0; | 53 | SubscribedEventsMs = 0; |
@@ -69,6 +70,23 @@ public abstract class BSPhysObject : PhysicsActor | |||
69 | // Reference to the physical shape (btCollisionShape) of this object | 70 | // Reference to the physical shape (btCollisionShape) of this object |
70 | public BulletShape BSShape; | 71 | public BulletShape BSShape; |
71 | 72 | ||
73 | // 'true' if the mesh's underlying asset failed to build. | ||
74 | // This will keep us from looping after the first time the build failed. | ||
75 | public bool LastAssetBuildFailed { get; set; } | ||
76 | |||
77 | // The objects base shape information. Null if not a prim type shape. | ||
78 | public PrimitiveBaseShape BaseShape { get; protected set; } | ||
79 | |||
80 | // When the physical properties are updated, an EntityProperty holds the update values. | ||
81 | // Keep the current and last EntityProperties to enable computation of differences | ||
82 | // between the current update and the previous values. | ||
83 | public EntityProperties CurrentEntityProperties { get; set; } | ||
84 | public EntityProperties LastEntityProperties { get; set; } | ||
85 | |||
86 | public abstract OMV.Vector3 Scale { get; set; } | ||
87 | public abstract bool IsSolid { get; } | ||
88 | public abstract bool IsStatic { get; } | ||
89 | |||
72 | // Stop all physical motion. | 90 | // Stop all physical motion. |
73 | public abstract void ZeroMotion(); | 91 | public abstract void ZeroMotion(); |
74 | 92 | ||
@@ -85,6 +103,14 @@ public abstract class BSPhysObject : PhysicsActor | |||
85 | 103 | ||
86 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 104 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
87 | 105 | ||
106 | public abstract OMV.Vector3 ForceVelocity { get; set; } | ||
107 | |||
108 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | ||
109 | |||
110 | public abstract float ForceBuoyancy { get; set; } | ||
111 | |||
112 | public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } | ||
113 | |||
88 | #region Collisions | 114 | #region Collisions |
89 | 115 | ||
90 | // Requested number of milliseconds between collision events. Zero means disabled. | 116 | // Requested number of milliseconds between collision events. Zero means disabled. |
@@ -125,30 +151,28 @@ public abstract class BSPhysObject : PhysicsActor | |||
125 | // if someone has subscribed for collision events.... | 151 | // if someone has subscribed for collision events.... |
126 | if (SubscribedEvents()) { | 152 | if (SubscribedEvents()) { |
127 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); | 153 | CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); |
128 | // DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", | 154 | DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", |
129 | // LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); | 155 | LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); |
130 | 156 | ||
131 | ret = true; | 157 | ret = true; |
132 | } | 158 | } |
133 | return ret; | 159 | return ret; |
134 | } | 160 | } |
135 | 161 | ||
136 | // Routine to send the collected collisions into the simulator. | 162 | // Send the collected collisions into the simulator. |
137 | // Also handles removal of this from the collection of objects with collisions if | ||
138 | // there are no collisions from this object. Mechanism is create one last | ||
139 | // collision event to make collision_end work. | ||
140 | // Called at taint time from within the Step() function thus no locking problems | 163 | // Called at taint time from within the Step() function thus no locking problems |
141 | // with CollisionCollection and ObjectsWithNoMoreCollisions. | 164 | // with CollisionCollection and ObjectsWithNoMoreCollisions. |
142 | // Return 'true' if there were some actual collisions passed up | 165 | // Return 'true' if there were some actual collisions passed up |
143 | public virtual bool SendCollisions() | 166 | public virtual bool SendCollisions() |
144 | { | 167 | { |
145 | bool ret = true; | 168 | bool ret = true; |
169 | // If the 'no collision' call, force it to happen right now so quick collision_end | ||
170 | bool force = CollisionCollection.Count == 0; | ||
146 | 171 | ||
147 | // throttle the collisions to the number of milliseconds specified in the subscription | 172 | // throttle the collisions to the number of milliseconds specified in the subscription |
148 | int nowTime = PhysicsScene.SimulationNowTime; | 173 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) |
149 | if (nowTime >= NextCollisionOkTime) | ||
150 | { | 174 | { |
151 | NextCollisionOkTime = nowTime + SubscribedEventsMs; | 175 | NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs; |
152 | 176 | ||
153 | // We are called if we previously had collisions. If there are no collisions | 177 | // We are called if we previously had collisions. If there are no collisions |
154 | // this time, send up one last empty event so OpenSim can sense collision end. | 178 | // this time, send up one last empty event so OpenSim can sense collision end. |
@@ -207,7 +231,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
207 | // High performance detailed logging routine used by the physical objects. | 231 | // High performance detailed logging routine used by the physical objects. |
208 | protected void DetailLog(string msg, params Object[] args) | 232 | protected void DetailLog(string msg, params Object[] args) |
209 | { | 233 | { |
210 | PhysicsScene.PhysicsLogging.Write(msg, args); | 234 | if (PhysicsScene.PhysicsLogging.Enabled) |
235 | PhysicsScene.DetailLog(msg, args); | ||
211 | } | 236 | } |
212 | } | 237 | } |
213 | } | 238 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index f7b68ba..aeeb4dd 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -46,12 +46,10 @@ public sealed class BSPrim : BSPhysObject | |||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
47 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 47 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
48 | 48 | ||
49 | private PrimitiveBaseShape _pbs; | 49 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
50 | 50 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | |
51 | // _size is what the user passed. _scale is what we pass to the physics engine with the mesh. | ||
52 | // Often _scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
53 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 51 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
54 | private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer | 52 | // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer |
55 | 53 | ||
56 | private bool _grabbed; | 54 | private bool _grabbed; |
57 | private bool _isSelected; | 55 | private bool _isSelected; |
@@ -98,12 +96,12 @@ public sealed class BSPrim : BSPhysObject | |||
98 | _physicsActorType = (int)ActorTypes.Prim; | 96 | _physicsActorType = (int)ActorTypes.Prim; |
99 | _position = pos; | 97 | _position = pos; |
100 | _size = size; | 98 | _size = size; |
101 | _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type | 99 | Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type |
102 | _orientation = rotation; | 100 | _orientation = rotation; |
103 | _buoyancy = 1f; | 101 | _buoyancy = 1f; |
104 | _velocity = OMV.Vector3.Zero; | 102 | _velocity = OMV.Vector3.Zero; |
105 | _rotationalVelocity = OMV.Vector3.Zero; | 103 | _rotationalVelocity = OMV.Vector3.Zero; |
106 | _pbs = pbs; | 104 | BaseShape = pbs; |
107 | _isPhysical = pisPhysical; | 105 | _isPhysical = pisPhysical; |
108 | _isVolumeDetect = false; | 106 | _isVolumeDetect = false; |
109 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material | 107 | _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material |
@@ -160,33 +158,32 @@ public sealed class BSPrim : BSPhysObject | |||
160 | get { return _size; } | 158 | get { return _size; } |
161 | set { | 159 | set { |
162 | _size = value; | 160 | _size = value; |
163 | PhysicsScene.TaintedObject("BSPrim.setSize", delegate() | 161 | ForceBodyShapeRebuild(false); |
164 | { | ||
165 | _mass = CalculateMass(); // changing size changes the mass | ||
166 | // Since _size changed, the mesh needs to be rebuilt. If rebuilt, all the correct | ||
167 | // scale and margins are set. | ||
168 | CreateGeomAndObject(true); | ||
169 | // DetailLog("{0},BSPrim.setSize,size={1},scale={2},mass={3},physical={4}", LocalID, _size, _scale, _mass, IsPhysical); | ||
170 | }); | ||
171 | } | 162 | } |
172 | } | 163 | } |
173 | // Scale is what we set in the physics engine. It is different than 'size' in that | 164 | // Scale is what we set in the physics engine. It is different than 'size' in that |
174 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | 165 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. |
175 | public OMV.Vector3 Scale | 166 | public override OMV.Vector3 Scale { get; set; } |
176 | { | 167 | |
177 | get { return _scale; } | ||
178 | set { _scale = value; } | ||
179 | } | ||
180 | public override PrimitiveBaseShape Shape { | 168 | public override PrimitiveBaseShape Shape { |
181 | set { | 169 | set { |
182 | _pbs = value; | 170 | BaseShape = value; |
183 | PhysicsScene.TaintedObject("BSPrim.setShape", delegate() | 171 | ForceBodyShapeRebuild(false); |
184 | { | ||
185 | _mass = CalculateMass(); // changing the shape changes the mass | ||
186 | CreateGeomAndObject(true); | ||
187 | }); | ||
188 | } | 172 | } |
189 | } | 173 | } |
174 | public override bool ForceBodyShapeRebuild(bool inTaintTime) | ||
175 | { | ||
176 | BSScene.TaintCallback rebuildOperation = delegate() | ||
177 | { | ||
178 | _mass = CalculateMass(); // changing the shape changes the mass | ||
179 | CreateGeomAndObject(true); | ||
180 | }; | ||
181 | if (inTaintTime) | ||
182 | rebuildOperation(); | ||
183 | else | ||
184 | PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation); | ||
185 | return true; | ||
186 | } | ||
190 | public override bool Grabbed { | 187 | public override bool Grabbed { |
191 | set { _grabbed = value; | 188 | set { _grabbed = value; |
192 | } | 189 | } |
@@ -196,7 +193,7 @@ public sealed class BSPrim : BSPhysObject | |||
196 | _isSelected = value; | 193 | _isSelected = value; |
197 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
198 | { | 195 | { |
199 | // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); |
200 | SetObjectDynamic(false); | 197 | SetObjectDynamic(false); |
201 | }); | 198 | }); |
202 | } | 199 | } |
@@ -265,6 +262,11 @@ public sealed class BSPrim : BSPhysObject | |||
265 | return _position; | 262 | return _position; |
266 | } | 263 | } |
267 | set { | 264 | set { |
265 | // If you must push the position into the physics engine, use ForcePosition. | ||
266 | if (_position == value) | ||
267 | { | ||
268 | return; | ||
269 | } | ||
268 | _position = value; | 270 | _position = value; |
269 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | 271 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? |
270 | PositionSanityCheck(); | 272 | PositionSanityCheck(); |
@@ -320,9 +322,9 @@ public sealed class BSPrim : BSPhysObject | |||
320 | } | 322 | } |
321 | 323 | ||
322 | // A version of the sanity check that also makes sure a new position value is | 324 | // A version of the sanity check that also makes sure a new position value is |
323 | // pushed back to the physics engine. This routine would be used by anyone | 325 | // pushed to the physics engine. This routine would be used by anyone |
324 | // who is not already pushing the value. | 326 | // who is not already pushing the value. |
325 | private bool PositionSanityCheck2(bool atTaintTime) | 327 | private bool PositionSanityCheck(bool inTaintTime) |
326 | { | 328 | { |
327 | bool ret = false; | 329 | bool ret = false; |
328 | if (PositionSanityCheck()) | 330 | if (PositionSanityCheck()) |
@@ -332,9 +334,9 @@ public sealed class BSPrim : BSPhysObject | |||
332 | BSScene.TaintCallback sanityOperation = delegate() | 334 | BSScene.TaintCallback sanityOperation = delegate() |
333 | { | 335 | { |
334 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 336 | DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
335 | BulletSimAPI.SetObjectTranslation(PhysicsScene.WorldID, LocalID, _position, _orientation); | 337 | ForcePosition = _position; |
336 | }; | 338 | }; |
337 | if (atTaintTime) | 339 | if (inTaintTime) |
338 | sanityOperation(); | 340 | sanityOperation(); |
339 | else | 341 | else |
340 | PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); | 342 | PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation); |
@@ -453,7 +455,6 @@ public sealed class BSPrim : BSPhysObject | |||
453 | } | 455 | } |
454 | return; | 456 | return; |
455 | } | 457 | } |
456 | |||
457 | public override OMV.Vector3 Velocity { | 458 | public override OMV.Vector3 Velocity { |
458 | get { return _velocity; } | 459 | get { return _velocity; } |
459 | set { | 460 | set { |
@@ -465,6 +466,13 @@ public sealed class BSPrim : BSPhysObject | |||
465 | }); | 466 | }); |
466 | } | 467 | } |
467 | } | 468 | } |
469 | public override OMV.Vector3 ForceVelocity { | ||
470 | get { return _velocity; } | ||
471 | set { | ||
472 | _velocity = value; | ||
473 | BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity); | ||
474 | } | ||
475 | } | ||
468 | public override OMV.Vector3 Torque { | 476 | public override OMV.Vector3 Torque { |
469 | get { return _torque; } | 477 | get { return _torque; } |
470 | set { _torque = value; | 478 | set { _torque = value; |
@@ -490,6 +498,8 @@ public sealed class BSPrim : BSPhysObject | |||
490 | return _orientation; | 498 | return _orientation; |
491 | } | 499 | } |
492 | set { | 500 | set { |
501 | if (_orientation == value) | ||
502 | return; | ||
493 | _orientation = value; | 503 | _orientation = value; |
494 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 504 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
495 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 505 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
@@ -534,13 +544,13 @@ public sealed class BSPrim : BSPhysObject | |||
534 | } | 544 | } |
535 | 545 | ||
536 | // An object is static (does not move) if selected or not physical | 546 | // An object is static (does not move) if selected or not physical |
537 | private bool IsStatic | 547 | public override bool IsStatic |
538 | { | 548 | { |
539 | get { return _isSelected || !IsPhysical; } | 549 | get { return _isSelected || !IsPhysical; } |
540 | } | 550 | } |
541 | 551 | ||
542 | // An object is solid if it's not phantom and if it's not doing VolumeDetect | 552 | // An object is solid if it's not phantom and if it's not doing VolumeDetect |
543 | public bool IsSolid | 553 | public override bool IsSolid |
544 | { | 554 | { |
545 | get { return !IsPhantom && !_isVolumeDetect; } | 555 | get { return !IsPhantom && !_isVolumeDetect; } |
546 | } | 556 | } |
@@ -570,7 +580,7 @@ public sealed class BSPrim : BSPhysObject | |||
570 | // Set up the object physicalness (does gravity and collisions move this object) | 580 | // Set up the object physicalness (does gravity and collisions move this object) |
571 | MakeDynamic(IsStatic); | 581 | MakeDynamic(IsStatic); |
572 | 582 | ||
573 | // Update vehicle specific parameters | 583 | // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) |
574 | _vehicle.Refresh(); | 584 | _vehicle.Refresh(); |
575 | 585 | ||
576 | // Arrange for collision events if the simulator wants them | 586 | // Arrange for collision events if the simulator wants them |
@@ -593,7 +603,7 @@ public sealed class BSPrim : BSPhysObject | |||
593 | // Recompute any linkset parameters. | 603 | // Recompute any linkset parameters. |
594 | // When going from non-physical to physical, this re-enables the constraints that | 604 | // When going from non-physical to physical, this re-enables the constraints that |
595 | // had been automatically disabled when the mass was set to zero. | 605 | // had been automatically disabled when the mass was set to zero. |
596 | Linkset.Refresh(this); | 606 | Linkset.Refresh(this, true); |
597 | 607 | ||
598 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", | 608 | DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", |
599 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); | 609 | LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape); |
@@ -618,10 +628,18 @@ public sealed class BSPrim : BSPhysObject | |||
618 | BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); | 628 | BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero); |
619 | // There is no inertia in a static object | 629 | // There is no inertia in a static object |
620 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | 630 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); |
631 | // Set collision detection parameters | ||
632 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
633 | { | ||
634 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
635 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
636 | } | ||
621 | // There can be special things needed for implementing linksets | 637 | // There can be special things needed for implementing linksets |
622 | Linkset.MakeStatic(this); | 638 | Linkset.MakeStatic(this); |
623 | // The activation state is 'disabled' so Bullet will not try to act on it | 639 | // The activation state is 'disabled' so Bullet will not try to act on it. |
624 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); | 640 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION); |
641 | // Start it out sleeping and physical actions could wake it up. | ||
642 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | ||
625 | 643 | ||
626 | BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 644 | BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; |
627 | BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 645 | BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; |
@@ -638,12 +656,22 @@ public sealed class BSPrim : BSPhysObject | |||
638 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 656 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
639 | BulletSimAPI.ClearAllForces2(BSBody.ptr); | 657 | BulletSimAPI.ClearAllForces2(BSBody.ptr); |
640 | 658 | ||
659 | // For good measure, make sure the transform is set through to the motion state | ||
660 | BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation); | ||
661 | |||
641 | // A dynamic object has mass | 662 | // A dynamic object has mass |
642 | IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); | 663 | IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); |
643 | OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); | 664 | OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass); |
644 | BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); | 665 | BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); |
645 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); | 666 | BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); |
646 | 667 | ||
668 | // Set collision detection parameters | ||
669 | if (PhysicsScene.Params.ccdMotionThreshold > 0f) | ||
670 | { | ||
671 | BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | ||
672 | BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | ||
673 | } | ||
674 | |||
647 | // Various values for simulation limits | 675 | // Various values for simulation limits |
648 | BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); | 676 | BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); |
649 | BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); | 677 | BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime); |
@@ -655,8 +683,8 @@ public sealed class BSPrim : BSPhysObject | |||
655 | 683 | ||
656 | // Force activation of the object so Bullet will act on it. | 684 | // Force activation of the object so Bullet will act on it. |
657 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 685 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
658 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 686 | BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); |
659 | BulletSimAPI.Activate2(BSBody.ptr, true); | 687 | // BulletSimAPI.Activate2(BSBody.ptr, true); |
660 | 688 | ||
661 | BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 689 | BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; |
662 | BSBody.collisionMask = CollisionFilterGroups.ObjectMask; | 690 | BSBody.collisionMask = CollisionFilterGroups.ObjectMask; |
@@ -774,6 +802,15 @@ public sealed class BSPrim : BSPhysObject | |||
774 | }); | 802 | }); |
775 | } | 803 | } |
776 | } | 804 | } |
805 | public override OMV.Vector3 ForceRotationalVelocity { | ||
806 | get { | ||
807 | return _rotationalVelocity; | ||
808 | } | ||
809 | set { | ||
810 | _rotationalVelocity = value; | ||
811 | BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity); | ||
812 | } | ||
813 | } | ||
777 | public override bool Kinematic { | 814 | public override bool Kinematic { |
778 | get { return _kinematic; } | 815 | get { return _kinematic; } |
779 | set { _kinematic = value; | 816 | set { _kinematic = value; |
@@ -786,13 +823,20 @@ public sealed class BSPrim : BSPhysObject | |||
786 | _buoyancy = value; | 823 | _buoyancy = value; |
787 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() | 824 | PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate() |
788 | { | 825 | { |
789 | // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 826 | ForceBuoyancy = _buoyancy; |
790 | // Buoyancy is faked by changing the gravity applied to the object | ||
791 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
792 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
793 | }); | 827 | }); |
794 | } | 828 | } |
795 | } | 829 | } |
830 | public override float ForceBuoyancy { | ||
831 | get { return _buoyancy; } | ||
832 | set { | ||
833 | _buoyancy = value; | ||
834 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
835 | // Buoyancy is faked by changing the gravity applied to the object | ||
836 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
837 | BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
838 | } | ||
839 | } | ||
796 | 840 | ||
797 | // Used for MoveTo | 841 | // Used for MoveTo |
798 | public override OMV.Vector3 PIDTarget { | 842 | public override OMV.Vector3 PIDTarget { |
@@ -828,6 +872,9 @@ public sealed class BSPrim : BSPhysObject | |||
828 | 872 | ||
829 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | 873 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); |
830 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 874 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
875 | AddForce(force, pushforce, false); | ||
876 | } | ||
877 | public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
831 | // for an object, doesn't matter if force is a pushforce or not | 878 | // for an object, doesn't matter if force is a pushforce or not |
832 | if (force.IsFinite()) | 879 | if (force.IsFinite()) |
833 | { | 880 | { |
@@ -840,11 +887,12 @@ public sealed class BSPrim : BSPhysObject | |||
840 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); | 887 | m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); |
841 | return; | 888 | return; |
842 | } | 889 | } |
843 | PhysicsScene.TaintedObject("BSPrim.AddForce", delegate() | 890 | BSScene.TaintCallback addForceOperation = delegate() |
844 | { | 891 | { |
845 | OMV.Vector3 fSum = OMV.Vector3.Zero; | 892 | OMV.Vector3 fSum = OMV.Vector3.Zero; |
846 | lock (m_accumulatedForces) | 893 | lock (m_accumulatedForces) |
847 | { | 894 | { |
895 | // Sum the accumulated additional forces for one big force to apply once. | ||
848 | foreach (OMV.Vector3 v in m_accumulatedForces) | 896 | foreach (OMV.Vector3 v in m_accumulatedForces) |
849 | { | 897 | { |
850 | fSum += v; | 898 | fSum += v; |
@@ -854,7 +902,11 @@ public sealed class BSPrim : BSPhysObject | |||
854 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); | 902 | // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum); |
855 | // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. | 903 | // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object. |
856 | BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); | 904 | BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum); |
857 | }); | 905 | }; |
906 | if (inTaintTime) | ||
907 | addForceOperation(); | ||
908 | else | ||
909 | PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation); | ||
858 | } | 910 | } |
859 | 911 | ||
860 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 912 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
@@ -872,19 +924,19 @@ public sealed class BSPrim : BSPhysObject | |||
872 | float tmp; | 924 | float tmp; |
873 | 925 | ||
874 | float returnMass = 0; | 926 | float returnMass = 0; |
875 | float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; | 927 | float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; |
876 | float hollowVolume = hollowAmount * hollowAmount; | 928 | float hollowVolume = hollowAmount * hollowAmount; |
877 | 929 | ||
878 | switch (_pbs.ProfileShape) | 930 | switch (BaseShape.ProfileShape) |
879 | { | 931 | { |
880 | case ProfileShape.Square: | 932 | case ProfileShape.Square: |
881 | // default box | 933 | // default box |
882 | 934 | ||
883 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 935 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
884 | { | 936 | { |
885 | if (hollowAmount > 0.0) | 937 | if (hollowAmount > 0.0) |
886 | { | 938 | { |
887 | switch (_pbs.HollowShape) | 939 | switch (BaseShape.HollowShape) |
888 | { | 940 | { |
889 | case HollowShape.Square: | 941 | case HollowShape.Square: |
890 | case HollowShape.Same: | 942 | case HollowShape.Same: |
@@ -908,19 +960,19 @@ public sealed class BSPrim : BSPhysObject | |||
908 | } | 960 | } |
909 | } | 961 | } |
910 | 962 | ||
911 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 963 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
912 | { | 964 | { |
913 | //a tube | 965 | //a tube |
914 | 966 | ||
915 | volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); | 967 | volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); |
916 | tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); | 968 | tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); |
917 | volume -= volume*tmp*tmp; | 969 | volume -= volume*tmp*tmp; |
918 | 970 | ||
919 | if (hollowAmount > 0.0) | 971 | if (hollowAmount > 0.0) |
920 | { | 972 | { |
921 | hollowVolume *= hollowAmount; | 973 | hollowVolume *= hollowAmount; |
922 | 974 | ||
923 | switch (_pbs.HollowShape) | 975 | switch (BaseShape.HollowShape) |
924 | { | 976 | { |
925 | case HollowShape.Square: | 977 | case HollowShape.Square: |
926 | case HollowShape.Same: | 978 | case HollowShape.Same: |
@@ -945,13 +997,13 @@ public sealed class BSPrim : BSPhysObject | |||
945 | 997 | ||
946 | case ProfileShape.Circle: | 998 | case ProfileShape.Circle: |
947 | 999 | ||
948 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 1000 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
949 | { | 1001 | { |
950 | volume *= 0.78539816339f; // elipse base | 1002 | volume *= 0.78539816339f; // elipse base |
951 | 1003 | ||
952 | if (hollowAmount > 0.0) | 1004 | if (hollowAmount > 0.0) |
953 | { | 1005 | { |
954 | switch (_pbs.HollowShape) | 1006 | switch (BaseShape.HollowShape) |
955 | { | 1007 | { |
956 | case HollowShape.Same: | 1008 | case HollowShape.Same: |
957 | case HollowShape.Circle: | 1009 | case HollowShape.Circle: |
@@ -973,10 +1025,10 @@ public sealed class BSPrim : BSPhysObject | |||
973 | } | 1025 | } |
974 | } | 1026 | } |
975 | 1027 | ||
976 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1028 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
977 | { | 1029 | { |
978 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); | 1030 | volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); |
979 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | 1031 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
980 | volume *= (1.0f - tmp * tmp); | 1032 | volume *= (1.0f - tmp * tmp); |
981 | 1033 | ||
982 | if (hollowAmount > 0.0) | 1034 | if (hollowAmount > 0.0) |
@@ -985,7 +1037,7 @@ public sealed class BSPrim : BSPhysObject | |||
985 | // calculate the hollow volume by it's shape compared to the prim shape | 1037 | // calculate the hollow volume by it's shape compared to the prim shape |
986 | hollowVolume *= hollowAmount; | 1038 | hollowVolume *= hollowAmount; |
987 | 1039 | ||
988 | switch (_pbs.HollowShape) | 1040 | switch (BaseShape.HollowShape) |
989 | { | 1041 | { |
990 | case HollowShape.Same: | 1042 | case HollowShape.Same: |
991 | case HollowShape.Circle: | 1043 | case HollowShape.Circle: |
@@ -1009,7 +1061,7 @@ public sealed class BSPrim : BSPhysObject | |||
1009 | break; | 1061 | break; |
1010 | 1062 | ||
1011 | case ProfileShape.HalfCircle: | 1063 | case ProfileShape.HalfCircle: |
1012 | if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1064 | if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
1013 | { | 1065 | { |
1014 | volume *= 0.52359877559829887307710723054658f; | 1066 | volume *= 0.52359877559829887307710723054658f; |
1015 | } | 1067 | } |
@@ -1017,7 +1069,7 @@ public sealed class BSPrim : BSPhysObject | |||
1017 | 1069 | ||
1018 | case ProfileShape.EquilateralTriangle: | 1070 | case ProfileShape.EquilateralTriangle: |
1019 | 1071 | ||
1020 | if (_pbs.PathCurve == (byte)Extrusion.Straight) | 1072 | if (BaseShape.PathCurve == (byte)Extrusion.Straight) |
1021 | { | 1073 | { |
1022 | volume *= 0.32475953f; | 1074 | volume *= 0.32475953f; |
1023 | 1075 | ||
@@ -1025,7 +1077,7 @@ public sealed class BSPrim : BSPhysObject | |||
1025 | { | 1077 | { |
1026 | 1078 | ||
1027 | // calculate the hollow volume by it's shape compared to the prim shape | 1079 | // calculate the hollow volume by it's shape compared to the prim shape |
1028 | switch (_pbs.HollowShape) | 1080 | switch (BaseShape.HollowShape) |
1029 | { | 1081 | { |
1030 | case HollowShape.Same: | 1082 | case HollowShape.Same: |
1031 | case HollowShape.Triangle: | 1083 | case HollowShape.Triangle: |
@@ -1050,11 +1102,11 @@ public sealed class BSPrim : BSPhysObject | |||
1050 | volume *= (1.0f - hollowVolume); | 1102 | volume *= (1.0f - hollowVolume); |
1051 | } | 1103 | } |
1052 | } | 1104 | } |
1053 | else if (_pbs.PathCurve == (byte)Extrusion.Curve1) | 1105 | else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) |
1054 | { | 1106 | { |
1055 | volume *= 0.32475953f; | 1107 | volume *= 0.32475953f; |
1056 | volume *= 0.01f * (float)(200 - _pbs.PathScaleX); | 1108 | volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); |
1057 | tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); | 1109 | tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); |
1058 | volume *= (1.0f - tmp * tmp); | 1110 | volume *= (1.0f - tmp * tmp); |
1059 | 1111 | ||
1060 | if (hollowAmount > 0.0) | 1112 | if (hollowAmount > 0.0) |
@@ -1062,7 +1114,7 @@ public sealed class BSPrim : BSPhysObject | |||
1062 | 1114 | ||
1063 | hollowVolume *= hollowAmount; | 1115 | hollowVolume *= hollowAmount; |
1064 | 1116 | ||
1065 | switch (_pbs.HollowShape) | 1117 | switch (BaseShape.HollowShape) |
1066 | { | 1118 | { |
1067 | case HollowShape.Same: | 1119 | case HollowShape.Same: |
1068 | case HollowShape.Triangle: | 1120 | case HollowShape.Triangle: |
@@ -1102,26 +1154,26 @@ public sealed class BSPrim : BSPhysObject | |||
1102 | float profileBegin; | 1154 | float profileBegin; |
1103 | float profileEnd; | 1155 | float profileEnd; |
1104 | 1156 | ||
1105 | if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) | 1157 | if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) |
1106 | { | 1158 | { |
1107 | taperX1 = _pbs.PathScaleX * 0.01f; | 1159 | taperX1 = BaseShape.PathScaleX * 0.01f; |
1108 | if (taperX1 > 1.0f) | 1160 | if (taperX1 > 1.0f) |
1109 | taperX1 = 2.0f - taperX1; | 1161 | taperX1 = 2.0f - taperX1; |
1110 | taperX = 1.0f - taperX1; | 1162 | taperX = 1.0f - taperX1; |
1111 | 1163 | ||
1112 | taperY1 = _pbs.PathScaleY * 0.01f; | 1164 | taperY1 = BaseShape.PathScaleY * 0.01f; |
1113 | if (taperY1 > 1.0f) | 1165 | if (taperY1 > 1.0f) |
1114 | taperY1 = 2.0f - taperY1; | 1166 | taperY1 = 2.0f - taperY1; |
1115 | taperY = 1.0f - taperY1; | 1167 | taperY = 1.0f - taperY1; |
1116 | } | 1168 | } |
1117 | else | 1169 | else |
1118 | { | 1170 | { |
1119 | taperX = _pbs.PathTaperX * 0.01f; | 1171 | taperX = BaseShape.PathTaperX * 0.01f; |
1120 | if (taperX < 0.0f) | 1172 | if (taperX < 0.0f) |
1121 | taperX = -taperX; | 1173 | taperX = -taperX; |
1122 | taperX1 = 1.0f - taperX; | 1174 | taperX1 = 1.0f - taperX; |
1123 | 1175 | ||
1124 | taperY = _pbs.PathTaperY * 0.01f; | 1176 | taperY = BaseShape.PathTaperY * 0.01f; |
1125 | if (taperY < 0.0f) | 1177 | if (taperY < 0.0f) |
1126 | taperY = -taperY; | 1178 | taperY = -taperY; |
1127 | taperY1 = 1.0f - taperY; | 1179 | taperY1 = 1.0f - taperY; |
@@ -1131,13 +1183,13 @@ public sealed class BSPrim : BSPhysObject | |||
1131 | 1183 | ||
1132 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); | 1184 | volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); |
1133 | 1185 | ||
1134 | pathBegin = (float)_pbs.PathBegin * 2.0e-5f; | 1186 | pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; |
1135 | pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; | 1187 | pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; |
1136 | volume *= (pathEnd - pathBegin); | 1188 | volume *= (pathEnd - pathBegin); |
1137 | 1189 | ||
1138 | // this is crude aproximation | 1190 | // this is crude aproximation |
1139 | profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; | 1191 | profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; |
1140 | profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; | 1192 | profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; |
1141 | volume *= (profileEnd - profileBegin); | 1193 | volume *= (profileEnd - profileBegin); |
1142 | 1194 | ||
1143 | returnMass = _density * volume; | 1195 | returnMass = _density * volume; |
@@ -1172,7 +1224,8 @@ public sealed class BSPrim : BSPhysObject | |||
1172 | shape.Position = _position; | 1224 | shape.Position = _position; |
1173 | shape.Rotation = _orientation; | 1225 | shape.Rotation = _orientation; |
1174 | shape.Velocity = _velocity; | 1226 | shape.Velocity = _velocity; |
1175 | shape.Scale = _scale; | 1227 | shape.Size = _size; |
1228 | shape.Scale = Scale; | ||
1176 | shape.Mass = _isPhysical ? _mass : 0f; | 1229 | shape.Mass = _isPhysical ? _mass : 0f; |
1177 | shape.Buoyancy = _buoyancy; | 1230 | shape.Buoyancy = _buoyancy; |
1178 | shape.HullKey = 0; | 1231 | shape.HullKey = 0; |
@@ -1182,7 +1235,6 @@ public sealed class BSPrim : BSPhysObject | |||
1182 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; | 1235 | shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; |
1183 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | 1236 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; |
1184 | shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; | 1237 | shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue; |
1185 | shape.Size = _size; | ||
1186 | } | 1238 | } |
1187 | // Rebuild the geometry and object. | 1239 | // Rebuild the geometry and object. |
1188 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1240 | // This is called when the shape changes so we need to recreate the mesh/hull. |
@@ -1199,11 +1251,12 @@ public sealed class BSPrim : BSPhysObject | |||
1199 | // Create the correct physical representation for this type of object. | 1251 | // Create the correct physical representation for this type of object. |
1200 | // Updates BSBody and BSShape with the new information. | 1252 | // Updates BSBody and BSShape with the new information. |
1201 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1253 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1202 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, _pbs, | 1254 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape, |
1203 | null, delegate(BulletBody dBody) | 1255 | null, delegate(BulletBody dBody) |
1204 | { | 1256 | { |
1205 | // Called if the current prim body is about to be destroyed. | 1257 | // Called if the current prim body is about to be destroyed. |
1206 | // Remove all the physical dependencies on the old body. | 1258 | // Remove all the physical dependencies on the old body. |
1259 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | ||
1207 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1260 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); |
1208 | }); | 1261 | }); |
1209 | 1262 | ||
@@ -1292,7 +1345,11 @@ public sealed class BSPrim : BSPhysObject | |||
1292 | _acceleration = entprop.Acceleration; | 1345 | _acceleration = entprop.Acceleration; |
1293 | _rotationalVelocity = entprop.RotationalVelocity; | 1346 | _rotationalVelocity = entprop.RotationalVelocity; |
1294 | 1347 | ||
1295 | PositionSanityCheck2(true); | 1348 | // remember the current and last set values |
1349 | LastEntityProperties = CurrentEntityProperties; | ||
1350 | CurrentEntityProperties = entprop; | ||
1351 | |||
1352 | PositionSanityCheck(true); | ||
1296 | 1353 | ||
1297 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1354 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1298 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 1355 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); |
@@ -1304,12 +1361,15 @@ public sealed class BSPrim : BSPhysObject | |||
1304 | /* | 1361 | /* |
1305 | else | 1362 | else |
1306 | { | 1363 | { |
1307 | // For debugging, we can also report the movement of children | 1364 | // For debugging, report the movement of children |
1308 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 1365 | DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
1309 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | 1366 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, |
1310 | entprop.Acceleration, entprop.RotationalVelocity); | 1367 | entprop.Acceleration, entprop.RotationalVelocity); |
1311 | } | 1368 | } |
1312 | */ | 1369 | */ |
1370 | // The linkset implimentation might want to know about this. | ||
1371 | |||
1372 | Linkset.UpdateProperties(this); | ||
1313 | } | 1373 | } |
1314 | } | 1374 | } |
1315 | } | 1375 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index aaed7de..6621d39 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,7 +39,6 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Move all logic out of the C++ code and into the C# code for easier future modifications. | ||
43 | // Test sculpties (verified that they don't work) | 42 | // Test sculpties (verified that they don't work) |
44 | // Compute physics FPS reasonably | 43 | // Compute physics FPS reasonably |
45 | // Based on material, set density and friction | 44 | // Based on material, set density and friction |
@@ -90,10 +89,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
90 | // let my minuions use my logger | 89 | // let my minuions use my logger |
91 | public ILog Logger { get { return m_log; } } | 90 | public ILog Logger { get { return m_log; } } |
92 | 91 | ||
93 | // If non-zero, the number of simulation steps between calls to the physics | ||
94 | // engine to output detailed physics stats. Debug logging level must be on also. | ||
95 | private int m_detailedStatsStep = 0; | ||
96 | |||
97 | public IMesher mesher; | 92 | public IMesher mesher; |
98 | // Level of Detail values kept as float because that's what the Meshmerizer wants | 93 | // Level of Detail values kept as float because that's what the Meshmerizer wants |
99 | public float MeshLOD { get; private set; } | 94 | public float MeshLOD { get; private set; } |
@@ -112,6 +107,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
112 | private float m_fixedTimeStep; | 107 | private float m_fixedTimeStep; |
113 | private long m_simulationStep = 0; | 108 | private long m_simulationStep = 0; |
114 | public long SimulationStep { get { return m_simulationStep; } } | 109 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | ||
115 | 111 | ||
116 | // A value of the time now so all the collision and update routines do not have to get their own | 112 | // A value of the time now so all the collision and update routines do not have to get their own |
117 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 113 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
@@ -131,6 +127,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
131 | 127 | ||
132 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed | 128 | public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed |
133 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes | 129 | public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes |
130 | public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects | ||
134 | 131 | ||
135 | public float PID_D { get; private set; } // derivative | 132 | public float PID_D { get; private set; } // derivative |
136 | public float PID_P { get; private set; } // proportional | 133 | public float PID_P { get; private set; } // proportional |
@@ -254,19 +251,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
254 | 251 | ||
255 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're | 252 | // The bounding box for the simulated world. The origin is 0,0,0 unless we're |
256 | // a child in a mega-region. | 253 | // a child in a mega-region. |
257 | // Turns out that Bullet really doesn't care about the extents of the simulated | 254 | // Bullet actually doesn't care about the extents of the simulated |
258 | // area. It tracks active objects no matter where they are. | 255 | // area. It tracks active objects no matter where they are. |
259 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 256 | Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
260 | 257 | ||
261 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); | 258 | // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); |
262 | WorldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), | 259 | World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(), |
263 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), | 260 | m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), |
264 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), | 261 | m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(), |
265 | m_DebugLogCallbackHandle); | 262 | m_DebugLogCallbackHandle)); |
266 | |||
267 | // Initialization to support the transition to a new API which puts most of the logic | ||
268 | // into the C# code so it is easier to modify and add to. | ||
269 | World = new BulletSim(WorldID, this, BulletSimAPI.GetSimHandle2(WorldID)); | ||
270 | 263 | ||
271 | Constraints = new BSConstraintCollection(World); | 264 | Constraints = new BSConstraintCollection(World); |
272 | 265 | ||
@@ -331,7 +324,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
331 | // Called directly from unmanaged code so don't do much | 324 | // Called directly from unmanaged code so don't do much |
332 | private void BulletLoggerPhysLog(string msg) | 325 | private void BulletLoggerPhysLog(string msg) |
333 | { | 326 | { |
334 | PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); | 327 | DetailLog("[BULLETS UNMANAGED]:" + msg); |
335 | } | 328 | } |
336 | 329 | ||
337 | public override void Dispose() | 330 | public override void Dispose() |
@@ -363,7 +356,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
363 | } | 356 | } |
364 | 357 | ||
365 | // Anything left in the unmanaged code should be cleaned out | 358 | // Anything left in the unmanaged code should be cleaned out |
366 | BulletSimAPI.Shutdown(WorldID); | 359 | BulletSimAPI.Shutdown2(World.ptr); |
367 | 360 | ||
368 | // Not logging any more | 361 | // Not logging any more |
369 | PhysicsLogging.Close(); | 362 | PhysicsLogging.Close(); |
@@ -494,19 +487,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
494 | m_simulationStep++; | 487 | m_simulationStep++; |
495 | int numSubSteps = 0; | 488 | int numSubSteps = 0; |
496 | 489 | ||
497 | // Sometimes needed for debugging to find out what happened before the step | 490 | // DEBUG |
498 | // PhysicsLogging.Flush(); | 491 | // DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep); |
499 | 492 | ||
500 | try | 493 | try |
501 | { | 494 | { |
502 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 495 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
503 | 496 | ||
504 | numSubSteps = BulletSimAPI.PhysicsStep(WorldID, timeStep, m_maxSubSteps, m_fixedTimeStep, | 497 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
505 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 498 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
506 | 499 | ||
507 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 500 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
508 | DetailLog("{0},Simulate,call, nTaints={1}, simTime={2}, substeps={3}, updates={4}, colliders={5}", | 501 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", |
509 | DetailLogZero, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 502 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); |
510 | } | 503 | } |
511 | catch (Exception e) | 504 | catch (Exception e) |
512 | { | 505 | { |
@@ -539,26 +532,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
539 | } | 532 | } |
540 | } | 533 | } |
541 | 534 | ||
542 | // This is a kludge to get avatar movement updates. | ||
543 | // the simulator expects collisions for avatars even if there are have been no collisions. This updates | ||
544 | // avatar animations and stuff. | ||
545 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
546 | foreach (BSPhysObject bsp in m_avatars) | ||
547 | bsp.SendCollisions(); | ||
548 | |||
549 | // The above SendCollision's batch up the collisions on the objects. | 535 | // The above SendCollision's batch up the collisions on the objects. |
550 | // Now push the collisions into the simulator. | 536 | // Now push the collisions into the simulator. |
551 | if (ObjectsWithCollisions.Count > 0) | 537 | if (ObjectsWithCollisions.Count > 0) |
552 | { | 538 | { |
553 | foreach (BSPhysObject bsp in ObjectsWithCollisions) | 539 | foreach (BSPhysObject bsp in ObjectsWithCollisions) |
554 | if (!m_avatars.Contains(bsp)) // don't call avatars twice | 540 | if (!bsp.SendCollisions()) |
555 | if (!bsp.SendCollisions()) | 541 | { |
556 | { | 542 | // If the object is done colliding, see that it's removed from the colliding list |
557 | // If the object is done colliding, see that it's removed from the colliding list | 543 | ObjectsWithNoMoreCollisions.Add(bsp); |
558 | ObjectsWithNoMoreCollisions.Add(bsp); | 544 | } |
559 | } | ||
560 | } | 545 | } |
561 | 546 | ||
547 | // This is a kludge to get avatar movement updates. | ||
548 | // The simulator expects collisions for avatars even if there are have been no collisions. | ||
549 | // The event updates avatar animations and stuff. | ||
550 | // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. | ||
551 | foreach (BSPhysObject bsp in m_avatars) | ||
552 | if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice | ||
553 | bsp.SendCollisions(); | ||
554 | |||
562 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 555 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
563 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 556 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
564 | if (ObjectsWithNoMoreCollisions.Count > 0) | 557 | if (ObjectsWithNoMoreCollisions.Count > 0) |
@@ -582,19 +575,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
582 | } | 575 | } |
583 | } | 576 | } |
584 | 577 | ||
585 | // If enabled, call into the physics engine to dump statistics | 578 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
586 | if (m_detailedStatsStep > 0) | 579 | // Only enable this in a limited test world with few objects. |
587 | { | 580 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG |
588 | if ((m_simulationStep % m_detailedStatsStep) == 0) | ||
589 | { | ||
590 | BulletSimAPI.DumpBulletStatistics(); | ||
591 | } | ||
592 | } | ||
593 | 581 | ||
594 | // The physics engine returns the number of milliseconds it simulated this call. | 582 | // The physics engine returns the number of milliseconds it simulated this call. |
595 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 583 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
596 | // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. | 584 | // We multiply by 55 to give a recognizable running rate (55 or less). |
597 | return numSubSteps * m_fixedTimeStep * 1000; | 585 | return numSubSteps * m_fixedTimeStep * 1000 * 55; |
586 | // return timeStep * 1000 * 55; | ||
598 | } | 587 | } |
599 | 588 | ||
600 | // Something has collided | 589 | // Something has collided |
@@ -617,7 +606,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
617 | BSPhysObject collidee = null; | 606 | BSPhysObject collidee = null; |
618 | PhysObjects.TryGetValue(collidingWith, out collidee); | 607 | PhysObjects.TryGetValue(collidingWith, out collidee); |
619 | 608 | ||
620 | DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); | 609 | // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); |
621 | 610 | ||
622 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) | 611 | if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) |
623 | { | 612 | { |
@@ -704,6 +693,35 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
704 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process | 693 | if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process |
705 | { | 694 | { |
706 | // swizzle a new list into the list location so we can process what's there | 695 | // swizzle a new list into the list location so we can process what's there |
696 | int taintCount = m_taintsToProcessPerStep; | ||
697 | TaintCallbackEntry oneCallback = new TaintCallbackEntry(); | ||
698 | while (_taintedObjects.Count > 0 && taintCount-- > 0) | ||
699 | { | ||
700 | bool gotOne = false; | ||
701 | lock (_taintLock) | ||
702 | { | ||
703 | if (_taintedObjects.Count > 0) | ||
704 | { | ||
705 | oneCallback = _taintedObjects[0]; | ||
706 | _taintedObjects.RemoveAt(0); | ||
707 | gotOne = true; | ||
708 | } | ||
709 | } | ||
710 | if (gotOne) | ||
711 | { | ||
712 | try | ||
713 | { | ||
714 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG | ||
715 | oneCallback.callback(); | ||
716 | } | ||
717 | catch (Exception e) | ||
718 | { | ||
719 | m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e); | ||
720 | } | ||
721 | } | ||
722 | } | ||
723 | /* | ||
724 | // swizzle a new list into the list location so we can process what's there | ||
707 | List<TaintCallbackEntry> oldList; | 725 | List<TaintCallbackEntry> oldList; |
708 | lock (_taintLock) | 726 | lock (_taintLock) |
709 | { | 727 | { |
@@ -715,6 +733,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
715 | { | 733 | { |
716 | try | 734 | try |
717 | { | 735 | { |
736 | DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG | ||
718 | tcbe.callback(); | 737 | tcbe.callback(); |
719 | } | 738 | } |
720 | catch (Exception e) | 739 | catch (Exception e) |
@@ -723,6 +742,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
723 | } | 742 | } |
724 | } | 743 | } |
725 | oldList.Clear(); | 744 | oldList.Clear(); |
745 | */ | ||
726 | } | 746 | } |
727 | } | 747 | } |
728 | 748 | ||
@@ -780,6 +800,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
780 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); | 800 | delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); |
781 | delegate float ParamGet(BSScene scene); | 801 | delegate float ParamGet(BSScene scene); |
782 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); | 802 | delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); |
803 | delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val); | ||
783 | 804 | ||
784 | private struct ParameterDefn | 805 | private struct ParameterDefn |
785 | { | 806 | { |
@@ -789,6 +810,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
789 | public ParamUser userParam; // get the value from the configuration file | 810 | public ParamUser userParam; // get the value from the configuration file |
790 | public ParamGet getter; // return the current value stored for this parameter | 811 | public ParamGet getter; // return the current value stored for this parameter |
791 | public ParamSet setter; // set the current value for this parameter | 812 | public ParamSet setter; // set the current value for this parameter |
813 | public SetOnObject onObject; // set the value on an object in the physical domain | ||
792 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) | 814 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) |
793 | { | 815 | { |
794 | name = n; | 816 | name = n; |
@@ -797,6 +819,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
797 | userParam = u; | 819 | userParam = u; |
798 | getter = g; | 820 | getter = g; |
799 | setter = s; | 821 | setter = s; |
822 | onObject = null; | ||
823 | } | ||
824 | public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o) | ||
825 | { | ||
826 | name = n; | ||
827 | desc = d; | ||
828 | defaultValue = v; | ||
829 | userParam = u; | ||
830 | getter = g; | ||
831 | setter = s; | ||
832 | onObject = o; | ||
800 | } | 833 | } |
801 | } | 834 | } |
802 | 835 | ||
@@ -818,6 +851,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
818 | // | 851 | // |
819 | // The single letter parameters for the delegates are: | 852 | // The single letter parameters for the delegates are: |
820 | // s = BSScene | 853 | // s = BSScene |
854 | // o = BSPhysObject | ||
821 | // p = string parameter name | 855 | // p = string parameter name |
822 | // l = localID of referenced object | 856 | // l = localID of referenced object |
823 | // v = float value | 857 | // v = float value |
@@ -834,6 +868,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
834 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, | 868 | (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, |
835 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, | 869 | (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); }, |
836 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), | 870 | (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ), |
871 | new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", | ||
872 | ConfigurationParameters.numericTrue, | ||
873 | (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); }, | ||
874 | (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); }, | ||
875 | (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ), | ||
837 | 876 | ||
838 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", | 877 | new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", |
839 | 8f, | 878 | 8f, |
@@ -876,6 +915,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
876 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, | 915 | (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, |
877 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, | 916 | (s) => { return (float)s.m_maxUpdatesPerFrame; }, |
878 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), | 917 | (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), |
918 | new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step", | ||
919 | 100f, | ||
920 | (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); }, | ||
921 | (s) => { return (float)s.m_taintsToProcessPerStep; }, | ||
922 | (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ), | ||
879 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", | 923 | new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", |
880 | 10000.01f, | 924 | 10000.01f, |
881 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, | 925 | (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); }, |
@@ -917,70 +961,84 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
917 | -9.80665f, | 961 | -9.80665f, |
918 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, | 962 | (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, |
919 | (s) => { return s.m_params[0].gravity; }, | 963 | (s) => { return s.m_params[0].gravity; }, |
920 | (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), | 964 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); }, |
965 | (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ), | ||
921 | 966 | ||
922 | 967 | ||
923 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", | 968 | new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", |
924 | 0f, | 969 | 0f, |
925 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, | 970 | (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, |
926 | (s) => { return s.m_params[0].linearDamping; }, | 971 | (s) => { return s.m_params[0].linearDamping; }, |
927 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); } ), | 972 | (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); } ), | ||
928 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", | 974 | new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", |
929 | 0f, | 975 | 0f, |
930 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, | 976 | (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, |
931 | (s) => { return s.m_params[0].angularDamping; }, | 977 | (s) => { return s.m_params[0].angularDamping; }, |
932 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); } ), | 978 | (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); } ), | ||
933 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", | 980 | new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", |
934 | 0.2f, | 981 | 0.2f, |
935 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, | 982 | (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, |
936 | (s) => { return s.m_params[0].deactivationTime; }, | 983 | (s) => { return s.m_params[0].deactivationTime; }, |
937 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); } ), | 984 | (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); } ), | ||
938 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", | 986 | new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", |
939 | 0.8f, | 987 | 0.8f, |
940 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, | 988 | (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, |
941 | (s) => { return s.m_params[0].linearSleepingThreshold; }, | 989 | (s) => { return s.m_params[0].linearSleepingThreshold; }, |
942 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), | 990 | (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); } ), | ||
943 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", | 992 | new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", |
944 | 1.0f, | 993 | 1.0f, |
945 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, | 994 | (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, |
946 | (s) => { return s.m_params[0].angularSleepingThreshold; }, | 995 | (s) => { return s.m_params[0].angularSleepingThreshold; }, |
947 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), | 996 | (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); } ), | ||
948 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , | 998 | new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , |
949 | 0f, // set to zero to disable | 999 | 0f, // set to zero to disable |
950 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, | 1000 | (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, |
951 | (s) => { return s.m_params[0].ccdMotionThreshold; }, | 1001 | (s) => { return s.m_params[0].ccdMotionThreshold; }, |
952 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), | 1002 | (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); } ), | ||
953 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , | 1004 | new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , |
954 | 0f, | 1005 | 0f, |
955 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, | 1006 | (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, |
956 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, | 1007 | (s) => { return s.m_params[0].ccdSweptSphereRadius; }, |
957 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), | 1008 | (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); } ), | ||
958 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , | 1010 | new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , |
959 | 0.1f, | 1011 | 0.1f, |
960 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, | 1012 | (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, |
961 | (s) => { return s.m_params[0].contactProcessingThreshold; }, | 1013 | (s) => { return s.m_params[0].contactProcessingThreshold; }, |
962 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), | 1014 | (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); } ), | ||
963 | 1016 | ||
964 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1017 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
965 | 0.5f, | 1018 | 0.5f, |
966 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1019 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
967 | (s) => { return s.m_params[0].terrainFriction; }, | 1020 | (s) => { return s.m_params[0].terrainFriction; }, |
968 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), | 1021 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), |
969 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , | 1022 | new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , |
970 | 0.8f, | 1023 | 0.8f, |
971 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, | 1024 | (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, |
972 | (s) => { return s.m_params[0].terrainHitFraction; }, | 1025 | (s) => { return s.m_params[0].terrainHitFraction; }, |
973 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), | 1026 | (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ), |
974 | new ParameterDefn("TerrainRestitution", "Bouncyness" , | 1027 | new ParameterDefn("TerrainRestitution", "Bouncyness" , |
975 | 0f, | 1028 | 0f, |
976 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1029 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
977 | (s) => { return s.m_params[0].terrainRestitution; }, | 1030 | (s) => { return s.m_params[0].terrainRestitution; }, |
978 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), | 1031 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), |
979 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1032 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
980 | 0.2f, | 1033 | 0.2f, |
981 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1034 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
982 | (s) => { return s.m_params[0].avatarFriction; }, | 1035 | (s) => { return s.m_params[0].avatarFriction; }, |
983 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1036 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1037 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | ||
1038 | 10f, | ||
1039 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | ||
1040 | (s) => { return s.m_params[0].avatarStandingFriction; }, | ||
1041 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | ||
984 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", | 1042 | new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", |
985 | 60f, | 1043 | 60f, |
986 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, | 1044 | (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, |
@@ -1070,12 +1128,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1070 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, | 1128 | (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, |
1071 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), | 1129 | (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), |
1072 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", | 1130 | new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", |
1073 | 0.1f, | 1131 | 0.001f, |
1074 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, | 1132 | (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, |
1075 | (s) => { return s.m_params[0].linkConstraintCFM; }, | 1133 | (s) => { return s.m_params[0].linkConstraintCFM; }, |
1076 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), | 1134 | (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), |
1077 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", | 1135 | new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", |
1078 | 0.2f, | 1136 | 0.8f, |
1079 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, | 1137 | (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, |
1080 | (s) => { return s.m_params[0].linkConstraintERP; }, | 1138 | (s) => { return s.m_params[0].linkConstraintERP; }, |
1081 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), | 1139 | (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), |
@@ -1085,11 +1143,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1085 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, | 1143 | (s) => { return s.m_params[0].linkConstraintSolverIterations; }, |
1086 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), | 1144 | (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ), |
1087 | 1145 | ||
1088 | new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", | 1146 | new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)", |
1089 | 0f, | 1147 | 0f, |
1090 | (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, | 1148 | (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); }, |
1091 | (s) => { return (float)s.m_detailedStatsStep; }, | 1149 | (s) => { return (float)s.m_params[0].physicsLoggingFrames; }, |
1092 | (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), | 1150 | (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ), |
1093 | }; | 1151 | }; |
1094 | 1152 | ||
1095 | // Convert a boolean to our numeric true and false values | 1153 | // Convert a boolean to our numeric true and false values |
@@ -1197,52 +1255,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1197 | return ret; | 1255 | return ret; |
1198 | } | 1256 | } |
1199 | 1257 | ||
1200 | // check to see if we are updating a parameter for a particular or all of the prims | ||
1201 | protected void UpdateParameterObject(ref float loc, string parm, uint localID, float val) | ||
1202 | { | ||
1203 | List<uint> operateOn; | ||
1204 | lock (PhysObjects) operateOn = new List<uint>(PhysObjects.Keys); | ||
1205 | UpdateParameterSet(operateOn, ref loc, parm, localID, val); | ||
1206 | } | ||
1207 | |||
1208 | // update all the localIDs specified | 1258 | // update all the localIDs specified |
1209 | // If the local ID is APPLY_TO_NONE, just change the default value | 1259 | // If the local ID is APPLY_TO_NONE, just change the default value |
1210 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs | 1260 | // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs |
1211 | // If the localID is a specific object, apply the parameter change to only that object | 1261 | // If the localID is a specific object, apply the parameter change to only that object |
1212 | protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) | 1262 | protected void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) |
1213 | { | 1263 | { |
1264 | List<uint> objectIDs = new List<uint>(); | ||
1214 | switch (localID) | 1265 | switch (localID) |
1215 | { | 1266 | { |
1216 | case PhysParameterEntry.APPLY_TO_NONE: | 1267 | case PhysParameterEntry.APPLY_TO_NONE: |
1217 | defaultLoc = val; // setting only the default value | 1268 | defaultLoc = val; // setting only the default value |
1269 | // This will cause a call into the physical world if some operation is specified (SetOnObject). | ||
1270 | objectIDs.Add(TERRAIN_ID); | ||
1271 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1218 | break; | 1272 | break; |
1219 | case PhysParameterEntry.APPLY_TO_ALL: | 1273 | case PhysParameterEntry.APPLY_TO_ALL: |
1220 | defaultLoc = val; // setting ALL also sets the default value | 1274 | defaultLoc = val; // setting ALL also sets the default value |
1221 | List<uint> objectIDs = lIDs; | 1275 | lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); |
1222 | string xparm = parm.ToLower(); | 1276 | TaintedUpdateParameter(parm, objectIDs, val); |
1223 | float xval = val; | ||
1224 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1225 | foreach (uint lID in objectIDs) | ||
1226 | { | ||
1227 | BulletSimAPI.UpdateParameter(WorldID, lID, xparm, xval); | ||
1228 | } | ||
1229 | }); | ||
1230 | break; | 1277 | break; |
1231 | default: | 1278 | default: |
1232 | // setting only one localID | 1279 | // setting only one localID |
1233 | TaintedUpdateParameter(parm, localID, val); | 1280 | objectIDs.Add(localID); |
1281 | TaintedUpdateParameter(parm, objectIDs, val); | ||
1234 | break; | 1282 | break; |
1235 | } | 1283 | } |
1236 | } | 1284 | } |
1237 | 1285 | ||
1238 | // schedule the actual updating of the paramter to when the phys engine is not busy | 1286 | // schedule the actual updating of the paramter to when the phys engine is not busy |
1239 | protected void TaintedUpdateParameter(string parm, uint localID, float val) | 1287 | protected void TaintedUpdateParameter(string parm, List<uint> lIDs, float val) |
1240 | { | 1288 | { |
1241 | uint xlocalID = localID; | ||
1242 | string xparm = parm.ToLower(); | ||
1243 | float xval = val; | 1289 | float xval = val; |
1244 | TaintedObject("BSScene.TaintedUpdateParameter", delegate() { | 1290 | List<uint> xlIDs = lIDs; |
1245 | BulletSimAPI.UpdateParameter(WorldID, xlocalID, xparm, xval); | 1291 | string xparm = parm; |
1292 | TaintedObject("BSScene.UpdateParameterSet", delegate() { | ||
1293 | ParameterDefn thisParam; | ||
1294 | if (TryGetParameter(xparm, out thisParam)) | ||
1295 | { | ||
1296 | if (thisParam.onObject != null) | ||
1297 | { | ||
1298 | foreach (uint lID in xlIDs) | ||
1299 | { | ||
1300 | BSPhysObject theObject = null; | ||
1301 | PhysObjects.TryGetValue(lID, out theObject); | ||
1302 | thisParam.onObject(this, theObject, xval); | ||
1303 | } | ||
1304 | } | ||
1305 | } | ||
1246 | }); | 1306 | }); |
1247 | } | 1307 | } |
1248 | 1308 | ||
@@ -1270,6 +1330,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
1270 | public void DetailLog(string msg, params Object[] args) | 1330 | public void DetailLog(string msg, params Object[] args) |
1271 | { | 1331 | { |
1272 | PhysicsLogging.Write(msg, args); | 1332 | PhysicsLogging.Write(msg, args); |
1333 | // Add the Flush() if debugging crashes to get all the messages written out. | ||
1334 | // PhysicsLogging.Flush(); | ||
1273 | } | 1335 | } |
1274 | // used to fill in the LocalID when there isn't one | 1336 | // used to fill in the LocalID when there isn't one |
1275 | public const string DetailLogZero = "0000000000"; | 1337 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 399a133..d3ba273 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -51,7 +51,7 @@ public class BSShapeCollection : IDisposable | |||
51 | } | 51 | } |
52 | 52 | ||
53 | // Description of a hull. | 53 | // Description of a hull. |
54 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient physical objects | 54 | // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. |
55 | private struct HullDesc | 55 | private struct HullDesc |
56 | { | 56 | { |
57 | public IntPtr ptr; | 57 | public IntPtr ptr; |
@@ -59,17 +59,9 @@ public class BSShapeCollection : IDisposable | |||
59 | public DateTime lastReferenced; | 59 | public DateTime lastReferenced; |
60 | } | 60 | } |
61 | 61 | ||
62 | private struct BodyDesc | 62 | // The sharable set of meshes and hulls. Indexed by their shape hash. |
63 | { | 63 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
64 | public IntPtr ptr; | 64 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
65 | // Bodies are only used once so reference count is always either one or zero | ||
66 | public int referenceCount; | ||
67 | public DateTime lastReferenced; | ||
68 | } | ||
69 | |||
70 | private Dictionary<ulong, MeshDesc> Meshes = new Dictionary<ulong, MeshDesc>(); | ||
71 | private Dictionary<ulong, HullDesc> Hulls = new Dictionary<ulong, HullDesc>(); | ||
72 | private Dictionary<uint, BodyDesc> Bodies = new Dictionary<uint, BodyDesc>(); | ||
73 | 65 | ||
74 | public BSShapeCollection(BSScene physScene) | 66 | public BSShapeCollection(BSScene physScene) |
75 | { | 67 | { |
@@ -92,8 +84,12 @@ public class BSShapeCollection : IDisposable | |||
92 | // First checks the shape and updates that if necessary then makes | 84 | // First checks the shape and updates that if necessary then makes |
93 | // sure the body is of the right type. | 85 | // sure the body is of the right type. |
94 | // Return 'true' if either the body or the shape changed. | 86 | // Return 'true' if either the body or the shape changed. |
87 | // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before | ||
88 | // the current shape or body is destroyed. This allows the caller to remove any | ||
89 | // higher level dependencies on the shape or body. Mostly used for LinkSets to | ||
90 | // remove the physical constraints before the body is destroyed. | ||
95 | // Called at taint-time!! | 91 | // Called at taint-time!! |
96 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPrim prim, | 92 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, |
97 | ShapeData shapeData, PrimitiveBaseShape pbs, | 93 | ShapeData shapeData, PrimitiveBaseShape pbs, |
98 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) | 94 | ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) |
99 | { | 95 | { |
@@ -103,7 +99,8 @@ public class BSShapeCollection : IDisposable | |||
103 | lock (m_collectionActivityLock) | 99 | lock (m_collectionActivityLock) |
104 | { | 100 | { |
105 | // Do we have the correct geometry for this type of object? | 101 | // Do we have the correct geometry for this type of object? |
106 | // Updates prim.BSShape with information/pointers to requested shape | 102 | // Updates prim.BSShape with information/pointers to shape. |
103 | // CreateGeom returns 'true' of BSShape as changed to a new shape. | ||
107 | bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); | 104 | bool newGeom = CreateGeom(forceRebuild, prim, shapeData, pbs, shapeCallback); |
108 | // If we had to select a new shape geometry for the object, | 105 | // If we had to select a new shape geometry for the object, |
109 | // rebuild the body around it. | 106 | // rebuild the body around it. |
@@ -120,26 +117,24 @@ public class BSShapeCollection : IDisposable | |||
120 | 117 | ||
121 | // Track another user of a body | 118 | // Track another user of a body |
122 | // We presume the caller has allocated the body. | 119 | // We presume the caller has allocated the body. |
123 | // Bodies only have one user so the reference count is either 1 or 0. | 120 | // Bodies only have one user so the body is just put into the world if not already there. |
124 | public void ReferenceBody(BulletBody body, bool atTaintTime) | 121 | public void ReferenceBody(BulletBody body, bool inTaintTime) |
125 | { | 122 | { |
126 | lock (m_collectionActivityLock) | 123 | lock (m_collectionActivityLock) |
127 | { | 124 | { |
128 | BodyDesc bodyDesc; | 125 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); |
129 | if (Bodies.TryGetValue(body.ID, out bodyDesc)) | 126 | BSScene.TaintCallback createOperation = delegate() |
130 | { | 127 | { |
131 | bodyDesc.referenceCount++; | 128 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
132 | DetailLog("{0},BSShapeCollection.ReferenceBody,existingBody,body={1},ref={2}", body.ID, body, bodyDesc.referenceCount); | 129 | { |
133 | } | 130 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
131 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | ||
132 | } | ||
133 | }; | ||
134 | if (inTaintTime) | ||
135 | createOperation(); | ||
134 | else | 136 | else |
135 | { | 137 | PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation); |
136 | // New entry | ||
137 | bodyDesc.ptr = body.ptr; | ||
138 | bodyDesc.referenceCount = 1; | ||
139 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount); | ||
140 | } | ||
141 | bodyDesc.lastReferenced = System.DateTime.Now; | ||
142 | Bodies[body.ID] = bodyDesc; | ||
143 | } | 138 | } |
144 | } | 139 | } |
145 | 140 | ||
@@ -152,42 +147,25 @@ public class BSShapeCollection : IDisposable | |||
152 | 147 | ||
153 | lock (m_collectionActivityLock) | 148 | lock (m_collectionActivityLock) |
154 | { | 149 | { |
155 | BodyDesc bodyDesc; | 150 | BSScene.TaintCallback removeOperation = delegate() |
156 | if (Bodies.TryGetValue(body.ID, out bodyDesc)) | ||
157 | { | 151 | { |
158 | bodyDesc.referenceCount--; | 152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}", |
159 | bodyDesc.lastReferenced = System.DateTime.Now; | 153 | body.ID, body.ptr.ToString("X"), inTaintTime); |
160 | Bodies[body.ID] = bodyDesc; | 154 | // If the caller needs to know the old body is going away, pass the event up. |
161 | DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount); | 155 | if (bodyCallback != null) bodyCallback(body); |
162 | 156 | ||
163 | // If body is no longer being used, free it -- bodies are never shared. | 157 | // It may have already been removed from the world in which case the next is a NOOP. |
164 | if (bodyDesc.referenceCount == 0) | 158 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); |
165 | { | 159 | |
166 | Bodies.Remove(body.ID); | 160 | // Zero any reference to the shape so it is not freed when the body is deleted. |
167 | BSScene.TaintCallback removeOperation = delegate() | 161 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); |
168 | { | 162 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); |
169 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}", | 163 | }; |
170 | body.ID, body.ptr.ToString("X")); | 164 | // If already in taint-time, do the operations now. Otherwise queue for later. |
171 | // If the caller needs to know the old body is going away, pass the event up. | 165 | if (inTaintTime) |
172 | if (bodyCallback != null) bodyCallback(body); | 166 | removeOperation(); |
173 | |||
174 | // Zero any reference to the shape so it is not freed when the body is deleted. | ||
175 | BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); | ||
176 | // It may have already been removed from the world in which case the next is a NOOP. | ||
177 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | ||
178 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); | ||
179 | }; | ||
180 | // If already in taint-time, do the operations now. Otherwise queue for later. | ||
181 | if (inTaintTime) | ||
182 | removeOperation(); | ||
183 | else | ||
184 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); | ||
185 | } | ||
186 | } | ||
187 | else | 167 | else |
188 | { | 168 | PhysicsScene.TaintedObject("BSShapeCollection.DereferenceBody", removeOperation); |
189 | DetailLog("{0},BSShapeCollection.DereferenceBody,DID NOT FIND BODY", body.ID, bodyDesc.referenceCount); | ||
190 | } | ||
191 | } | 169 | } |
192 | } | 170 | } |
193 | 171 | ||
@@ -208,7 +186,7 @@ public class BSShapeCollection : IDisposable | |||
208 | { | 186 | { |
209 | // There is an existing instance of this mesh. | 187 | // There is an existing instance of this mesh. |
210 | meshDesc.referenceCount++; | 188 | meshDesc.referenceCount++; |
211 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}", | 189 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
212 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 190 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
213 | } | 191 | } |
214 | else | 192 | else |
@@ -217,7 +195,7 @@ public class BSShapeCollection : IDisposable | |||
217 | meshDesc.ptr = shape.ptr; | 195 | meshDesc.ptr = shape.ptr; |
218 | // We keep a reference to the underlying IMesh data so a hull can be built | 196 | // We keep a reference to the underlying IMesh data so a hull can be built |
219 | meshDesc.referenceCount = 1; | 197 | meshDesc.referenceCount = 1; |
220 | DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}", | 198 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
221 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 199 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
222 | ret = true; | 200 | ret = true; |
223 | } | 201 | } |
@@ -230,7 +208,7 @@ public class BSShapeCollection : IDisposable | |||
230 | { | 208 | { |
231 | // There is an existing instance of this hull. | 209 | // There is an existing instance of this hull. |
232 | hullDesc.referenceCount++; | 210 | hullDesc.referenceCount++; |
233 | DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}", | 211 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
234 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 212 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
235 | } | 213 | } |
236 | else | 214 | else |
@@ -238,7 +216,7 @@ public class BSShapeCollection : IDisposable | |||
238 | // This is a new reference to a hull | 216 | // This is a new reference to a hull |
239 | hullDesc.ptr = shape.ptr; | 217 | hullDesc.ptr = shape.ptr; |
240 | hullDesc.referenceCount = 1; | 218 | hullDesc.referenceCount = 1; |
241 | DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}", | 219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
242 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
243 | ret = true; | 221 | ret = true; |
244 | 222 | ||
@@ -256,37 +234,42 @@ public class BSShapeCollection : IDisposable | |||
256 | } | 234 | } |
257 | 235 | ||
258 | // Release the usage of a shape. | 236 | // Release the usage of a shape. |
259 | // The collisionObject is released since it is a copy of the real collision shape. | 237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) |
260 | public void DereferenceShape(BulletShape shape, bool atTaintTime, ShapeDestructionCallback shapeCallback) | ||
261 | { | 238 | { |
262 | if (shape.ptr == IntPtr.Zero) | 239 | if (shape.ptr == IntPtr.Zero) |
263 | return; | 240 | return; |
264 | 241 | ||
265 | BSScene.TaintCallback dereferenceOperation = delegate() | 242 | BSScene.TaintCallback dereferenceOperation = delegate() |
266 | { | 243 | { |
267 | switch (shape.type) | 244 | if (shape.ptr != IntPtr.Zero) |
268 | { | 245 | { |
269 | case ShapeData.PhysicsShapeType.SHAPE_HULL: | 246 | if (shape.isNativeShape) |
270 | DereferenceHull(shape, shapeCallback); | 247 | { |
271 | break; | ||
272 | case ShapeData.PhysicsShapeType.SHAPE_MESH: | ||
273 | DereferenceMesh(shape, shapeCallback); | ||
274 | break; | ||
275 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
276 | break; | ||
277 | default: | ||
278 | // Native shapes are not tracked and are released immediately | 248 | // Native shapes are not tracked and are released immediately |
279 | if (shape.ptr != IntPtr.Zero & shape.isNativeShape) | 249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | ||
251 | if (shapeCallback != null) shapeCallback(shape); | ||
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | switch (shape.type) | ||
280 | { | 257 | { |
281 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 258 | case ShapeData.PhysicsShapeType.SHAPE_HULL: |
282 | BSScene.DetailLogZero, shape.ptr.ToString("X"), atTaintTime); | 259 | DereferenceHull(shape, shapeCallback); |
283 | if (shapeCallback != null) shapeCallback(shape); | 260 | break; |
284 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 261 | case ShapeData.PhysicsShapeType.SHAPE_MESH: |
262 | DereferenceMesh(shape, shapeCallback); | ||
263 | break; | ||
264 | case ShapeData.PhysicsShapeType.SHAPE_UNKNOWN: | ||
265 | break; | ||
266 | default: | ||
267 | break; | ||
285 | } | 268 | } |
286 | break; | 269 | } |
287 | } | 270 | } |
288 | }; | 271 | }; |
289 | if (atTaintTime) | 272 | if (inTaintTime) |
290 | { | 273 | { |
291 | lock (m_collectionActivityLock) | 274 | lock (m_collectionActivityLock) |
292 | { | 275 | { |
@@ -336,19 +319,31 @@ public class BSShapeCollection : IDisposable | |||
336 | 319 | ||
337 | // Create the geometry information in Bullet for later use. | 320 | // Create the geometry information in Bullet for later use. |
338 | // The objects needs a hull if it's physical otherwise a mesh is enough. | 321 | // The objects needs a hull if it's physical otherwise a mesh is enough. |
339 | // No locking here because this is done when we know physics is not simulating. | 322 | // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, |
340 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used. | 323 | // shared geometries will be used. If the parameters of the existing shape are the same |
324 | // as this request, the shape is not rebuilt. | ||
325 | // Info in prim.BSShape is updated to the new shape. | ||
341 | // Returns 'true' if the geometry was rebuilt. | 326 | // Returns 'true' if the geometry was rebuilt. |
342 | // Called at taint-time! | 327 | // Called at taint-time! |
343 | private bool CreateGeom(bool forceRebuild, BSPrim prim, ShapeData shapeData, | 328 | private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeData shapeData, |
344 | PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) | 329 | PrimitiveBaseShape pbs, ShapeDestructionCallback shapeCallback) |
345 | { | 330 | { |
346 | bool ret = false; | 331 | bool ret = false; |
347 | bool haveShape = false; | 332 | bool haveShape = false; |
348 | bool nativeShapePossible = true; | 333 | bool nativeShapePossible = true; |
349 | 334 | ||
335 | if (shapeData.Type == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
336 | { | ||
337 | // an avatar capsule is close to a native shape (it is not shared) | ||
338 | ret = GetReferenceToNativeShape(prim, shapeData, ShapeData.PhysicsShapeType.SHAPE_AVATAR, | ||
339 | ShapeData.FixedShapeKey.KEY_CAPSULE, shapeCallback); | ||
340 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.BSShape); | ||
341 | haveShape = true; | ||
342 | } | ||
350 | // If the prim attributes are simple, this could be a simple Bullet native shape | 343 | // If the prim attributes are simple, this could be a simple Bullet native shape |
351 | if (nativeShapePossible | 344 | if (!haveShape |
345 | && pbs != null | ||
346 | && nativeShapePossible | ||
352 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) | 347 | && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) |
353 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 | 348 | || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 |
354 | && pbs.ProfileHollow == 0 | 349 | && pbs.ProfileHollow == 0 |
@@ -358,7 +353,8 @@ public class BSShapeCollection : IDisposable | |||
358 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 353 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
359 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 354 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
360 | { | 355 | { |
361 | if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 356 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
357 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | ||
362 | { | 358 | { |
363 | haveShape = true; | 359 | haveShape = true; |
364 | if (forceRebuild | 360 | if (forceRebuild |
@@ -372,7 +368,7 @@ public class BSShapeCollection : IDisposable | |||
372 | prim.LocalID, forceRebuild, prim.BSShape); | 368 | prim.LocalID, forceRebuild, prim.BSShape); |
373 | } | 369 | } |
374 | } | 370 | } |
375 | else | 371 | if (pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) |
376 | { | 372 | { |
377 | haveShape = true; | 373 | haveShape = true; |
378 | if (forceRebuild | 374 | if (forceRebuild |
@@ -390,9 +386,9 @@ public class BSShapeCollection : IDisposable | |||
390 | // If a simple shape is not happening, create a mesh and possibly a hull. | 386 | // If a simple shape is not happening, create a mesh and possibly a hull. |
391 | // Note that if it's a native shape, the check for physical/non-physical is not | 387 | // Note that if it's a native shape, the check for physical/non-physical is not |
392 | // made. Native shapes are best used in either case. | 388 | // made. Native shapes are best used in either case. |
393 | if (!haveShape) | 389 | if (!haveShape && pbs != null) |
394 | { | 390 | { |
395 | if (prim.IsPhysical) | 391 | if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) |
396 | { | 392 | { |
397 | // Update prim.BSShape to reference a hull of this shape. | 393 | // Update prim.BSShape to reference a hull of this shape. |
398 | ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); | 394 | ret = GetReferenceToHull(prim, shapeData, pbs, shapeCallback); |
@@ -409,12 +405,12 @@ public class BSShapeCollection : IDisposable | |||
409 | return ret; | 405 | return ret; |
410 | } | 406 | } |
411 | 407 | ||
412 | // Creates a native shape and assignes it to prim.BSShape | 408 | // Creates a native shape and assignes it to prim.BSShape. |
413 | private bool GetReferenceToNativeShape( BSPrim prim, ShapeData shapeData, | 409 | // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape(). |
410 | private bool GetReferenceToNativeShape(BSPhysObject prim, ShapeData shapeData, | ||
414 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, | 411 | ShapeData.PhysicsShapeType shapeType, ShapeData.FixedShapeKey shapeKey, |
415 | ShapeDestructionCallback shapeCallback) | 412 | ShapeDestructionCallback shapeCallback) |
416 | { | 413 | { |
417 | BulletShape newShape; | ||
418 | 414 | ||
419 | shapeData.Type = shapeType; | 415 | shapeData.Type = shapeType; |
420 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 416 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
@@ -424,29 +420,48 @@ public class BSShapeCollection : IDisposable | |||
424 | // release any previous shape | 420 | // release any previous shape |
425 | DereferenceShape(prim.BSShape, true, shapeCallback); | 421 | DereferenceShape(prim.BSShape, true, shapeCallback); |
426 | 422 | ||
427 | // Native shapes are always built independently. | 423 | BulletShape newShape = BuildPhysicalNativeShape(shapeType, shapeData, shapeKey); |
428 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | ||
429 | newShape.shapeKey = (ulong)shapeKey; | ||
430 | newShape.isNativeShape = true; | ||
431 | 424 | ||
432 | // Don't need to do a 'ReferenceShape()' here because native shapes are not tracked. | 425 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
433 | // DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1}", shapeData.ID, newShape); | 426 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
427 | shapeData.ID, newShape, shapeData.Scale); | ||
434 | 428 | ||
435 | prim.BSShape = newShape; | 429 | prim.BSShape = newShape; |
436 | return true; | 430 | return true; |
437 | } | 431 | } |
438 | 432 | ||
433 | private BulletShape BuildPhysicalNativeShape(ShapeData.PhysicsShapeType shapeType, | ||
434 | ShapeData shapeData, ShapeData.FixedShapeKey shapeKey) | ||
435 | { | ||
436 | BulletShape newShape; | ||
437 | |||
438 | if (shapeType == ShapeData.PhysicsShapeType.SHAPE_AVATAR) | ||
439 | { | ||
440 | newShape = new BulletShape( | ||
441 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1.0f, 1.0f, shapeData.Scale), | ||
442 | shapeType); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, shapeData), shapeType); | ||
447 | } | ||
448 | newShape.shapeKey = (System.UInt64)shapeKey; | ||
449 | newShape.isNativeShape = true; | ||
450 | |||
451 | return newShape; | ||
452 | } | ||
453 | |||
439 | // Builds a mesh shape in the physical world and updates prim.BSShape. | 454 | // Builds a mesh shape in the physical world and updates prim.BSShape. |
440 | // Dereferences previous shape in BSShape and adds a reference for this new shape. | 455 | // Dereferences previous shape in BSShape and adds a reference for this new shape. |
441 | // Returns 'true' of a mesh was actually built. Otherwise . | 456 | // Returns 'true' of a mesh was actually built. Otherwise . |
442 | // Called at taint-time! | 457 | // Called at taint-time! |
443 | private bool GetReferenceToMesh(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 458 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, |
444 | ShapeDestructionCallback shapeCallback) | 459 | ShapeDestructionCallback shapeCallback) |
445 | { | 460 | { |
446 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 461 | BulletShape newShape = new BulletShape(IntPtr.Zero); |
447 | 462 | ||
448 | float lod; | 463 | float lod; |
449 | ulong newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); | 464 | System.UInt64 newMeshKey = ComputeShapeKey(shapeData, pbs, out lod); |
450 | 465 | ||
451 | // if this new shape is the same as last time, don't recreate the mesh | 466 | // if this new shape is the same as last time, don't recreate the mesh |
452 | if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) | 467 | if (newMeshKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_MESH) |
@@ -459,6 +474,8 @@ public class BSShapeCollection : IDisposable | |||
459 | DereferenceShape(prim.BSShape, true, shapeCallback); | 474 | DereferenceShape(prim.BSShape, true, shapeCallback); |
460 | 475 | ||
461 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); | 476 | newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, pbs, shapeData.Size, lod); |
477 | // Take evasive action if the mesh was not constructed. | ||
478 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
462 | 479 | ||
463 | ReferenceShape(newShape); | 480 | ReferenceShape(newShape); |
464 | 481 | ||
@@ -469,10 +486,10 @@ public class BSShapeCollection : IDisposable | |||
469 | return true; // 'true' means a new shape has been added to this prim | 486 | return true; // 'true' means a new shape has been added to this prim |
470 | } | 487 | } |
471 | 488 | ||
472 | private BulletShape CreatePhysicalMesh(string objName, ulong newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 489 | private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
473 | { | 490 | { |
474 | IMesh meshData = null; | 491 | IMesh meshData = null; |
475 | IntPtr meshPtr; | 492 | IntPtr meshPtr = IntPtr.Zero; |
476 | MeshDesc meshDesc; | 493 | MeshDesc meshDesc; |
477 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) | 494 | if (Meshes.TryGetValue(newMeshKey, out meshDesc)) |
478 | { | 495 | { |
@@ -484,23 +501,26 @@ public class BSShapeCollection : IDisposable | |||
484 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 501 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
485 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 502 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
486 | 503 | ||
487 | int[] indices = meshData.getIndexListAsInt(); | 504 | if (meshData != null) |
488 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
489 | |||
490 | float[] verticesAsFloats = new float[vertices.Count * 3]; | ||
491 | int vi = 0; | ||
492 | foreach (OMV.Vector3 vv in vertices) | ||
493 | { | 505 | { |
494 | verticesAsFloats[vi++] = vv.X; | 506 | int[] indices = meshData.getIndexListAsInt(); |
495 | verticesAsFloats[vi++] = vv.Y; | 507 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
496 | verticesAsFloats[vi++] = vv.Z; | 508 | |
497 | } | 509 | float[] verticesAsFloats = new float[vertices.Count * 3]; |
510 | int vi = 0; | ||
511 | foreach (OMV.Vector3 vv in vertices) | ||
512 | { | ||
513 | verticesAsFloats[vi++] = vv.X; | ||
514 | verticesAsFloats[vi++] = vv.Y; | ||
515 | verticesAsFloats[vi++] = vv.Z; | ||
516 | } | ||
498 | 517 | ||
499 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", | 518 | // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", |
500 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); | 519 | // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); |
501 | 520 | ||
502 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 521 | meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
503 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); | 522 | indices.GetLength(0), indices, vertices.Count, verticesAsFloats); |
523 | } | ||
504 | } | 524 | } |
505 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); | 525 | BulletShape newShape = new BulletShape(meshPtr, ShapeData.PhysicsShapeType.SHAPE_MESH); |
506 | newShape.shapeKey = newMeshKey; | 526 | newShape.shapeKey = newMeshKey; |
@@ -510,13 +530,13 @@ public class BSShapeCollection : IDisposable | |||
510 | 530 | ||
511 | // See that hull shape exists in the physical world and update prim.BSShape. | 531 | // See that hull shape exists in the physical world and update prim.BSShape. |
512 | // We could be creating the hull because scale changed or whatever. | 532 | // We could be creating the hull because scale changed or whatever. |
513 | private bool GetReferenceToHull(BSPrim prim, ShapeData shapeData, PrimitiveBaseShape pbs, | 533 | private bool GetReferenceToHull(BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs, |
514 | ShapeDestructionCallback shapeCallback) | 534 | ShapeDestructionCallback shapeCallback) |
515 | { | 535 | { |
516 | BulletShape newShape; | 536 | BulletShape newShape; |
517 | 537 | ||
518 | float lod; | 538 | float lod; |
519 | ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); | 539 | System.UInt64 newHullKey = ComputeShapeKey(shapeData, pbs, out lod); |
520 | 540 | ||
521 | // if the hull hasn't changed, don't rebuild it | 541 | // if the hull hasn't changed, don't rebuild it |
522 | if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) | 542 | if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL) |
@@ -525,10 +545,11 @@ public class BSShapeCollection : IDisposable | |||
525 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", | 545 | DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", |
526 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 546 | prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
527 | 547 | ||
528 | // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull. | 548 | // Remove usage of the previous shape. |
529 | DereferenceShape(prim.BSShape, true, shapeCallback); | 549 | DereferenceShape(prim.BSShape, true, shapeCallback); |
530 | 550 | ||
531 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); | 551 | newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); |
552 | newShape = VerifyMeshCreated(newShape, prim, shapeData, pbs); | ||
532 | 553 | ||
533 | ReferenceShape(newShape); | 554 | ReferenceShape(newShape); |
534 | 555 | ||
@@ -539,10 +560,10 @@ public class BSShapeCollection : IDisposable | |||
539 | } | 560 | } |
540 | 561 | ||
541 | List<ConvexResult> m_hulls; | 562 | List<ConvexResult> m_hulls; |
542 | private BulletShape CreatePhysicalHull(string objName, ulong newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) | 563 | private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) |
543 | { | 564 | { |
544 | 565 | ||
545 | IntPtr hullPtr; | 566 | IntPtr hullPtr = IntPtr.Zero; |
546 | HullDesc hullDesc; | 567 | HullDesc hullDesc; |
547 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) | 568 | if (Hulls.TryGetValue(newHullKey, out hullDesc)) |
548 | { | 569 | { |
@@ -554,86 +575,89 @@ public class BSShapeCollection : IDisposable | |||
554 | // Build a new hull in the physical world | 575 | // Build a new hull in the physical world |
555 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 576 | // Pass false for physicalness as this creates some sort of bounding box which we don't need |
556 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 577 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); |
557 | 578 | if (meshData != null) | |
558 | int[] indices = meshData.getIndexListAsInt(); | ||
559 | List<OMV.Vector3> vertices = meshData.getVertexList(); | ||
560 | |||
561 | //format conversion from IMesh format to DecompDesc format | ||
562 | List<int> convIndices = new List<int>(); | ||
563 | List<float3> convVertices = new List<float3>(); | ||
564 | for (int ii = 0; ii < indices.GetLength(0); ii++) | ||
565 | { | 579 | { |
566 | convIndices.Add(indices[ii]); | ||
567 | } | ||
568 | foreach (OMV.Vector3 vv in vertices) | ||
569 | { | ||
570 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
571 | } | ||
572 | 580 | ||
573 | // setup and do convex hull conversion | 581 | int[] indices = meshData.getIndexListAsInt(); |
574 | m_hulls = new List<ConvexResult>(); | 582 | List<OMV.Vector3> vertices = meshData.getVertexList(); |
575 | DecompDesc dcomp = new DecompDesc(); | ||
576 | dcomp.mIndices = convIndices; | ||
577 | dcomp.mVertices = convVertices; | ||
578 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
579 | // create the hull into the _hulls variable | ||
580 | convexBuilder.process(dcomp); | ||
581 | |||
582 | // Convert the vertices and indices for passing to unmanaged. | ||
583 | // The hull information is passed as a large floating point array. | ||
584 | // The format is: | ||
585 | // convHulls[0] = number of hulls | ||
586 | // convHulls[1] = number of vertices in first hull | ||
587 | // convHulls[2] = hull centroid X coordinate | ||
588 | // convHulls[3] = hull centroid Y coordinate | ||
589 | // convHulls[4] = hull centroid Z coordinate | ||
590 | // convHulls[5] = first hull vertex X | ||
591 | // convHulls[6] = first hull vertex Y | ||
592 | // convHulls[7] = first hull vertex Z | ||
593 | // convHulls[8] = second hull vertex X | ||
594 | // ... | ||
595 | // convHulls[n] = number of vertices in second hull | ||
596 | // convHulls[n+1] = second hull centroid X coordinate | ||
597 | // ... | ||
598 | // | ||
599 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
600 | // data structures that do not need to be converted in order to pass to Bullet. | ||
601 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
602 | int hullCount = m_hulls.Count; | ||
603 | int totalVertices = 1; // include one for the count of the hulls | ||
604 | foreach (ConvexResult cr in m_hulls) | ||
605 | { | ||
606 | totalVertices += 4; // add four for the vertex count and centroid | ||
607 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
608 | } | ||
609 | float[] convHulls = new float[totalVertices]; | ||
610 | 583 | ||
611 | convHulls[0] = (float)hullCount; | 584 | //format conversion from IMesh format to DecompDesc format |
612 | int jj = 1; | 585 | List<int> convIndices = new List<int>(); |
613 | foreach (ConvexResult cr in m_hulls) | 586 | List<float3> convVertices = new List<float3>(); |
614 | { | 587 | for (int ii = 0; ii < indices.GetLength(0); ii++) |
615 | // copy vertices for index access | 588 | { |
616 | float3[] verts = new float3[cr.HullVertices.Count]; | 589 | convIndices.Add(indices[ii]); |
617 | int kk = 0; | 590 | } |
618 | foreach (float3 ff in cr.HullVertices) | 591 | foreach (OMV.Vector3 vv in vertices) |
592 | { | ||
593 | convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); | ||
594 | } | ||
595 | |||
596 | // setup and do convex hull conversion | ||
597 | m_hulls = new List<ConvexResult>(); | ||
598 | DecompDesc dcomp = new DecompDesc(); | ||
599 | dcomp.mIndices = convIndices; | ||
600 | dcomp.mVertices = convVertices; | ||
601 | ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); | ||
602 | // create the hull into the _hulls variable | ||
603 | convexBuilder.process(dcomp); | ||
604 | |||
605 | // Convert the vertices and indices for passing to unmanaged. | ||
606 | // The hull information is passed as a large floating point array. | ||
607 | // The format is: | ||
608 | // convHulls[0] = number of hulls | ||
609 | // convHulls[1] = number of vertices in first hull | ||
610 | // convHulls[2] = hull centroid X coordinate | ||
611 | // convHulls[3] = hull centroid Y coordinate | ||
612 | // convHulls[4] = hull centroid Z coordinate | ||
613 | // convHulls[5] = first hull vertex X | ||
614 | // convHulls[6] = first hull vertex Y | ||
615 | // convHulls[7] = first hull vertex Z | ||
616 | // convHulls[8] = second hull vertex X | ||
617 | // ... | ||
618 | // convHulls[n] = number of vertices in second hull | ||
619 | // convHulls[n+1] = second hull centroid X coordinate | ||
620 | // ... | ||
621 | // | ||
622 | // TODO: is is very inefficient. Someday change the convex hull generator to return | ||
623 | // data structures that do not need to be converted in order to pass to Bullet. | ||
624 | // And maybe put the values directly into pinned memory rather than marshaling. | ||
625 | int hullCount = m_hulls.Count; | ||
626 | int totalVertices = 1; // include one for the count of the hulls | ||
627 | foreach (ConvexResult cr in m_hulls) | ||
619 | { | 628 | { |
620 | verts[kk++] = ff; | 629 | totalVertices += 4; // add four for the vertex count and centroid |
630 | totalVertices += cr.HullIndices.Count * 3; // we pass just triangles | ||
621 | } | 631 | } |
632 | float[] convHulls = new float[totalVertices]; | ||
622 | 633 | ||
623 | // add to the array one hull's worth of data | 634 | convHulls[0] = (float)hullCount; |
624 | convHulls[jj++] = cr.HullIndices.Count; | 635 | int jj = 1; |
625 | convHulls[jj++] = 0f; // centroid x,y,z | 636 | foreach (ConvexResult cr in m_hulls) |
626 | convHulls[jj++] = 0f; | ||
627 | convHulls[jj++] = 0f; | ||
628 | foreach (int ind in cr.HullIndices) | ||
629 | { | 637 | { |
630 | convHulls[jj++] = verts[ind].x; | 638 | // copy vertices for index access |
631 | convHulls[jj++] = verts[ind].y; | 639 | float3[] verts = new float3[cr.HullVertices.Count]; |
632 | convHulls[jj++] = verts[ind].z; | 640 | int kk = 0; |
641 | foreach (float3 ff in cr.HullVertices) | ||
642 | { | ||
643 | verts[kk++] = ff; | ||
644 | } | ||
645 | |||
646 | // add to the array one hull's worth of data | ||
647 | convHulls[jj++] = cr.HullIndices.Count; | ||
648 | convHulls[jj++] = 0f; // centroid x,y,z | ||
649 | convHulls[jj++] = 0f; | ||
650 | convHulls[jj++] = 0f; | ||
651 | foreach (int ind in cr.HullIndices) | ||
652 | { | ||
653 | convHulls[jj++] = verts[ind].x; | ||
654 | convHulls[jj++] = verts[ind].y; | ||
655 | convHulls[jj++] = verts[ind].z; | ||
656 | } | ||
633 | } | 657 | } |
658 | // create the hull data structure in Bullet | ||
659 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
634 | } | 660 | } |
635 | // create the hull data structure in Bullet | ||
636 | hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); | ||
637 | } | 661 | } |
638 | 662 | ||
639 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); | 663 | BulletShape newShape = new BulletShape(hullPtr, ShapeData.PhysicsShapeType.SHAPE_HULL); |
@@ -652,32 +676,77 @@ public class BSShapeCollection : IDisposable | |||
652 | 676 | ||
653 | // Create a hash of all the shape parameters to be used as a key | 677 | // Create a hash of all the shape parameters to be used as a key |
654 | // for this particular shape. | 678 | // for this particular shape. |
655 | private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) | 679 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs, out float retLod) |
656 | { | 680 | { |
657 | // level of detail based on size and type of the object | 681 | // level of detail based on size and type of the object |
658 | float lod = PhysicsScene.MeshLOD; | 682 | float lod = PhysicsScene.MeshLOD; |
659 | if (pbs.SculptEntry) | 683 | if (pbs.SculptEntry) |
660 | lod = PhysicsScene.SculptLOD; | 684 | lod = PhysicsScene.SculptLOD; |
661 | 685 | ||
686 | // Mega prims usually get more detail because one can interact with shape approximations at this size. | ||
662 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); | 687 | float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z)); |
663 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) | 688 | if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) |
664 | lod = PhysicsScene.MeshMegaPrimLOD; | 689 | lod = PhysicsScene.MeshMegaPrimLOD; |
665 | 690 | ||
666 | retLod = lod; | 691 | retLod = lod; |
667 | return (ulong)pbs.GetMeshKey(shapeData.Size, lod); | 692 | return pbs.GetMeshKey(shapeData.Size, lod); |
668 | } | 693 | } |
669 | // For those who don't want the LOD | 694 | // For those who don't want the LOD |
670 | private ulong ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) | 695 | private System.UInt64 ComputeShapeKey(ShapeData shapeData, PrimitiveBaseShape pbs) |
671 | { | 696 | { |
672 | float lod; | 697 | float lod; |
673 | return ComputeShapeKey(shapeData, pbs, out lod); | 698 | return ComputeShapeKey(shapeData, pbs, out lod); |
674 | } | 699 | } |
675 | 700 | ||
701 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim, ShapeData shapeData, PrimitiveBaseShape pbs) | ||
702 | { | ||
703 | // If the shape was successfully created, nothing more to do | ||
704 | if (newShape.ptr != IntPtr.Zero) | ||
705 | return newShape; | ||
706 | |||
707 | // The most common reason for failure is that an underlying asset is not available | ||
708 | |||
709 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | ||
710 | if (pbs.SculptEntry && !prim.LastAssetBuildFailed && pbs.SculptTexture != OMV.UUID.Zero) | ||
711 | { | ||
712 | prim.LastAssetBuildFailed = true; | ||
713 | BSPhysObject xprim = prim; | ||
714 | Util.FireAndForget(delegate | ||
715 | { | ||
716 | RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod; | ||
717 | if (assetProvider != null) | ||
718 | { | ||
719 | BSPhysObject yprim = xprim; // probably not necessary, but, just in case. | ||
720 | assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) | ||
721 | { | ||
722 | if (!yprim.BaseShape.SculptEntry) | ||
723 | return; | ||
724 | if (yprim.BaseShape.SculptTexture.ToString() != asset.ID) | ||
725 | return; | ||
726 | |||
727 | yprim.BaseShape.SculptData = new byte[asset.Data.Length]; | ||
728 | asset.Data.CopyTo(yprim.BaseShape.SculptData, 0); | ||
729 | // This will cause the prim to see that the filler shape is not the right | ||
730 | // one and try again to build the object. | ||
731 | yprim.ForceBodyShapeRebuild(false); | ||
732 | |||
733 | }); | ||
734 | } | ||
735 | }); | ||
736 | } | ||
737 | |||
738 | // While we figure out the real problem, stick a simple native shape on the object. | ||
739 | BulletShape fillinShape = | ||
740 | BuildPhysicalNativeShape(ShapeData.PhysicsShapeType.SHAPE_SPHERE, shapeData, ShapeData.FixedShapeKey.KEY_SPHERE); | ||
741 | |||
742 | return fillinShape; | ||
743 | } | ||
744 | |||
676 | // Create a body object in Bullet. | 745 | // Create a body object in Bullet. |
677 | // Updates prim.BSBody with the information about the new body if one is created. | 746 | // Updates prim.BSBody with the information about the new body if one is created. |
678 | // Returns 'true' if an object was actually created. | 747 | // Returns 'true' if an object was actually created. |
679 | // Called at taint-time. | 748 | // Called at taint-time. |
680 | private bool CreateBody(bool forceRebuild, BSPrim prim, BulletSim sim, BulletShape shape, | 749 | private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, |
681 | ShapeData shapeData, BodyDestructionCallback bodyCallback) | 750 | ShapeData shapeData, BodyDestructionCallback bodyCallback) |
682 | { | 751 | { |
683 | bool ret = false; | 752 | bool ret = false; |
@@ -701,6 +770,7 @@ public class BSShapeCollection : IDisposable | |||
701 | 770 | ||
702 | if (mustRebuild || forceRebuild) | 771 | if (mustRebuild || forceRebuild) |
703 | { | 772 | { |
773 | // Free any old body | ||
704 | DereferenceBody(prim.BSBody, true, bodyCallback); | 774 | DereferenceBody(prim.BSBody, true, bodyCallback); |
705 | 775 | ||
706 | BulletBody aBody; | 776 | BulletBody aBody; |
@@ -709,13 +779,13 @@ public class BSShapeCollection : IDisposable | |||
709 | { | 779 | { |
710 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 780 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
711 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 781 | shapeData.ID, shapeData.Position, shapeData.Rotation); |
712 | // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 782 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
713 | } | 783 | } |
714 | else | 784 | else |
715 | { | 785 | { |
716 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 786 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
717 | shapeData.ID, shapeData.Position, shapeData.Rotation); | 787 | shapeData.ID, shapeData.Position, shapeData.Rotation); |
718 | // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 788 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
719 | } | 789 | } |
720 | aBody = new BulletBody(shapeData.ID, bodyPtr); | 790 | aBody = new BulletBody(shapeData.ID, bodyPtr); |
721 | 791 | ||
@@ -731,7 +801,8 @@ public class BSShapeCollection : IDisposable | |||
731 | 801 | ||
732 | private void DetailLog(string msg, params Object[] args) | 802 | private void DetailLog(string msg, params Object[] args) |
733 | { | 803 | { |
734 | PhysicsScene.PhysicsLogging.Write(msg, args); | 804 | if (PhysicsScene.PhysicsLogging.Enabled) |
805 | PhysicsScene.DetailLog(msg, args); | ||
735 | } | 806 | } |
736 | } | 807 | } |
737 | } | 808 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 70aa429..4106534 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -114,6 +114,9 @@ public class BSTerrainManager | |||
114 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 114 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |
115 | Vector3.Zero, Quaternion.Identity)); | 115 | Vector3.Zero, Quaternion.Identity)); |
116 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); | 116 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr); |
117 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr); | ||
118 | // Ground plane does not move | ||
119 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | ||
117 | // Everything collides with the ground plane. | 120 | // Everything collides with the ground plane. |
118 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 121 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, |
119 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 122 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); |
@@ -201,10 +204,10 @@ public class BSTerrainManager | |||
201 | // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when | 204 | // The 'doNow' boolean says whether to do all the unmanaged activities right now (like when |
202 | // calling this routine from initialization or taint-time routines) or whether to delay | 205 | // calling this routine from initialization or taint-time routines) or whether to delay |
203 | // all the unmanaged activities to taint-time. | 206 | // all the unmanaged activities to taint-time. |
204 | private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool atTaintTime) | 207 | private void UpdateOrCreateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
205 | { | 208 | { |
206 | DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},atTaintTime={3}", | 209 | DetailLog("{0},BSTerrainManager.UpdateOrCreateTerrain,call,minC={1},maxC={2},inTaintTime={3}", |
207 | BSScene.DetailLogZero, minCoords, maxCoords, atTaintTime); | 210 | BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime); |
208 | 211 | ||
209 | float minZ = float.MaxValue; | 212 | float minZ = float.MaxValue; |
210 | float maxZ = float.MinValue; | 213 | float maxZ = float.MinValue; |
@@ -296,16 +299,16 @@ public class BSTerrainManager | |||
296 | mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, | 299 | mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, mapInfo.ID, |
297 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); | 300 | mapInfo.minCoords, mapInfo.maxCoords, mapInfo.heightMap, TERRAIN_COLLISION_MARGIN); |
298 | 301 | ||
302 | // Create the terrain shape from the mapInfo | ||
303 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr), | ||
304 | ShapeData.PhysicsShapeType.SHAPE_TERRAIN); | ||
305 | |||
299 | // The terrain object initial position is at the center of the object | 306 | // The terrain object initial position is at the center of the object |
300 | Vector3 centerPos; | 307 | Vector3 centerPos; |
301 | centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); | 308 | centerPos.X = minCoords.X + (mapInfo.sizeX / 2f); |
302 | centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); | 309 | centerPos.Y = minCoords.Y + (mapInfo.sizeY / 2f); |
303 | centerPos.Z = minZ + ((maxZ - minZ) / 2f); | 310 | centerPos.Z = minZ + ((maxZ - minZ) / 2f); |
304 | 311 | ||
305 | // Create the terrain shape from the mapInfo | ||
306 | mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(mapInfo.Ptr), | ||
307 | ShapeData.PhysicsShapeType.SHAPE_TERRAIN); | ||
308 | |||
309 | mapInfo.terrainBody = new BulletBody(mapInfo.ID, | 312 | mapInfo.terrainBody = new BulletBody(mapInfo.ID, |
310 | BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, | 313 | BulletSimAPI.CreateBodyWithDefaultMotionState2(mapInfo.terrainShape.ptr, |
311 | id, centerPos, Quaternion.Identity)); | 314 | id, centerPos, Quaternion.Identity)); |
@@ -320,9 +323,6 @@ public class BSTerrainManager | |||
320 | BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); | 323 | BulletSimAPI.SetRestitution2(mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); |
321 | BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 324 | BulletSimAPI.SetCollisionFlags2(mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
322 | 325 | ||
323 | BulletSimAPI.SetMassProps2(mapInfo.terrainBody.ptr, 0f, Vector3.Zero); | ||
324 | BulletSimAPI.UpdateInertiaTensor2(mapInfo.terrainBody.ptr); | ||
325 | |||
326 | // Return the new terrain to the world of physical objects | 326 | // Return the new terrain to the world of physical objects |
327 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); | 327 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, mapInfo.terrainBody.ptr); |
328 | 328 | ||
@@ -335,14 +335,15 @@ public class BSTerrainManager | |||
335 | 335 | ||
336 | // Make sure the new shape is processed. | 336 | // Make sure the new shape is processed. |
337 | // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); | 337 | // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); |
338 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 338 | BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.ISLAND_SLEEPING); |
339 | // BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | ||
339 | 340 | ||
340 | m_terrainModified = true; | 341 | m_terrainModified = true; |
341 | }; | 342 | }; |
342 | 343 | ||
343 | // There is the option to do the changes now (we're already in 'taint time'), or | 344 | // There is the option to do the changes now (we're already in 'taint time'), or |
344 | // to do the Bullet operations later. | 345 | // to do the Bullet operations later. |
345 | if (atTaintTime) | 346 | if (inTaintTime) |
346 | rebuildOperation(); | 347 | rebuildOperation(); |
347 | else | 348 | else |
348 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); | 349 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:UpdateExisting", rebuildOperation); |
@@ -381,7 +382,7 @@ public class BSTerrainManager | |||
381 | }; | 382 | }; |
382 | 383 | ||
383 | // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. | 384 | // If already in taint-time, just call Bullet. Otherwise queue the operations for the safe time. |
384 | if (atTaintTime) | 385 | if (inTaintTime) |
385 | createOperation(); | 386 | createOperation(); |
386 | else | 387 | else |
387 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); | 388 | PhysicsScene.TaintedObject("BSScene.UpdateOrCreateTerrain:NewTerrain", createOperation); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index a43880d..5ffd591 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -101,9 +101,8 @@ public struct BulletShape | |||
101 | } | 101 | } |
102 | public IntPtr ptr; | 102 | public IntPtr ptr; |
103 | public ShapeData.PhysicsShapeType type; | 103 | public ShapeData.PhysicsShapeType type; |
104 | public ulong shapeKey; | 104 | public System.UInt64 shapeKey; |
105 | public bool isNativeShape; | 105 | public bool isNativeShape; |
106 | // Hulls have an underlying mesh. A pointer to it is hidden here. | ||
107 | public override string ToString() | 106 | public override string ToString() |
108 | { | 107 | { |
109 | StringBuilder buff = new StringBuilder(); | 108 | StringBuilder buff = new StringBuilder(); |
@@ -192,8 +191,9 @@ public struct ShapeData | |||
192 | SHAPE_SPHERE = 5, | 191 | SHAPE_SPHERE = 5, |
193 | SHAPE_MESH = 6, | 192 | SHAPE_MESH = 6, |
194 | SHAPE_HULL = 7, | 193 | SHAPE_HULL = 7, |
195 | SHAPE_GROUNDPLANE = 8, | 194 | // following defined by BulletSim |
196 | SHAPE_TERRAIN = 9, | 195 | SHAPE_GROUNDPLANE = 20, |
196 | SHAPE_TERRAIN = 21, | ||
197 | }; | 197 | }; |
198 | public uint ID; | 198 | public uint ID; |
199 | public PhysicsShapeType Type; | 199 | public PhysicsShapeType Type; |
@@ -223,6 +223,7 @@ public struct ShapeData | |||
223 | KEY_SPHERE = 2, | 223 | KEY_SPHERE = 2, |
224 | KEY_CONE = 3, | 224 | KEY_CONE = 3, |
225 | KEY_CYLINDER = 4, | 225 | KEY_CYLINDER = 4, |
226 | KEY_CAPSULE = 5, | ||
226 | } | 227 | } |
227 | } | 228 | } |
228 | [StructLayout(LayoutKind.Sequential)] | 229 | [StructLayout(LayoutKind.Sequential)] |
@@ -282,6 +283,7 @@ public struct ConfigurationParameters | |||
282 | public float terrainHitFraction; | 283 | public float terrainHitFraction; |
283 | public float terrainRestitution; | 284 | public float terrainRestitution; |
284 | public float avatarFriction; | 285 | public float avatarFriction; |
286 | public float avatarStandingFriction; | ||
285 | public float avatarDensity; | 287 | public float avatarDensity; |
286 | public float avatarRestitution; | 288 | public float avatarRestitution; |
287 | public float avatarCapsuleRadius; | 289 | public float avatarCapsuleRadius; |
@@ -305,6 +307,8 @@ public struct ConfigurationParameters | |||
305 | public float linkConstraintCFM; | 307 | public float linkConstraintCFM; |
306 | public float linkConstraintSolverIterations; | 308 | public float linkConstraintSolverIterations; |
307 | 309 | ||
310 | public float physicsLoggingFrames; | ||
311 | |||
308 | public const float numericTrue = 1f; | 312 | public const float numericTrue = 1f; |
309 | public const float numericFalse = 0f; | 313 | public const float numericFalse = 0f; |
310 | } | 314 | } |
@@ -386,7 +390,7 @@ public enum CollisionFilterGroups : uint | |||
386 | VolumeDetectMask = ~BSensorTrigger, | 390 | VolumeDetectMask = ~BSensorTrigger, |
387 | TerrainFilter = BTerrainFilter, | 391 | TerrainFilter = BTerrainFilter, |
388 | TerrainMask = BAllFilter & ~BStaticFilter, | 392 | TerrainMask = BAllFilter & ~BStaticFilter, |
389 | GroundPlaneFilter = BAllFilter, | 393 | GroundPlaneFilter = BGroundPlaneFilter, |
390 | GroundPlaneMask = BAllFilter | 394 | GroundPlaneMask = BAllFilter |
391 | 395 | ||
392 | }; | 396 | }; |
@@ -426,6 +430,7 @@ public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg | |||
426 | [return: MarshalAs(UnmanagedType.LPStr)] | 430 | [return: MarshalAs(UnmanagedType.LPStr)] |
427 | public static extern string GetVersion(); | 431 | public static extern string GetVersion(); |
428 | 432 | ||
433 | /* Remove the linkage to the old api methods | ||
429 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 434 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
430 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, | 435 | public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, |
431 | int maxCollisions, IntPtr collisionArray, | 436 | int maxCollisions, IntPtr collisionArray, |
@@ -529,7 +534,7 @@ public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); | |||
529 | // =============================================================================== | 534 | // =============================================================================== |
530 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 535 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
531 | public static extern void DumpBulletStatistics(); | 536 | public static extern void DumpBulletStatistics(); |
532 | 537 | */ | |
533 | // Log a debug message | 538 | // Log a debug message |
534 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 539 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
535 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | 540 | public static extern void SetDebugLogCallback(DebugLogCallback callback); |
@@ -560,7 +565,8 @@ public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); | |||
560 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 565 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
561 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, | 566 | public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, |
562 | int maxCollisions, IntPtr collisionArray, | 567 | int maxCollisions, IntPtr collisionArray, |
563 | int maxUpdates, IntPtr updateArray); | 568 | int maxUpdates, IntPtr updateArray, |
569 | DebugLogCallback logRoutine); | ||
564 | 570 | ||
565 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 571 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
566 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); | 572 | public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); |
@@ -602,6 +608,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
602 | public static extern bool IsNativeShape2(IntPtr shape); | 608 | public static extern bool IsNativeShape2(IntPtr shape); |
603 | 609 | ||
604 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 610 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
611 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | ||
612 | |||
613 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
605 | public static extern IntPtr CreateCompoundShape2(IntPtr sim); | 614 | public static extern IntPtr CreateCompoundShape2(IntPtr sim); |
606 | 615 | ||
607 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 616 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -1037,18 +1046,6 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | |||
1037 | public static extern int GetNumConstraintRefs2(IntPtr obj); | 1046 | public static extern int GetNumConstraintRefs2(IntPtr obj); |
1038 | 1047 | ||
1039 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1048 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1040 | public static extern Vector3 GetDeltaLinearVelocity2(IntPtr obj); | ||
1041 | |||
1042 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1043 | public static extern Vector3 GetDeltaAngularVelocity2(IntPtr obj); | ||
1044 | |||
1045 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1046 | public static extern Vector3 GetPushVelocity2(IntPtr obj); | ||
1047 | |||
1048 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1049 | public static extern Vector3 GetTurnVelocity2(IntPtr obj); | ||
1050 | |||
1051 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1052 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | 1049 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); |
1053 | 1050 | ||
1054 | // ===================================================================================== | 1051 | // ===================================================================================== |
@@ -1108,6 +1105,15 @@ public static extern float GetMargin2(IntPtr shape); | |||
1108 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | 1105 | public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); |
1109 | 1106 | ||
1110 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1107 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1108 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | ||
1109 | |||
1110 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1111 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | ||
1112 | |||
1113 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1114 | public static extern void DumpAllInfo2(IntPtr sim); | ||
1115 | |||
1116 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1111 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 1117 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); |
1112 | 1118 | ||
1113 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1119 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |