aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs717
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs51
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs)67
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs)112
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1169
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs437
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs275
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs327
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs104
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs263
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs4
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1392
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs1000
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs1001
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs208
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs170
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs419
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs256
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs791
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs33
21 files changed, 6349 insertions, 2451 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index e2f7af9..4c195e1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -28,62 +28,48 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection; 29using System.Reflection;
30using log4net; 30using log4net;
31using OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.Physics.Manager;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
36{ 36{
37public class BSCharacter : PhysicsActor 37public sealed class BSCharacter : BSPhysObject
38{ 38{
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40 private static readonly string LogHeader = "[BULLETS CHAR]"; 40 private static readonly string LogHeader = "[BULLETS CHAR]";
41 41
42 private BSScene _scene;
43 public BSScene Scene { get { return _scene; } }
44 private String _avName;
45 // private bool _stopped; 42 // private bool _stopped;
46 private Vector3 _size; 43 private OMV.Vector3 _size;
47 private Vector3 _scale;
48 private PrimitiveBaseShape _pbs;
49 private uint _localID = 0;
50 private bool _grabbed; 44 private bool _grabbed;
51 private bool _selected; 45 private bool _selected;
52 private Vector3 _position; 46 private OMV.Vector3 _position;
53 private float _mass; 47 private float _mass;
54 public float _density; 48 private float _avatarDensity;
55 public float _avatarVolume; 49 private float _avatarVolume;
56 private Vector3 _force; 50 private OMV.Vector3 _force;
57 private Vector3 _velocity; 51 private OMV.Vector3 _velocity;
58 private Vector3 _torque; 52 private OMV.Vector3 _torque;
59 private float _collisionScore; 53 private float _collisionScore;
60 private Vector3 _acceleration; 54 private OMV.Vector3 _acceleration;
61 private Quaternion _orientation; 55 private OMV.Quaternion _orientation;
62 private int _physicsActorType; 56 private int _physicsActorType;
63 private bool _isPhysical; 57 private bool _isPhysical;
64 private bool _flying; 58 private bool _flying;
65 private bool _setAlwaysRun; 59 private bool _setAlwaysRun;
66 private bool _throttleUpdates; 60 private bool _throttleUpdates;
67 private bool _isColliding; 61 private bool _isColliding;
68 private long _collidingStep;
69 private bool _collidingGround;
70 private long _collidingGroundStep;
71 private bool _collidingObj; 62 private bool _collidingObj;
72 private bool _floatOnWater; 63 private bool _floatOnWater;
73 private Vector3 _rotationalVelocity; 64 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic; 65 private bool _kinematic;
75 private float _buoyancy; 66 private float _buoyancy;
76 67
77 private BulletBody m_body; 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
78 public BulletBody Body { 69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
79 get { return m_body; } 70 private float _currentFriction; // the friction currently being used (changed by setVelocity).
80 set { m_body = value; }
81 }
82
83 private int _subscribedEventsMs = 0;
84 private int _nextCollisionOkTime = 0;
85 71
86 private Vector3 _PIDTarget; 72 private OMV.Vector3 _PIDTarget;
87 private bool _usePID; 73 private bool _usePID;
88 private float _PIDTau; 74 private float _PIDTau;
89 private bool _useHoverPID; 75 private bool _useHoverPID;
@@ -91,332 +77,529 @@ public class BSCharacter : PhysicsActor
91 private PIDHoverType _PIDHoverType; 77 private PIDHoverType _PIDHoverType;
92 private float _PIDHoverTao; 78 private float _PIDHoverTao;
93 79
94 public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 pos, Vector3 size, bool isFlying) 80 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
81 : base(parent_scene, localID, avName, "BSCharacter")
95 { 82 {
96 _localID = localID; 83 _physicsActorType = (int)ActorTypes.Agent;
97 _avName = avName;
98 _scene = parent_scene;
99 _position = pos; 84 _position = pos;
85
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
100 _size = size; 88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
101 _flying = isFlying; 92 _flying = isFlying;
102 _orientation = Quaternion.Identity; 93 _orientation = OMV.Quaternion.Identity;
103 _velocity = Vector3.Zero; 94 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
104 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 96 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity;
99
105 // The dimensions of the avatar capsule are kept in the scale. 100 // The dimensions of the avatar capsule are kept in the scale.
106 // Physics creates a unit capsule which is scaled by the physics engine. 101 // Physics creates a unit capsule which is scaled by the physics engine.
107 _scale = new Vector3(_scene.Params.avatarCapsuleRadius, _scene.Params.avatarCapsuleRadius, size.Z); 102 ComputeAvatarScale(_size);
108 _density = _scene.Params.avatarDensity; 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
109 ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale 104 ComputeAvatarVolumeAndMass();
110 105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
111 ShapeData shapeData = new ShapeData(); 106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
112 shapeData.ID = _localID;
113 shapeData.Type = ShapeData.PhysicsShapeType.SHAPE_AVATAR;
114 shapeData.Position = _position;
115 shapeData.Rotation = _orientation;
116 shapeData.Velocity = _velocity;
117 shapeData.Scale = _scale;
118 shapeData.Mass = _mass;
119 shapeData.Buoyancy = _buoyancy;
120 shapeData.Static = ShapeData.numericFalse;
121 shapeData.Friction = _scene.Params.avatarFriction;
122 shapeData.Restitution = _scene.Params.avatarRestitution;
123 107
124 // do actual create at taint time 108 // do actual create at taint time
125 _scene.TaintedObject("BSCharacter.create", delegate() 109 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
126 { 110 {
127 BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData); 111 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null);
128 114
129 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); 115 SetPhysicalProperties();
130 // avatars get all collisions no matter what
131 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
132 }); 116 });
133
134 return; 117 return;
135 } 118 }
136 119
137 // called when this character is being destroyed and the resources should be released 120 // called when this character is being destroyed and the resources should be released
138 public void Destroy() 121 public override void Destroy()
139 { 122 {
140 // DetailLog("{0},BSCharacter.Destroy", LocalID); 123 DetailLog("{0},BSCharacter.Destroy", LocalID);
141 _scene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
142 { 125 {
143 BulletSimAPI.DestroyObject(_scene.WorldID, _localID); 126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
144 }); 128 });
145 } 129 }
146 130
131 private void SetPhysicalProperties()
132 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
134
135 ZeroMotion(true);
136 ForcePosition = _position;
137 // Set the velocity and compute the proper friction
138 ForceVelocity = _velocity;
139
140 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying;
143
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
149 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
152 }
153
154 UpdatePhysicalMassProperties(RawMass);
155
156 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero);
158
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT);
160
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
162
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
166
167 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr,
169 (uint)CollisionFilterGroups.AvatarFilter,
170 (uint)CollisionFilterGroups.AvatarMask);
171 }
172
147 public override void RequestPhysicsterseUpdate() 173 public override void RequestPhysicsterseUpdate()
148 { 174 {
149 base.RequestPhysicsterseUpdate(); 175 base.RequestPhysicsterseUpdate();
150 } 176 }
151 // No one calls this method so I don't know what it could possibly mean 177 // No one calls this method so I don't know what it could possibly mean
152 public override bool Stopped { 178 public override bool Stopped { get { return false; } }
153 get { return false; } 179
154 } 180 public override OMV.Vector3 Size {
155 public override Vector3 Size {
156 get 181 get
157 { 182 {
158 // Avatar capsule size is kept in the scale parameter. 183 // Avatar capsule size is kept in the scale parameter.
159 return new Vector3(_scale.X * 2, _scale.Y * 2, _scale.Z); 184 return _size;
160 } 185 }
161 186
162 set { 187 set {
163 // When an avatar's size is set, only the height is changed 188 // When an avatar's size is set, only the height is changed.
164 // and that really only depends on the radius.
165 _size = value; 189 _size = value;
166 _scale.Z = (_size.Z * 1.15f) - (_scale.X + _scale.Y); 190 ComputeAvatarScale(_size);
167
168 // TODO: something has to be done with the avatar's vertical position
169
170 ComputeAvatarVolumeAndMass(); 191 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
171 194
172 _scene.TaintedObject("BSCharacter.setSize", delegate() 195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
173 { 196 {
174 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true); 197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
198 UpdatePhysicalMassProperties(RawMass);
175 }); 199 });
176 200
177 } 201 }
178 } 202 }
179 public override PrimitiveBaseShape Shape { 203
180 set { _pbs = value; 204 public override OMV.Vector3 Scale { get; set; }
181 } 205
206 public override PrimitiveBaseShape Shape
207 {
208 set { BaseShape = value; }
182 } 209 }
183 public override uint LocalID { 210 // I want the physics engine to make an avatar capsule
184 set { _localID = value; 211 public override BSPhysicsShapeType PreferredPhysicalShape
185 } 212 {
186 get { return _localID; } 213 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
187 } 214 }
188 public override bool Grabbed { 215
189 set { _grabbed = value; 216 public override bool Grabbed {
190 } 217 set { _grabbed = value; }
191 } 218 }
192 public override bool Selected { 219 public override bool Selected {
193 set { _selected = value; 220 set { _selected = value; }
194 }
195 } 221 }
196 public override void CrossingFailure() { return; } 222 public override void CrossingFailure() { return; }
197 public override void link(PhysicsActor obj) { return; } 223 public override void link(PhysicsActor obj) { return; }
198 public override void delink() { return; } 224 public override void delink() { return; }
199 public override void LockAngularMotion(Vector3 axis) { return; }
200 225
201 public override Vector3 Position { 226 // Set motion values to zero.
227 // Do it to the properties so the values get set in the physics engine.
228 // Push the setting of the values to the viewer.
229 // Called at taint time!
230 public override void ZeroMotion(bool inTaintTime)
231 {
232 _velocity = OMV.Vector3.Zero;
233 _acceleration = OMV.Vector3.Zero;
234 _rotationalVelocity = OMV.Vector3.Zero;
235
236 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
240 });
241 }
242 public override void ZeroAngularMotion(bool inTaintTime)
243 {
244 _rotationalVelocity = OMV.Vector3.Zero;
245
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
250 // The next also get rid of applied linear force but the linear velocity is untouched.
251 BulletSimAPI.ClearForces2(PhysBody.ptr);
252 });
253 }
254
255
256 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
257
258 public override OMV.Vector3 RawPosition
259 {
260 get { return _position; }
261 set { _position = value; }
262 }
263 public override OMV.Vector3 Position {
202 get { 264 get {
203 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 265 // Don't refetch the position because this function is called a zillion times
204 return _position; 266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID);
205 } 267 return _position;
268 }
206 set { 269 set {
207 _position = value; 270 _position = value;
208 PositionSanityCheck(); 271 PositionSanityCheck();
209 272
210 _scene.TaintedObject("BSCharacter.setPosition", delegate() 273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
211 { 274 {
212 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
213 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
214 }); 277 });
215 } 278 }
279 }
280 public override OMV.Vector3 ForcePosition {
281 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
283 return _position;
284 }
285 set {
286 _position = value;
287 PositionSanityCheck();
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
289 }
216 } 290 }
217 291
292
218 // Check that the current position is sane and, if not, modify the position to make it so. 293 // Check that the current position is sane and, if not, modify the position to make it so.
219 // Check for being below terrain and being out of bounds. 294 // Check for being below terrain or on water.
220 // Returns 'true' of the position was made sane by some action. 295 // Returns 'true' of the position was made sane by some action.
221 private bool PositionSanityCheck() 296 private bool PositionSanityCheck()
222 { 297 {
223 bool ret = false; 298 bool ret = false;
224 299
225 // If below the ground, move the avatar up 300 // If below the ground, move the avatar up
226 float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position); 301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
227 if (_position.Z < terrainHeight) 302 if (Position.Z < terrainHeight)
228 { 303 {
229 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation); 304 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
230 _position.Z = terrainHeight + 2.0f; 305 _position.Z = terrainHeight + 2.0f;
231 ret = true; 306 ret = true;
232 } 307 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight)
312 {
313 _position.Z = waterHeight;
314 ret = true;
315 }
316 }
233 317
234 // TODO: check for out of bounds 318 // TODO: check for out of bounds
319 return ret;
320 }
235 321
322 // 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
324 // who is not already pushing the value.
325 private bool PositionSanityCheck(bool inTaintTime)
326 {
327 bool ret = false;
328 if (PositionSanityCheck())
329 {
330 // The new position value must be pushed into the physics engine but we can't
331 // just assign to "Position" because of potential call loops.
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
336 });
337 ret = true;
338 }
236 return ret; 339 return ret;
237 } 340 }
238 341
239 public override float Mass { 342 public override float Mass { get { return _mass; } }
240 get { 343
241 return _mass; 344 // used when we only want this prim's mass and not the linkset thing
242 } 345 public override float RawMass {
346 get {return _mass; }
243 } 347 }
244 public override Vector3 Force { 348 public override void UpdatePhysicalMassProperties(float physMass)
245 get { return _force; } 349 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia);
352 }
353
354 public override OMV.Vector3 Force {
355 get { return _force; }
246 set { 356 set {
247 _force = value; 357 _force = value;
248 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 358 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
249 Scene.TaintedObject("BSCharacter.SetForce", delegate() 359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
250 { 360 {
251 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
252 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force); 362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
253 }); 363 });
254 } 364 }
255 } 365 }
256 366
257 public override int VehicleType { 367 // Avatars don't do vehicles
258 get { return 0; } 368 public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
259 set { return; }
260 }
261 public override void VehicleFloatParam(int param, float value) { } 369 public override void VehicleFloatParam(int param, float value) { }
262 public override void VehicleVectorParam(int param, Vector3 value) {} 370 public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
263 public override void VehicleRotationParam(int param, Quaternion rotation) { } 371 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
264 public override void VehicleFlags(int param, bool remove) { } 372 public override void VehicleFlags(int param, bool remove) { }
265 373
266 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 374 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
267 public override void SetVolumeDetect(int param) { return; } 375 public override void SetVolumeDetect(int param) { return; }
268 376
269 public override Vector3 GeometricCenter { get { return Vector3.Zero; } } 377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
270 public override Vector3 CenterOfMass { get { return Vector3.Zero; } } 378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
271 public override Vector3 Velocity { 379 public override OMV.Vector3 Velocity {
272 get { return _velocity; } 380 get { return _velocity; }
273 set { 381 set {
274 _velocity = value; 382 _velocity = value;
275 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
276 _scene.TaintedObject("BSCharacter.setVelocity", delegate() 384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
277 { 385 {
278 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
279 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); 387 ForceVelocity = _velocity;
280 }); 388 });
281 } 389 }
282 } 390 }
283 public override Vector3 Torque { 391 public override OMV.Vector3 ForceVelocity {
284 get { return _torque; } 392 get { return _velocity; }
285 set { _torque = value; 393 set {
286 } 394 // Depending on whether the avatar is moving or not, change the friction
395 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0)
397 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
399 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
402 }
403 }
404 else
405 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction)
407 {
408 _currentFriction = PhysicsScene.Params.avatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
410 }
411 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
417 BulletSimAPI.Activate2(PhysBody.ptr, true);
418 }
287 } 419 }
288 public override float CollisionScore { 420 public override OMV.Vector3 Torque {
289 get { return _collisionScore; } 421 get { return _torque; }
290 set { _collisionScore = value; 422 set { _torque = value;
291 } 423 }
424 }
425 public override float CollisionScore {
426 get { return _collisionScore; }
427 set { _collisionScore = value;
428 }
292 } 429 }
293 public override Vector3 Acceleration { 430 public override OMV.Vector3 Acceleration {
294 get { return _acceleration; } 431 get { return _acceleration; }
295 set { _acceleration = value; } 432 set { _acceleration = value; }
296 } 433 }
297 public override Quaternion Orientation { 434 public override OMV.Quaternion RawOrientation
298 get { return _orientation; } 435 {
436 get { return _orientation; }
437 set { _orientation = value; }
438 }
439 public override OMV.Quaternion Orientation {
440 get { return _orientation; }
299 set { 441 set {
300 _orientation = value; 442 _orientation = value;
301 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
302 _scene.TaintedObject("BSCharacter.setOrientation", delegate() 444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
303 { 445 {
304 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
305 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
306 }); 448 });
307 } 449 }
308 } 450 }
309 public override int PhysicsActorType { 451 // Go directly to Bullet to get/set the value.
310 get { return _physicsActorType; } 452 public override OMV.Quaternion ForceOrientation
311 set { _physicsActorType = value; 453 {
312 } 454 get
455 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
457 return _orientation;
458 }
459 set
460 {
461 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
463 }
313 } 464 }
314 public override bool IsPhysical { 465 public override int PhysicsActorType {
315 get { return _isPhysical; } 466 get { return _physicsActorType; }
467 set { _physicsActorType = value;
468 }
469 }
470 public override bool IsPhysical {
471 get { return _isPhysical; }
316 set { _isPhysical = value; 472 set { _isPhysical = value;
317 } 473 }
474 }
475 public override bool IsSolid {
476 get { return true; }
318 } 477 }
319 public override bool Flying { 478 public override bool IsStatic {
320 get { return _flying; } 479 get { return false; }
480 }
481 public override bool Flying {
482 get { return _flying; }
321 set { 483 set {
322 if (_flying != value) 484 _flying = value;
323 { 485 // simulate flying by changing the effect of gravity
324 _flying = value; 486 Buoyancy = ComputeBuoyancyFromFlying(_flying);
325 // simulate flying by changing the effect of gravity 487 }
326 this.Buoyancy = ComputeBuoyancyFromFlying(_flying);
327 }
328 }
329 } 488 }
489 // Flying is implimented by changing the avatar's buoyancy.
490 // Would this be done better with a vehicle type?
330 private float ComputeBuoyancyFromFlying(bool ifFlying) { 491 private float ComputeBuoyancyFromFlying(bool ifFlying) {
331 return ifFlying ? 1f : 0f; 492 return ifFlying ? 1f : 0f;
332 } 493 }
333 public override bool 494 public override bool
334 SetAlwaysRun { 495 SetAlwaysRun {
335 get { return _setAlwaysRun; } 496 get { return _setAlwaysRun; }
336 set { _setAlwaysRun = value; } 497 set { _setAlwaysRun = value; }
337 } 498 }
338 public override bool ThrottleUpdates { 499 public override bool ThrottleUpdates {
339 get { return _throttleUpdates; } 500 get { return _throttleUpdates; }
340 set { _throttleUpdates = value; } 501 set { _throttleUpdates = value; }
341 } 502 }
342 public override bool IsColliding { 503 public override bool IsColliding {
343 get { return (_collidingStep == _scene.SimulationStep); } 504 get { return (CollidingStep == PhysicsScene.SimulationStep); }
344 set { _isColliding = value; } 505 set { _isColliding = value; }
345 } 506 }
346 public override bool CollidingGround { 507 public override bool CollidingGround {
347 get { return (_collidingGroundStep == _scene.SimulationStep); } 508 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
348 set { _collidingGround = value; } 509 set { CollidingGround = value; }
349 } 510 }
350 public override bool CollidingObj { 511 public override bool CollidingObj {
351 get { return _collidingObj; } 512 get { return _collidingObj; }
352 set { _collidingObj = value; } 513 set { _collidingObj = value; }
353 } 514 }
354 public override bool FloatOnWater { 515 public override bool FloatOnWater {
355 set { _floatOnWater = value; } 516 set {
517 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 {
520 if (_floatOnWater)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
522 else
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
524 });
525 }
526 }
527 public override OMV.Vector3 RotationalVelocity {
528 get { return _rotationalVelocity; }
529 set { _rotationalVelocity = value; }
356 } 530 }
357 public override Vector3 RotationalVelocity { 531 public override OMV.Vector3 ForceRotationalVelocity {
358 get { return _rotationalVelocity; } 532 get { return _rotationalVelocity; }
359 set { _rotationalVelocity = value; } 533 set { _rotationalVelocity = value; }
360 } 534 }
361 public override bool Kinematic { 535 public override bool Kinematic {
362 get { return _kinematic; } 536 get { return _kinematic; }
363 set { _kinematic = value; } 537 set { _kinematic = value; }
364 } 538 }
365 // neg=fall quickly, 0=1g, 1=0g, pos=float up 539 // neg=fall quickly, 0=1g, 1=0g, pos=float up
366 public override float Buoyancy { 540 public override float Buoyancy {
367 get { return _buoyancy; } 541 get { return _buoyancy; }
368 set { _buoyancy = value; 542 set { _buoyancy = value;
369 _scene.TaintedObject("BSCharacter.setBuoyancy", delegate() 543 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate()
370 { 544 {
371 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 545 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
372 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); 546 ForceBuoyancy = _buoyancy;
373 }); 547 });
374 } 548 }
549 }
550 public override float ForceBuoyancy {
551 get { return _buoyancy; }
552 set { _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
557 }
375 } 558 }
376 559
377 // Used for MoveTo 560 // Used for MoveTo
378 public override Vector3 PIDTarget { 561 public override OMV.Vector3 PIDTarget {
379 set { _PIDTarget = value; } 562 set { _PIDTarget = value; }
380 } 563 }
381 public override bool PIDActive { 564 public override bool PIDActive {
382 set { _usePID = value; } 565 set { _usePID = value; }
383 } 566 }
384 public override float PIDTau { 567 public override float PIDTau {
385 set { _PIDTau = value; } 568 set { _PIDTau = value; }
386 } 569 }
387 570
388 // Used for llSetHoverHeight and maybe vehicle height 571 // Used for llSetHoverHeight and maybe vehicle height
389 // Hover Height will override MoveTo target's Z 572 // Hover Height will override MoveTo target's Z
390 public override bool PIDHoverActive { 573 public override bool PIDHoverActive {
391 set { _useHoverPID = value; } 574 set { _useHoverPID = value; }
392 } 575 }
393 public override float PIDHoverHeight { 576 public override float PIDHoverHeight {
394 set { _PIDHoverHeight = value; } 577 set { _PIDHoverHeight = value; }
395 } 578 }
396 public override PIDHoverType PIDHoverType { 579 public override PIDHoverType PIDHoverType {
397 set { _PIDHoverType = value; } 580 set { _PIDHoverType = value; }
398 } 581 }
399 public override float PIDHoverTau { 582 public override float PIDHoverTau {
400 set { _PIDHoverTao = value; } 583 set { _PIDHoverTao = value; }
401 } 584 }
402 585
403 // For RotLookAt 586 // For RotLookAt
404 public override Quaternion APIDTarget { set { return; } } 587 public override OMV.Quaternion APIDTarget { set { return; } }
405 public override bool APIDActive { set { return; } } 588 public override bool APIDActive { set { return; } }
406 public override float APIDStrength { set { return; } } 589 public override float APIDStrength { set { return; } }
407 public override float APIDDamping { set { return; } } 590 public override float APIDDamping { set { return; } }
408 591
409 public override void AddForce(Vector3 force, bool pushforce) { 592 public override void AddForce(OMV.Vector3 force, bool pushforce) {
410 if (force.IsFinite()) 593 if (force.IsFinite())
411 { 594 {
412 _force.X += force.X; 595 _force.X += force.X;
413 _force.Y += force.Y; 596 _force.Y += force.Y;
414 _force.Z += force.Z; 597 _force.Z += force.Z;
415 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); 598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
416 _scene.TaintedObject("BSCharacter.AddForce", delegate() 599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
417 { 600 {
418 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force);
419 BulletSimAPI.AddObjectForce2(Body.Ptr, _force); 602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
420 }); 603 });
421 } 604 }
422 else 605 else
@@ -426,129 +609,81 @@ public class BSCharacter : PhysicsActor
426 //m_lastUpdateSent = false; 609 //m_lastUpdateSent = false;
427 } 610 }
428 611
429 public override void AddAngularForce(Vector3 force, bool pushforce) { 612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
430 } 613 }
431 public override void SetMomentum(Vector3 momentum) { 614 public override void SetMomentum(OMV.Vector3 momentum) {
432 } 615 }
433 616
434 // Turn on collision events at a rate no faster than one every the given milliseconds 617 private void ComputeAvatarScale(OMV.Vector3 size)
435 public override void SubscribeEvents(int ms) { 618 {
436 _subscribedEventsMs = ms; 619 // The 'size' given by the simulator is the mid-point of the avatar
437 if (ms > 0) 620 // and X and Y are unspecified.
438 {
439 // make sure first collision happens
440 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
441 621
442 Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate() 622 OMV.Vector3 newScale = size;
443 { 623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth;
444 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth;
445 }); 625
446 } 626 // From the total height, remove the capsule half spheres that are at each end
447 } 627 // The 1.15f came from ODE. Not sure what this factors in.
448 // Stop collision events 628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y);
449 public override void UnSubscribeEvents() { 629
450 _subscribedEventsMs = 0; 630 // The total scale height is the central cylindar plus the caps on the two ends.
451 // Avatars get all their collision events 631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f);
452 // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate() 632
453 // { 633 // Convert diameters to radii and height to half height -- the way Bullet expects it.
454 // BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 634 Scale = newScale / 2f;
455 // });
456 }
457 // Return 'true' if someone has subscribed to events
458 public override bool SubscribedEvents() {
459 return (_subscribedEventsMs > 0);
460 } 635 }
461 636
462 // set _avatarVolume and _mass based on capsule size, _density and _scale 637 // set _avatarVolume and _mass based on capsule size, _density and Scale
463 private void ComputeAvatarVolumeAndMass() 638 private void ComputeAvatarVolumeAndMass()
464 { 639 {
465 _avatarVolume = (float)( 640 _avatarVolume = (float)(
466 Math.PI 641 Math.PI
467 * _scale.X 642 * Scale.X
468 * _scale.Y // the area of capsule cylinder 643 * Scale.Y // the area of capsule cylinder
469 * _scale.Z // times height of capsule cylinder 644 * Scale.Z // times height of capsule cylinder
470 + 1.33333333f 645 + 1.33333333f
471 * Math.PI 646 * Math.PI
472 * _scale.X 647 * Scale.X
473 * Math.Min(_scale.X, _scale.Y) 648 * Math.Min(Scale.X, Scale.Y)
474 * _scale.Y // plus the volume of the capsule end caps 649 * Scale.Y // plus the volume of the capsule end caps
475 ); 650 );
476 _mass = _density * _avatarVolume; 651 _mass = _avatarDensity * _avatarVolume;
477 } 652 }
478 653
479 // The physics engine says that properties have updated. Update same and inform 654 // The physics engine says that properties have updated. Update same and inform
480 // the world that things have changed. 655 // the world that things have changed.
481 public void UpdateProperties(EntityProperties entprop) 656 public override void UpdateProperties(EntityProperties entprop)
482 { 657 {
483 _position = entprop.Position; 658 _position = entprop.Position;
484 _orientation = entprop.Rotation; 659 _orientation = entprop.Rotation;
485 _velocity = entprop.Velocity; 660 _velocity = entprop.Velocity;
486 _acceleration = entprop.Acceleration; 661 _acceleration = entprop.Acceleration;
487 _rotationalVelocity = entprop.RotationalVelocity; 662 _rotationalVelocity = entprop.RotationalVelocity;
488 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
489 // base.RequestPhysicsterseUpdate(); 664 PositionSanityCheck(true);
490 665
491 /* 666 // remember the current and last set values
492 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 667 LastEntityProperties = CurrentEntityProperties;
493 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 668 CurrentEntityProperties = entprop;
494 entprop.Acceleration, entprop.RotationalVelocity);
495 */
496 }
497 669
498 // Called by the scene when a collision with this object is reported 670 if (entprop.Velocity != LastEntityProperties.Velocity)
499 // The collision, if it should be reported to the character, is placed in a collection
500 // that will later be sent to the simulator when SendCollisions() is called.
501 CollisionEventUpdate collisionCollection = null;
502 public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth)
503 {
504 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
505
506 // The following makes IsColliding() and IsCollidingGround() work
507 _collidingStep = _scene.SimulationStep;
508 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
509 { 671 {
510 _collidingGroundStep = _scene.SimulationStep; 672 // Changes in the velocity are suppressed in avatars.
673 // That's just the way they are defined.
674 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
675 _velocity = avVel;
676 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
511 } 677 }
512 // DetailLog("{0},BSCharacter.Collison,call,with={1}", LocalID, collidingWith);
513 678
514 // throttle collisions to the rate specified in the subscription 679 // Tell the linkset about value changes
515 if (_subscribedEventsMs != 0) { 680 Linkset.UpdateProperties(this);
516 int nowTime = _scene.SimulationNowTime;
517 if (nowTime >= _nextCollisionOkTime) {
518 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
519 681
520 if (collisionCollection == null) 682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
521 collisionCollection = new CollisionEventUpdate(); 683 // base.RequestPhysicsterseUpdate();
522 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
523 }
524 }
525 }
526 684
527 public void SendCollisions() 685 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
528 { 686 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
529 /*
530 if (collisionCollection != null && collisionCollection.Count > 0)
531 {
532 base.SendCollisionUpdate(collisionCollection);
533 collisionCollection = null;
534 }
535 */
536 // Kludge to make a collision call even if there are no collisions.
537 // This causes the avatar animation to get updated.
538 if (collisionCollection == null)
539 collisionCollection = new CollisionEventUpdate();
540 base.SendCollisionUpdate(collisionCollection);
541 // If there were any collisions in the collection, make sure we don't use the
542 // same instance next time.
543 if (collisionCollection.Count > 0)
544 collisionCollection = null;
545 // End kludge
546 }
547
548 // Invoke the detailed logger and output something if it's enabled.
549 private void DetailLog(string msg, params Object[] args)
550 {
551 Scene.PhysicsLogging.Write(msg, args);
552 } 687 }
553} 688}
554} 689}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 25084d8..65fac00 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -34,12 +34,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34 34
35public abstract class BSConstraint : IDisposable 35public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38
37 protected BulletSim m_world; 39 protected BulletSim m_world;
38 protected BulletBody m_body1; 40 protected BulletBody m_body1;
39 protected BulletBody m_body2; 41 protected BulletBody m_body2;
40 protected BulletConstraint m_constraint; 42 protected BulletConstraint m_constraint;
41 protected bool m_enabled = false; 43 protected bool m_enabled = false;
42 44
45 public BulletBody Body1 { get { return m_body1; } }
46 public BulletBody Body2 { get { return m_body2; } }
47 public BulletConstraint Constraint { get { return m_constraint; } }
48 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } }
50
43 public BSConstraint() 51 public BSConstraint()
44 { 52 {
45 } 53 }
@@ -48,22 +56,25 @@ public abstract class BSConstraint : IDisposable
48 { 56 {
49 if (m_enabled) 57 if (m_enabled)
50 { 58 {
51 // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
52 bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
53 m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
54 m_constraint.Ptr = System.IntPtr.Zero;
55 m_enabled = false; 59 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero)
61 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
64 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString("X"),
66 m_body2.ID, m_body2.ptr.ToString("X"),
67 success);
68 m_constraint.ptr = System.IntPtr.Zero;
69 }
56 } 70 }
57 } 71 }
58 72
59 public BulletBody Body1 { get { return m_body1; } }
60 public BulletBody Body2 { get { return m_body2; } }
61
62 public virtual bool SetLinearLimits(Vector3 low, Vector3 high) 73 public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
63 { 74 {
64 bool ret = false; 75 bool ret = false;
65 if (m_enabled) 76 if (m_enabled)
66 ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high); 77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high);
67 return ret; 78 return ret;
68 } 79 }
69 80
@@ -71,7 +82,18 @@ public abstract class BSConstraint : IDisposable
71 { 82 {
72 bool ret = false; 83 bool ret = false;
73 if (m_enabled) 84 if (m_enabled)
74 ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high); 85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high);
86 return ret;
87 }
88
89 public virtual bool SetSolverIterations(float cnt)
90 {
91 bool ret = false;
92 if (m_enabled)
93 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt);
95 ret = true;
96 }
75 return ret; 97 return ret;
76 } 98 }
77 99
@@ -81,7 +103,7 @@ public abstract class BSConstraint : IDisposable
81 if (m_enabled) 103 if (m_enabled)
82 { 104 {
83 // Recompute the internal transforms 105 // Recompute the internal transforms
84 BulletSimAPI.CalculateTransforms2(m_constraint.Ptr); 106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr);
85 ret = true; 107 ret = true;
86 } 108 }
87 return ret; 109 return ret;
@@ -97,13 +119,14 @@ public abstract class BSConstraint : IDisposable
97 ret = CalculateTransforms(); 119 ret = CalculateTransforms();
98 if (ret) 120 if (ret)
99 { 121 {
100 // m_world.scene.PhysicsLogging.Write("{0},BSConstraint.RecomputeConstraintVariables,taint,enabling,A={1},B={2}", 122 // Setting an object's mass to zero (making it static like when it's selected)
101 // BSScene.DetailLogZero, Body1.ID, Body2.ID); 123 // automatically disables the constraints.
102 BulletSimAPI.SetConstraintEnable2(m_constraint.Ptr, m_world.scene.NumericBool(true)); 124 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
103 } 126 }
104 else 127 else
105 { 128 {
106 m_world.scene.Logger.ErrorFormat("[BULLETSIM CONSTRAINT] CalculateTransforms failed. A={0}, B={1}", Body1.ID, Body2.ID); 129 m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID);
107 } 130 }
108 } 131 }
109 return ret; 132 return ret;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 683bc51..23ef052 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -32,10 +32,14 @@ using OpenMetaverse;
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35public class BS6DofConstraint : BSConstraint 35public sealed class BSConstraint6Dof : BSConstraint
36{ 36{
37 private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]";
38
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40
37 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
38 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
39 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
40 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
41 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
@@ -44,25 +48,52 @@ public class BS6DofConstraint : BSConstraint
44 m_body1 = obj1; 48 m_body1 = obj1;
45 m_body2 = obj2; 49 m_body2 = obj2;
46 m_constraint = new BulletConstraint( 50 m_constraint = new BulletConstraint(
47 BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
48 frame1, frame1rot, 52 frame1, frame1rot,
49 frame2, frame2rot, 53 frame2, frame2rot,
50 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
51 m_enabled = true; 55 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
52 } 59 }
53 60
54 public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2,
55 Vector3 joinPoint, 62 Vector3 joinPoint,
56 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
57 { 64 {
58 m_world = world; 65 m_world = world;
59 m_body1 = obj1; 66 m_body1 = obj1;
60 m_body2 = obj2; 67 m_body2 = obj2;
61 m_constraint = new BulletConstraint( 68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
62 BulletSimAPI.Create6DofConstraintToPoint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 69 {
63 joinPoint, 70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
64 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 71 BSScene.DetailLogZero, world.worldID,
65 m_enabled = true; 72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
75 m_enabled = false;
76 }
77 else
78 {
79 m_constraint = new BulletConstraint(
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"),
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
86 if (m_constraint.ptr == IntPtr.Zero)
87 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID);
90 m_enabled = false;
91 }
92 else
93 {
94 m_enabled = true;
95 }
96 }
66 } 97 }
67 98
68 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) 99 public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
@@ -70,7 +101,7 @@ public class BS6DofConstraint : BSConstraint
70 bool ret = false; 101 bool ret = false;
71 if (m_enabled) 102 if (m_enabled)
72 { 103 {
73 BulletSimAPI.SetFrames2(m_constraint.Ptr, frameA, frameArot, frameB, frameBrot); 104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
74 ret = true; 105 ret = true;
75 } 106 }
76 return ret; 107 return ret;
@@ -81,9 +112,9 @@ public class BS6DofConstraint : BSConstraint
81 bool ret = false; 112 bool ret = false;
82 if (m_enabled) 113 if (m_enabled)
83 { 114 {
84 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
85 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
86 BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
87 ret = true; 118 ret = true;
88 } 119 }
89 return ret; 120 return ret;
@@ -94,7 +125,7 @@ public class BS6DofConstraint : BSConstraint
94 bool ret = false; 125 bool ret = false;
95 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
96 if (m_enabled) 127 if (m_enabled)
97 ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff); 128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff);
98 return ret; 129 return ret;
99 } 130 }
100 131
@@ -103,7 +134,11 @@ public class BS6DofConstraint : BSConstraint
103 bool ret = false; 134 bool ret = false;
104 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
105 if (m_enabled) 136 if (m_enabled)
106 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce); 137 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 }
107 return ret; 142 return ret;
108 } 143 }
109 144
@@ -111,7 +146,7 @@ public class BS6DofConstraint : BSConstraint
111 { 146 {
112 bool ret = false; 147 bool ret = false;
113 if (m_enabled) 148 if (m_enabled)
114 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.Ptr, threshold); 149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold);
115 return ret; 150 return ret;
116 } 151 }
117} 152}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index 22ea367..a9fd826 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 35
36public class BSConstraintCollection : IDisposable 36public sealed class BSConstraintCollection : IDisposable
37{ 37{
38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 38 // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; 39 // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
@@ -143,8 +143,6 @@ public class BSConstraintCollection : IDisposable
143 // Return 'true' if any constraints were destroyed. 143 // Return 'true' if any constraints were destroyed.
144 public bool RemoveAndDestroyConstraint(BulletBody body1) 144 public bool RemoveAndDestroyConstraint(BulletBody body1)
145 { 145 {
146 // return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
147
148 List<BSConstraint> toRemove = new List<BSConstraint>(); 146 List<BSConstraint> toRemove = new List<BSConstraint>();
149 uint lookingID = body1.ID; 147 uint lookingID = body1.ID;
150 lock (m_constraints) 148 lock (m_constraints)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index d68048b..ed3ffa7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSHingeConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -1,55 +1,57 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products 13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission. 14 * derived from this software without specific prior written permission.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30using OpenMetaverse; 30using OpenMetaverse;
31 31
32namespace OpenSim.Region.Physics.BulletSPlugin 32namespace OpenSim.Region.Physics.BulletSPlugin
33{ 33{
34 34
35class BSHingeConstraint : BSConstraint 35public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public BSHingeConstraint(BulletSim world, BulletBody obj1, BulletBody obj2, 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 Vector3 pivotInA, Vector3 pivotInB, 38
39 Vector3 axisInA, Vector3 axisInB, 39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2,
40 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 40 Vector3 pivotInA, Vector3 pivotInB,
41 { 41 Vector3 axisInA, Vector3 axisInB,
42 m_world = world; 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 m_body1 = obj1; 43 {
44 m_body2 = obj2; 44 m_world = world;
45 m_constraint = new BulletConstraint( 45 m_body1 = obj1;
46 BulletSimAPI.CreateHingeConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr, 46 m_body2 = obj2;
47 pivotInA, pivotInB, 47 m_constraint = new BulletConstraint(
48 axisInA, axisInB, 48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 49 pivotInA, pivotInB,
50 m_enabled = true; 50 axisInA, axisInB,
51 } 51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 52 m_enabled = true;
53} 53 }
54 54
55} 55}
56
57}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 5a9f135..dbc9039 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -23,7 +23,7 @@
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 *
27 27
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to
29 * call the BulletSim system. 29 * call the BulletSim system.
@@ -52,19 +52,20 @@ using OpenSim.Region.Physics.Manager;
52 52
53namespace OpenSim.Region.Physics.BulletSPlugin 53namespace OpenSim.Region.Physics.BulletSPlugin
54{ 54{
55 public class BSDynamics 55 public sealed class BSDynamics
56 { 56 {
57 private int frcount = 0; // Used to limit dynamics debug output to 57 private static string LogHeader = "[BULLETSIM VEHICLE]";
58 // every 100th frame 58
59 private BSScene PhysicsScene { get; set; }
60 // the prim this dynamic controller belongs to
61 private BSPrim Prim { get; set; }
59 62
60 private BSPrim m_prim; // the prim this dynamic controller belongs to 63 // mass of the vehicle fetched each time we're calles
64 private float m_vehicleMass;
61 65
62 // Vehicle properties 66 // Vehicle properties
63 private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind 67 public Vehicle Type { get; set; }
64 public Vehicle Type 68
65 {
66 get { return m_type; }
67 }
68 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier 69 // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
69 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: 70 private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
70 // HOVER_TERRAIN_ONLY 71 // HOVER_TERRAIN_ONLY
@@ -74,13 +75,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
74 // HOVER_UP_ONLY 75 // HOVER_UP_ONLY
75 // LIMIT_MOTOR_UP 76 // LIMIT_MOTOR_UP
76 // LIMIT_ROLL_ONLY 77 // LIMIT_ROLL_ONLY
77 private VehicleFlag m_Hoverflags = (VehicleFlag)0;
78 private Vector3 m_BlockingEndPoint = Vector3.Zero; 78 private Vector3 m_BlockingEndPoint = Vector3.Zero;
79 private Quaternion m_RollreferenceFrame = Quaternion.Identity; 79 private Quaternion m_RollreferenceFrame = Quaternion.Identity;
80 private Quaternion m_referenceFrame = Quaternion.Identity;
81
80 // Linear properties 82 // Linear properties
81 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
82 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
83 private Vector3 m_dir = Vector3.Zero; // velocity applied to body 86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
84 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 87 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
85 private float m_linearMotorDecayTimescale = 0; 88 private float m_linearMotorDecayTimescale = 0;
86 private float m_linearMotorTimescale = 0; 89 private float m_linearMotorTimescale = 0;
@@ -91,28 +94,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
91 94
92 //Angular properties 95 //Angular properties
93 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
94 private int m_angularMotorApply = 0; // application frame counter 97 // private int m_angularMotorApply = 0; // application frame counter
95 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
96 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
97 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
98 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 101 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
99 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 102 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body
100 // private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
101 104
102 //Deflection properties 105 //Deflection properties
103 // private float m_angularDeflectionEfficiency = 0; 106 private float m_angularDeflectionEfficiency = 0;
104 // private float m_angularDeflectionTimescale = 0; 107 private float m_angularDeflectionTimescale = 0;
105 // private float m_linearDeflectionEfficiency = 0; 108 private float m_linearDeflectionEfficiency = 0;
106 // private float m_linearDeflectionTimescale = 0; 109 private float m_linearDeflectionTimescale = 0;
107 110
108 //Banking properties 111 //Banking properties
109 // private float m_bankingEfficiency = 0; 112 private float m_bankingEfficiency = 0;
110 // private float m_bankingMix = 0; 113 private float m_bankingMix = 0;
111 // private float m_bankingTimescale = 0; 114 private float m_bankingTimescale = 0;
112 115
113 //Hover and Buoyancy properties 116 //Hover and Buoyancy properties
114 private float m_VhoverHeight = 0f; 117 private float m_VhoverHeight = 0f;
115// private float m_VhoverEfficiency = 0f; 118 private float m_VhoverEfficiency = 0f;
116 private float m_VhoverTimescale = 0f; 119 private float m_VhoverTimescale = 0f;
117 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 120 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
118 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 121 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle.
@@ -124,86 +127,74 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 private float m_verticalAttractionEfficiency = 1.0f; // damped 127 private float m_verticalAttractionEfficiency = 1.0f; // damped
125 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
126 129
127 public BSDynamics(BSPrim myPrim) 130 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 {
132 PhysicsScene = myScene;
133 Prim = myPrim;
134 Type = Vehicle.TYPE_NONE;
135 }
136
137 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive
128 { 139 {
129 m_prim = myPrim; 140 get { return Type != Vehicle.TYPE_NONE; }
130 m_type = Vehicle.TYPE_NONE;
131 } 141 }
132 142
133 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) 143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
134 { 144 {
135 DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 145 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
136 switch (pParam) 146 switch (pParam)
137 { 147 {
138 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 148 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
139 if (pValue < 0.01f) pValue = 0.01f; 149 m_angularDeflectionEfficiency = Math.Max(pValue, 0.01f);
140 // m_angularDeflectionEfficiency = pValue;
141 break; 150 break;
142 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE: 151 case Vehicle.ANGULAR_DEFLECTION_TIMESCALE:
143 if (pValue < 0.01f) pValue = 0.01f; 152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
144 // m_angularDeflectionTimescale = pValue;
145 break; 153 break;
146 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
147 if (pValue < 0.01f) pValue = 0.01f; 155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
148 m_angularMotorDecayTimescale = pValue;
149 break; 156 break;
150 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 157 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
151 if (pValue < 0.01f) pValue = 0.01f; 158 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
152 m_angularMotorTimescale = pValue;
153 break; 159 break;
154 case Vehicle.BANKING_EFFICIENCY: 160 case Vehicle.BANKING_EFFICIENCY:
155 if (pValue < 0.01f) pValue = 0.01f; 161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
156 // m_bankingEfficiency = pValue;
157 break; 162 break;
158 case Vehicle.BANKING_MIX: 163 case Vehicle.BANKING_MIX:
159 if (pValue < 0.01f) pValue = 0.01f; 164 m_bankingMix = Math.Max(pValue, 0.01f);
160 // m_bankingMix = pValue;
161 break; 165 break;
162 case Vehicle.BANKING_TIMESCALE: 166 case Vehicle.BANKING_TIMESCALE:
163 if (pValue < 0.01f) pValue = 0.01f; 167 m_bankingTimescale = Math.Max(pValue, 0.01f);
164 // m_bankingTimescale = pValue;
165 break; 168 break;
166 case Vehicle.BUOYANCY: 169 case Vehicle.BUOYANCY:
167 if (pValue < -1f) pValue = -1f; 170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f));
168 if (pValue > 1f) pValue = 1f; 171 break;
169 m_VehicleBuoyancy = pValue; 172 case Vehicle.HOVER_EFFICIENCY:
170 break; 173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f));
171// case Vehicle.HOVER_EFFICIENCY: 174 break;
172// if (pValue < 0f) pValue = 0f;
173// if (pValue > 1f) pValue = 1f;
174// m_VhoverEfficiency = pValue;
175// break;
176 case Vehicle.HOVER_HEIGHT: 175 case Vehicle.HOVER_HEIGHT:
177 m_VhoverHeight = pValue; 176 m_VhoverHeight = pValue;
178 break; 177 break;
179 case Vehicle.HOVER_TIMESCALE: 178 case Vehicle.HOVER_TIMESCALE:
180 if (pValue < 0.01f) pValue = 0.01f; 179 m_VhoverTimescale = Math.Max(pValue, 0.01f);
181 m_VhoverTimescale = pValue;
182 break; 180 break;
183 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY: 181 case Vehicle.LINEAR_DEFLECTION_EFFICIENCY:
184 if (pValue < 0.01f) pValue = 0.01f; 182 m_linearDeflectionEfficiency = Math.Max(pValue, 0.01f);
185 // m_linearDeflectionEfficiency = pValue;
186 break; 183 break;
187 case Vehicle.LINEAR_DEFLECTION_TIMESCALE: 184 case Vehicle.LINEAR_DEFLECTION_TIMESCALE:
188 if (pValue < 0.01f) pValue = 0.01f; 185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
189 // m_linearDeflectionTimescale = pValue;
190 break; 186 break;
191 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
192 if (pValue < 0.01f) pValue = 0.01f; 188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
193 m_linearMotorDecayTimescale = pValue;
194 break; 189 break;
195 case Vehicle.LINEAR_MOTOR_TIMESCALE: 190 case Vehicle.LINEAR_MOTOR_TIMESCALE:
196 if (pValue < 0.01f) pValue = 0.01f; 191 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
197 m_linearMotorTimescale = pValue;
198 break; 192 break;
199 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
200 if (pValue < 0.1f) pValue = 0.1f; // Less goes unstable 194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
201 if (pValue > 1.0f) pValue = 1.0f;
202 m_verticalAttractionEfficiency = pValue;
203 break; 195 break;
204 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
205 if (pValue < 0.01f) pValue = 0.01f; 197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
206 m_verticalAttractionTimescale = pValue;
207 break; 198 break;
208 199
209 // These are vector properties but the engine lets you use a single float value to 200 // These are vector properties but the engine lets you use a single float value to
@@ -213,7 +204,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
213 break; 204 break;
214 case Vehicle.ANGULAR_MOTOR_DIRECTION: 205 case Vehicle.ANGULAR_MOTOR_DIRECTION:
215 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
216 m_angularMotorApply = 10; 207 // m_angularMotorApply = 100;
217 break; 208 break;
218 case Vehicle.LINEAR_FRICTION_TIMESCALE: 209 case Vehicle.LINEAR_FRICTION_TIMESCALE:
219 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
@@ -223,30 +214,27 @@ namespace OpenSim.Region.Physics.BulletSPlugin
223 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
224 break; 215 break;
225 case Vehicle.LINEAR_MOTOR_OFFSET: 216 case Vehicle.LINEAR_MOTOR_OFFSET:
226 // m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
227 break; 218 break;
228 219
229 } 220 }
230 }//end ProcessFloatVehicleParam 221 }//end ProcessFloatVehicleParam
231 222
232 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep) 223 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
233 { 224 {
234 DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 225 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
235 switch (pParam) 226 switch (pParam)
236 { 227 {
237 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 228 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
238 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
239 break; 230 break;
240 case Vehicle.ANGULAR_MOTOR_DIRECTION: 231 case Vehicle.ANGULAR_MOTOR_DIRECTION:
241 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
242 // Limit requested angular speed to 2 rps= 4 pi rads/sec 232 // Limit requested angular speed to 2 rps= 4 pi rads/sec
243 if (m_angularMotorDirection.X > 12.56f) m_angularMotorDirection.X = 12.56f; 233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f));
244 if (m_angularMotorDirection.X < - 12.56f) m_angularMotorDirection.X = - 12.56f; 234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
245 if (m_angularMotorDirection.Y > 12.56f) m_angularMotorDirection.Y = 12.56f; 235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
246 if (m_angularMotorDirection.Y < - 12.56f) m_angularMotorDirection.Y = - 12.56f; 236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
247 if (m_angularMotorDirection.Z > 12.56f) m_angularMotorDirection.Z = 12.56f; 237 // m_angularMotorApply = 100;
248 if (m_angularMotorDirection.Z < - 12.56f) m_angularMotorDirection.Z = - 12.56f;
249 m_angularMotorApply = 10;
250 break; 238 break;
251 case Vehicle.LINEAR_FRICTION_TIMESCALE: 239 case Vehicle.LINEAR_FRICTION_TIMESCALE:
252 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -256,7 +244,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
256 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
257 break; 245 break;
258 case Vehicle.LINEAR_MOTOR_OFFSET: 246 case Vehicle.LINEAR_MOTOR_OFFSET:
259 // m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
260 break; 248 break;
261 case Vehicle.BLOCK_EXIT: 249 case Vehicle.BLOCK_EXIT:
262 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z); 250 m_BlockingEndPoint = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -266,11 +254,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
266 254
267 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 255 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
268 { 256 {
269 DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); 257 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
270 switch (pParam) 258 switch (pParam)
271 { 259 {
272 case Vehicle.REFERENCE_FRAME: 260 case Vehicle.REFERENCE_FRAME:
273 // m_referenceFrame = pValue; 261 m_referenceFrame = pValue;
274 break; 262 break;
275 case Vehicle.ROLL_FRAME: 263 case Vehicle.ROLL_FRAME:
276 m_RollreferenceFrame = pValue; 264 m_RollreferenceFrame = pValue;
@@ -280,575 +268,545 @@ namespace OpenSim.Region.Physics.BulletSPlugin
280 268
281 internal void ProcessVehicleFlags(int pParam, bool remove) 269 internal void ProcessVehicleFlags(int pParam, bool remove)
282 { 270 {
283 DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); 271 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
284 if (remove) 272 VehicleFlag parm = (VehicleFlag)pParam;
285 { 273 if (pParam == -1)
286 if (pParam == -1) 274 m_flags = (VehicleFlag)0;
287 {
288 m_flags = (VehicleFlag)0;
289 m_Hoverflags = (VehicleFlag)0;
290 return;
291 }
292 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT)
293 {
294 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != (VehicleFlag)0)
295 m_Hoverflags &= ~(VehicleFlag.HOVER_GLOBAL_HEIGHT);
296 }
297 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
298 {
299 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != (VehicleFlag)0)
300 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY);
301 }
302 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
303 {
304 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != (VehicleFlag)0)
305 m_Hoverflags &= ~(VehicleFlag.HOVER_UP_ONLY);
306 }
307 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
308 {
309 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != (VehicleFlag)0)
310 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY);
311 }
312 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
313 {
314 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != (VehicleFlag)0)
315 m_flags &= ~(VehicleFlag.LIMIT_MOTOR_UP);
316 }
317 if ((pParam & (int)VehicleFlag.LIMIT_ROLL_ONLY) == (int)VehicleFlag.LIMIT_ROLL_ONLY)
318 {
319 if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) != (VehicleFlag)0)
320 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY);
321 }
322 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
323 {
324 if ((m_flags & VehicleFlag.MOUSELOOK_BANK) != (VehicleFlag)0)
325 m_flags &= ~(VehicleFlag.MOUSELOOK_BANK);
326 }
327 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
328 {
329 if ((m_flags & VehicleFlag.MOUSELOOK_STEER) != (VehicleFlag)0)
330 m_flags &= ~(VehicleFlag.MOUSELOOK_STEER);
331 }
332 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
333 {
334 if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) != (VehicleFlag)0)
335 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP);
336 }
337 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
338 {
339 if ((m_flags & VehicleFlag.CAMERA_DECOUPLED) != (VehicleFlag)0)
340 m_flags &= ~(VehicleFlag.CAMERA_DECOUPLED);
341 }
342 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
343 {
344 if ((m_flags & VehicleFlag.NO_X) != (VehicleFlag)0)
345 m_flags &= ~(VehicleFlag.NO_X);
346 }
347 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
348 {
349 if ((m_flags & VehicleFlag.NO_Y) != (VehicleFlag)0)
350 m_flags &= ~(VehicleFlag.NO_Y);
351 }
352 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
353 {
354 if ((m_flags & VehicleFlag.NO_Z) != (VehicleFlag)0)
355 m_flags &= ~(VehicleFlag.NO_Z);
356 }
357 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
358 {
359 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != (VehicleFlag)0)
360 m_Hoverflags &= ~(VehicleFlag.LOCK_HOVER_HEIGHT);
361 }
362 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
363 {
364 if ((m_flags & VehicleFlag.NO_DEFLECTION) != (VehicleFlag)0)
365 m_flags &= ~(VehicleFlag.NO_DEFLECTION);
366 }
367 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
368 {
369 if ((m_flags & VehicleFlag.LOCK_ROTATION) != (VehicleFlag)0)
370 m_flags &= ~(VehicleFlag.LOCK_ROTATION);
371 }
372 }
373 else 275 else
374 { 276 {
375 if ((pParam & (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) == (int)VehicleFlag.HOVER_GLOBAL_HEIGHT) 277 if (remove)
376 { 278 m_flags &= ~parm;
377 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT | m_flags); 279 else
378 } 280 m_flags |= parm;
379 if ((pParam & (int)VehicleFlag.HOVER_TERRAIN_ONLY) == (int)VehicleFlag.HOVER_TERRAIN_ONLY)
380 {
381 m_Hoverflags |= (VehicleFlag.HOVER_TERRAIN_ONLY | m_flags);
382 }
383 if ((pParam & (int)VehicleFlag.HOVER_UP_ONLY) == (int)VehicleFlag.HOVER_UP_ONLY)
384 {
385 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY | m_flags);
386 }
387 if ((pParam & (int)VehicleFlag.HOVER_WATER_ONLY) == (int)VehicleFlag.HOVER_WATER_ONLY)
388 {
389 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY | m_flags);
390 }
391 if ((pParam & (int)VehicleFlag.LIMIT_MOTOR_UP) == (int)VehicleFlag.LIMIT_MOTOR_UP)
392 {
393 m_flags |= (VehicleFlag.LIMIT_MOTOR_UP | m_flags);
394 }
395 if ((pParam & (int)VehicleFlag.MOUSELOOK_BANK) == (int)VehicleFlag.MOUSELOOK_BANK)
396 {
397 m_flags |= (VehicleFlag.MOUSELOOK_BANK | m_flags);
398 }
399 if ((pParam & (int)VehicleFlag.MOUSELOOK_STEER) == (int)VehicleFlag.MOUSELOOK_STEER)
400 {
401 m_flags |= (VehicleFlag.MOUSELOOK_STEER | m_flags);
402 }
403 if ((pParam & (int)VehicleFlag.NO_DEFLECTION_UP) == (int)VehicleFlag.NO_DEFLECTION_UP)
404 {
405 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | m_flags);
406 }
407 if ((pParam & (int)VehicleFlag.CAMERA_DECOUPLED) == (int)VehicleFlag.CAMERA_DECOUPLED)
408 {
409 m_flags |= (VehicleFlag.CAMERA_DECOUPLED | m_flags);
410 }
411 if ((pParam & (int)VehicleFlag.NO_X) == (int)VehicleFlag.NO_X)
412 {
413 m_flags |= (VehicleFlag.NO_X);
414 }
415 if ((pParam & (int)VehicleFlag.NO_Y) == (int)VehicleFlag.NO_Y)
416 {
417 m_flags |= (VehicleFlag.NO_Y);
418 }
419 if ((pParam & (int)VehicleFlag.NO_Z) == (int)VehicleFlag.NO_Z)
420 {
421 m_flags |= (VehicleFlag.NO_Z);
422 }
423 if ((pParam & (int)VehicleFlag.LOCK_HOVER_HEIGHT) == (int)VehicleFlag.LOCK_HOVER_HEIGHT)
424 {
425 m_Hoverflags |= (VehicleFlag.LOCK_HOVER_HEIGHT);
426 }
427 if ((pParam & (int)VehicleFlag.NO_DEFLECTION) == (int)VehicleFlag.NO_DEFLECTION)
428 {
429 m_flags |= (VehicleFlag.NO_DEFLECTION);
430 }
431 if ((pParam & (int)VehicleFlag.LOCK_ROTATION) == (int)VehicleFlag.LOCK_ROTATION)
432 {
433 m_flags |= (VehicleFlag.LOCK_ROTATION);
434 }
435 } 281 }
436 }//end ProcessVehicleFlags 282 }
437 283
438 internal void ProcessTypeChange(Vehicle pType) 284 internal void ProcessTypeChange(Vehicle pType)
439 { 285 {
440 DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); 286 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
441 // Set Defaults For Type 287 // Set Defaults For Type
442 m_type = pType; 288 Type = pType;
443 switch (pType) 289 switch (pType)
444 { 290 {
445 case Vehicle.TYPE_NONE: 291 case Vehicle.TYPE_NONE:
446 m_linearFrictionTimescale = new Vector3(0, 0, 0);
447 m_angularFrictionTimescale = new Vector3(0, 0, 0);
448 m_linearMotorDirection = Vector3.Zero; 292 m_linearMotorDirection = Vector3.Zero;
449 m_linearMotorTimescale = 0; 293 m_linearMotorTimescale = 0;
450 m_linearMotorDecayTimescale = 0; 294 m_linearMotorDecayTimescale = 0;
295 m_linearFrictionTimescale = new Vector3(0, 0, 0);
296
451 m_angularMotorDirection = Vector3.Zero; 297 m_angularMotorDirection = Vector3.Zero;
452 m_angularMotorTimescale = 0;
453 m_angularMotorDecayTimescale = 0; 298 m_angularMotorDecayTimescale = 0;
299 m_angularMotorTimescale = 0;
300 m_angularFrictionTimescale = new Vector3(0, 0, 0);
301
454 m_VhoverHeight = 0; 302 m_VhoverHeight = 0;
303 m_VhoverEfficiency = 0;
455 m_VhoverTimescale = 0; 304 m_VhoverTimescale = 0;
456 m_VehicleBuoyancy = 0; 305 m_VehicleBuoyancy = 0;
306
307 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1;
309
310 m_angularDeflectionEfficiency = 0;
311 m_angularDeflectionTimescale = 1000;
312
313 m_verticalAttractionEfficiency = 0;
314 m_verticalAttractionTimescale = 0;
315
316 m_bankingEfficiency = 0;
317 m_bankingTimescale = 1000;
318 m_bankingMix = 1;
319
320 m_referenceFrame = Quaternion.Identity;
457 m_flags = (VehicleFlag)0; 321 m_flags = (VehicleFlag)0;
458 break; 322 break;
459 323
460 case Vehicle.TYPE_SLED: 324 case Vehicle.TYPE_SLED:
461 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
462 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
463 m_linearMotorDirection = Vector3.Zero; 325 m_linearMotorDirection = Vector3.Zero;
464 m_linearMotorTimescale = 1000; 326 m_linearMotorTimescale = 1000;
465 m_linearMotorDecayTimescale = 120; 327 m_linearMotorDecayTimescale = 120;
328 m_linearFrictionTimescale = new Vector3(30, 1, 1000);
329
466 m_angularMotorDirection = Vector3.Zero; 330 m_angularMotorDirection = Vector3.Zero;
467 m_angularMotorTimescale = 1000; 331 m_angularMotorTimescale = 1000;
468 m_angularMotorDecayTimescale = 120; 332 m_angularMotorDecayTimescale = 120;
333 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
334
469 m_VhoverHeight = 0; 335 m_VhoverHeight = 0;
470// m_VhoverEfficiency = 1; 336 m_VhoverEfficiency = 10; // TODO: this looks wrong!!
471 m_VhoverTimescale = 10; 337 m_VhoverTimescale = 10;
472 m_VehicleBuoyancy = 0; 338 m_VehicleBuoyancy = 0;
473 // m_linearDeflectionEfficiency = 1; 339
474 // m_linearDeflectionTimescale = 1; 340 m_linearDeflectionEfficiency = 1;
475 // m_angularDeflectionEfficiency = 1; 341 m_linearDeflectionTimescale = 1;
476 // m_angularDeflectionTimescale = 1000; 342
477 // m_bankingEfficiency = 0; 343 m_angularDeflectionEfficiency = 1;
478 // m_bankingMix = 1; 344 m_angularDeflectionTimescale = 1000;
479 // m_bankingTimescale = 10; 345
480 // m_referenceFrame = Quaternion.Identity; 346 m_verticalAttractionEfficiency = 0;
481 m_Hoverflags &= 347 m_verticalAttractionTimescale = 0;
348
349 m_bankingEfficiency = 0;
350 m_bankingTimescale = 10;
351 m_bankingMix = 1;
352
353 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
355 m_flags &=
482 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
483 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
484 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
485 break; 358 break;
486 case Vehicle.TYPE_CAR: 359 case Vehicle.TYPE_CAR:
487 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
488 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
489 m_linearMotorDirection = Vector3.Zero; 360 m_linearMotorDirection = Vector3.Zero;
490 m_linearMotorTimescale = 1; 361 m_linearMotorTimescale = 1;
491 m_linearMotorDecayTimescale = 60; 362 m_linearMotorDecayTimescale = 60;
363 m_linearFrictionTimescale = new Vector3(100, 2, 1000);
364
492 m_angularMotorDirection = Vector3.Zero; 365 m_angularMotorDirection = Vector3.Zero;
493 m_angularMotorTimescale = 1; 366 m_angularMotorTimescale = 1;
494 m_angularMotorDecayTimescale = 0.8f; 367 m_angularMotorDecayTimescale = 0.8f;
368 m_angularFrictionTimescale = new Vector3(1000, 1000, 1000);
369
495 m_VhoverHeight = 0; 370 m_VhoverHeight = 0;
496// m_VhoverEfficiency = 0; 371 m_VhoverEfficiency = 0;
497 m_VhoverTimescale = 1000; 372 m_VhoverTimescale = 1000;
498 m_VehicleBuoyancy = 0; 373 m_VehicleBuoyancy = 0;
499 // // m_linearDeflectionEfficiency = 1; 374
500 // // m_linearDeflectionTimescale = 2; 375 m_linearDeflectionEfficiency = 1;
501 // // m_angularDeflectionEfficiency = 0; 376 m_linearDeflectionTimescale = 2;
502 // m_angularDeflectionTimescale = 10; 377
378 m_angularDeflectionEfficiency = 0;
379 m_angularDeflectionTimescale = 10;
380
503 m_verticalAttractionEfficiency = 1f; 381 m_verticalAttractionEfficiency = 1f;
504 m_verticalAttractionTimescale = 10f; 382 m_verticalAttractionTimescale = 10f;
505 // m_bankingEfficiency = -0.2f; 383
506 // m_bankingMix = 1; 384 m_bankingEfficiency = -0.2f;
507 // m_bankingTimescale = 1; 385 m_bankingMix = 1;
508 // m_referenceFrame = Quaternion.Identity; 386 m_bankingTimescale = 1;
509 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT); 387
510 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | 388 m_referenceFrame = Quaternion.Identity;
511 VehicleFlag.LIMIT_MOTOR_UP); 389 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
512 m_Hoverflags |= (VehicleFlag.HOVER_UP_ONLY); 390 | VehicleFlag.HOVER_TERRAIN_ONLY
391 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
392 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
393 | VehicleFlag.LIMIT_ROLL_ONLY
394 | VehicleFlag.LIMIT_MOTOR_UP
395 | VehicleFlag.HOVER_UP_ONLY);
513 break; 396 break;
514 case Vehicle.TYPE_BOAT: 397 case Vehicle.TYPE_BOAT:
515 m_linearFrictionTimescale = new Vector3(10, 3, 2);
516 m_angularFrictionTimescale = new Vector3(10,10,10);
517 m_linearMotorDirection = Vector3.Zero; 398 m_linearMotorDirection = Vector3.Zero;
518 m_linearMotorTimescale = 5; 399 m_linearMotorTimescale = 5;
519 m_linearMotorDecayTimescale = 60; 400 m_linearMotorDecayTimescale = 60;
401 m_linearFrictionTimescale = new Vector3(10, 3, 2);
402
520 m_angularMotorDirection = Vector3.Zero; 403 m_angularMotorDirection = Vector3.Zero;
521 m_angularMotorTimescale = 4; 404 m_angularMotorTimescale = 4;
522 m_angularMotorDecayTimescale = 4; 405 m_angularMotorDecayTimescale = 4;
406 m_angularFrictionTimescale = new Vector3(10,10,10);
407
523 m_VhoverHeight = 0; 408 m_VhoverHeight = 0;
524// m_VhoverEfficiency = 0.5f; 409 m_VhoverEfficiency = 0.5f;
525 m_VhoverTimescale = 2; 410 m_VhoverTimescale = 2;
526 m_VehicleBuoyancy = 1; 411 m_VehicleBuoyancy = 1;
527 // m_linearDeflectionEfficiency = 0.5f; 412
528 // m_linearDeflectionTimescale = 3; 413 m_linearDeflectionEfficiency = 0.5f;
529 // m_angularDeflectionEfficiency = 0.5f; 414 m_linearDeflectionTimescale = 3;
530 // m_angularDeflectionTimescale = 5; 415
416 m_angularDeflectionEfficiency = 0.5f;
417 m_angularDeflectionTimescale = 5;
418
531 m_verticalAttractionEfficiency = 0.5f; 419 m_verticalAttractionEfficiency = 0.5f;
532 m_verticalAttractionTimescale = 5f; 420 m_verticalAttractionTimescale = 5f;
533 // m_bankingEfficiency = -0.3f; 421
534 // m_bankingMix = 0.8f; 422 m_bankingEfficiency = -0.3f;
535 // m_bankingTimescale = 1; 423 m_bankingMix = 0.8f;
536 // m_referenceFrame = Quaternion.Identity; 424 m_bankingTimescale = 1;
537 m_Hoverflags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY | 425
538 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 426 m_referenceFrame = Quaternion.Identity;
539 m_flags &= ~(VehicleFlag.LIMIT_ROLL_ONLY); 427 m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
540 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 428 | VehicleFlag.HOVER_GLOBAL_HEIGHT
541 VehicleFlag.LIMIT_MOTOR_UP); 429 | VehicleFlag.LIMIT_ROLL_ONLY
542 m_Hoverflags |= (VehicleFlag.HOVER_WATER_ONLY); 430 | VehicleFlag.HOVER_UP_ONLY);
431 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
432 | VehicleFlag.LIMIT_MOTOR_UP
433 | VehicleFlag.HOVER_WATER_ONLY);
543 break; 434 break;
544 case Vehicle.TYPE_AIRPLANE: 435 case Vehicle.TYPE_AIRPLANE:
545 m_linearFrictionTimescale = new Vector3(200, 10, 5);
546 m_angularFrictionTimescale = new Vector3(20, 20, 20);
547 m_linearMotorDirection = Vector3.Zero; 436 m_linearMotorDirection = Vector3.Zero;
548 m_linearMotorTimescale = 2; 437 m_linearMotorTimescale = 2;
549 m_linearMotorDecayTimescale = 60; 438 m_linearMotorDecayTimescale = 60;
439 m_linearFrictionTimescale = new Vector3(200, 10, 5);
440
550 m_angularMotorDirection = Vector3.Zero; 441 m_angularMotorDirection = Vector3.Zero;
551 m_angularMotorTimescale = 4; 442 m_angularMotorTimescale = 4;
552 m_angularMotorDecayTimescale = 4; 443 m_angularMotorDecayTimescale = 4;
444 m_angularFrictionTimescale = new Vector3(20, 20, 20);
445
553 m_VhoverHeight = 0; 446 m_VhoverHeight = 0;
554// m_VhoverEfficiency = 0.5f; 447 m_VhoverEfficiency = 0.5f;
555 m_VhoverTimescale = 1000; 448 m_VhoverTimescale = 1000;
556 m_VehicleBuoyancy = 0; 449 m_VehicleBuoyancy = 0;
557 // m_linearDeflectionEfficiency = 0.5f; 450
558 // m_linearDeflectionTimescale = 3; 451 m_linearDeflectionEfficiency = 0.5f;
559 // m_angularDeflectionEfficiency = 1; 452 m_linearDeflectionTimescale = 3;
560 // m_angularDeflectionTimescale = 2; 453
454 m_angularDeflectionEfficiency = 1;
455 m_angularDeflectionTimescale = 2;
456
561 m_verticalAttractionEfficiency = 0.9f; 457 m_verticalAttractionEfficiency = 0.9f;
562 m_verticalAttractionTimescale = 2f; 458 m_verticalAttractionTimescale = 2f;
563 // m_bankingEfficiency = 1; 459
564 // m_bankingMix = 0.7f; 460 m_bankingEfficiency = 1;
565 // m_bankingTimescale = 2; 461 m_bankingMix = 0.7f;
566 // m_referenceFrame = Quaternion.Identity; 462 m_bankingTimescale = 2;
567 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 463
568 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 464 m_referenceFrame = Quaternion.Identity;
569 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 465 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
466 | VehicleFlag.HOVER_TERRAIN_ONLY
467 | VehicleFlag.HOVER_GLOBAL_HEIGHT
468 | VehicleFlag.HOVER_UP_ONLY
469 | VehicleFlag.NO_DEFLECTION_UP
470 | VehicleFlag.LIMIT_MOTOR_UP);
570 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 471 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY);
571 break; 472 break;
572 case Vehicle.TYPE_BALLOON: 473 case Vehicle.TYPE_BALLOON:
573 m_linearFrictionTimescale = new Vector3(5, 5, 5);
574 m_angularFrictionTimescale = new Vector3(10, 10, 10);
575 m_linearMotorDirection = Vector3.Zero; 474 m_linearMotorDirection = Vector3.Zero;
576 m_linearMotorTimescale = 5; 475 m_linearMotorTimescale = 5;
476 m_linearFrictionTimescale = new Vector3(5, 5, 5);
577 m_linearMotorDecayTimescale = 60; 477 m_linearMotorDecayTimescale = 60;
478
578 m_angularMotorDirection = Vector3.Zero; 479 m_angularMotorDirection = Vector3.Zero;
579 m_angularMotorTimescale = 6; 480 m_angularMotorTimescale = 6;
481 m_angularFrictionTimescale = new Vector3(10, 10, 10);
580 m_angularMotorDecayTimescale = 10; 482 m_angularMotorDecayTimescale = 10;
483
581 m_VhoverHeight = 5; 484 m_VhoverHeight = 5;
582// m_VhoverEfficiency = 0.8f; 485 m_VhoverEfficiency = 0.8f;
583 m_VhoverTimescale = 10; 486 m_VhoverTimescale = 10;
584 m_VehicleBuoyancy = 1; 487 m_VehicleBuoyancy = 1;
585 // m_linearDeflectionEfficiency = 0; 488
586 // m_linearDeflectionTimescale = 5; 489 m_linearDeflectionEfficiency = 0;
587 // m_angularDeflectionEfficiency = 0; 490 m_linearDeflectionTimescale = 5;
588 // m_angularDeflectionTimescale = 5; 491
492 m_angularDeflectionEfficiency = 0;
493 m_angularDeflectionTimescale = 5;
494
589 m_verticalAttractionEfficiency = 1f; 495 m_verticalAttractionEfficiency = 1f;
590 m_verticalAttractionTimescale = 100f; 496 m_verticalAttractionTimescale = 100f;
591 // m_bankingEfficiency = 0; 497
592 // m_bankingMix = 0.7f; 498 m_bankingEfficiency = 0;
593 // m_bankingTimescale = 5; 499 m_bankingMix = 0.7f;
594 // m_referenceFrame = Quaternion.Identity; 500 m_bankingTimescale = 5;
595 m_Hoverflags &= ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 501 m_referenceFrame = Quaternion.Identity;
596 VehicleFlag.HOVER_UP_ONLY); 502
597 m_flags &= ~(VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_MOTOR_UP); 503 m_referenceFrame = Quaternion.Identity;
598 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); 504 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
599 m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); 505 | VehicleFlag.HOVER_TERRAIN_ONLY
506 | VehicleFlag.HOVER_UP_ONLY
507 | VehicleFlag.NO_DEFLECTION_UP
508 | VehicleFlag.LIMIT_MOTOR_UP);
509 m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
600 break; 511 break;
601 } 512 }
602 }//end SetDefaultsForType 513 }
514
515 // Some of the properties of this prim may have changed.
516 // Do any updating needed for a vehicle
517 public void Refresh()
518 {
519 if (IsActive)
520 {
521 // Friction effects are handled by this vehicle code
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
526
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
528 }
529 }
530
531 public bool RemoveBodyDependencies(BSPhysObject prim)
532 {
533 // If active, we need to add our properties back when the body is rebuilt.
534 return IsActive;
535 }
536
537 public void RestoreBodyDependencies(BSPhysObject prim)
538 {
539 if (Prim.LocalID != prim.LocalID)
540 {
541 // The call should be on us by our prim. Error if not.
542 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
543 LogHeader, prim.LocalID, Prim.LocalID);
544 return;
545 }
546 Refresh();
547 }
603 548
549 // One step of the vehicle properties for the next 'pTimestep' seconds.
604 internal void Step(float pTimestep) 550 internal void Step(float pTimestep)
605 { 551 {
606 if (m_type == Vehicle.TYPE_NONE) return; 552 if (!IsActive) return;
607 553
608 frcount++; // used to limit debug comment output 554 // DEBUG
609 if (frcount > 100) 555 // Because Bullet does apply forces to the vehicle, our last computed
610 frcount = 0; 556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562
563 m_vehicleMass = Prim.Linkset.LinksetMass;
611 564
612 MoveLinear(pTimestep); 565 MoveLinear(pTimestep);
566 // Commented out for debug
613 MoveAngular(pTimestep); 567 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570
614 LimitRotation(pTimestep); 571 LimitRotation(pTimestep);
615 572
616 DetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 573 // remember the position so next step we can limit absolute movement effects
617 m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); 574 m_lastPositionVector = Prim.ForcePosition;
575
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
577 Prim.LocalID,
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
580 Prim.Inertia,
581 m_vehicleMass
582 );
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
618 }// end Step 585 }// end Step
619 586
587 // Apply the effect of the linear motor.
588 // Also does hover and float.
620 private void MoveLinear(float pTimestep) 589 private void MoveLinear(float pTimestep)
621 { 590 {
622 // requested m_linearMotorDirection is significant 591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
623 // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) 592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
624 if (m_linearMotorDirection.LengthSquared() > 0.0001f) 593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
625 { 594 {
626 Vector3 origDir = m_linearMotorDirection; 595 Vector3 origDir = m_linearMotorDirection; // DEBUG
627 Vector3 origVel = m_lastLinearVelocityVector; 596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
628 597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
629 // add drive to body 598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
630 // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); 599
631 Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); 600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
632 // lastLinearVelocityVector is the current body velocity vector? 601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
633 // RA: Not sure what the *10 is for. A correction for pTimestep?
634 // m_lastLinearVelocityVector += (addAmount*10);
635 m_lastLinearVelocityVector += addAmount;
636
637 // This will work temporarily, but we really need to compare speed on an axis
638 // KF: Limit body velocity to applied velocity?
639 // Limit the velocity vector to less than the last set linear motor direction
640 if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X))
641 m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X;
642 if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y))
643 m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y;
644 if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z))
645 m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z;
646
647 // decay applied velocity
648 Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep)));
649 m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f;
650
651 /*
652 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale;
653 m_lastLinearVelocityVector += addAmount; 602 m_lastLinearVelocityVector += addAmount;
654 603
655 float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale); 604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
656 m_linearMotorDirection *= decayfraction; 605 m_linearMotorDirection *= (1f - decayFactor);
606
607 // Rotate new object velocity from vehicle relative to world coordinates
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
657 609
658 */ 610 // Apply friction for next time
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
659 613
660 DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", 614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
661 m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector); 615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
662 } 617 }
663 else 618 else
664 { 619 {
665 // if what remains of applied is small, zero it. 620 // if what remains of direction is very small, zero it.
666 // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f))
667 // m_lastLinearVelocityVector = Vector3.Zero;
668 m_linearMotorDirection = Vector3.Zero; 621 m_linearMotorDirection = Vector3.Zero;
669 m_lastLinearVelocityVector = Vector3.Zero; 622 m_lastLinearVelocityVector = Vector3.Zero;
670 } 623 m_newVelocity = Vector3.Zero;
671 624
672 // convert requested object velocity to world-referenced vector 625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
673 Quaternion rotq = m_prim.Orientation; 626 }
674 m_dir = m_lastLinearVelocityVector * rotq;
675 627
676 // Add the various forces into m_dir which will be our new direction vector (velocity) 628 // m_newVelocity is velocity computed from linear motor in world coordinates
677 629
678 // add Gravity and Buoyancy 630 // Gravity and Buoyancy
679 // KF: So far I have found no good method to combine a script-requested
680 // .Z velocity and gravity. Therefore only 0g will used script-requested
681 // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only.
682 Vector3 grav = Vector3.Zero;
683 // There is some gravity, make a gravity force vector that is applied after object velocity. 631 // There is some gravity, make a gravity force vector that is applied after object velocity.
684 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
685 grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); 633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
634
635 /*
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
686 // Preserve the current Z velocity 637 // Preserve the current Z velocity
687 Vector3 vel_now = m_prim.Velocity; 638 Vector3 vel_now = m_prim.Velocity;
688 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
640 */
689 641
690 Vector3 pos = m_prim.Position; 642 Vector3 pos = Prim.ForcePosition;
691 Vector3 posChange = pos;
692// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); 643// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
693 double Zchange = Math.Abs(posChange.Z);
694 if (m_BlockingEndPoint != Vector3.Zero)
695 {
696 bool changed = false;
697 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
698 {
699 pos.X -= posChange.X + 1;
700 changed = true;
701 }
702 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
703 {
704 pos.Y -= posChange.Y + 1;
705 changed = true;
706 }
707 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
708 {
709 pos.Z -= posChange.Z + 1;
710 changed = true;
711 }
712 if (pos.X <= 0)
713 {
714 pos.X += posChange.X + 1;
715 changed = true;
716 }
717 if (pos.Y <= 0)
718 {
719 pos.Y += posChange.Y + 1;
720 changed = true;
721 }
722 if (changed)
723 {
724 m_prim.Position = pos;
725 DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
726 m_prim.LocalID, m_BlockingEndPoint, posChange, pos);
727 }
728 }
729 644
730 // If below the terrain, move us above the ground a little. 645 // If below the terrain, move us above the ground a little.
731 if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) 646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
650 // if (rotatedSize.Z < terrainHeight)
651 if (pos.Z < terrainHeight)
732 { 652 {
733 pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; 653 pos.Z = terrainHeight + 2;
734 m_prim.Position = pos; 654 Prim.ForcePosition = pos;
735 DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); 655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
736 } 656 }
737 657
738 // Check if hovering 658 // Check if hovering
739 if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
740 { 662 {
741 // We should hover, get the target height 663 // We should hover, get the target height
742 if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) 664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
743 { 665 {
744 m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; 666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
745 } 667 }
746 if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
747 { 669 {
748 m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; 670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight;
749 } 671 }
750 if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
751 { 673 {
752 m_VhoverTargetHeight = m_VhoverHeight; 674 m_VhoverTargetHeight = m_VhoverHeight;
753 } 675 }
754 676
755 if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) 677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
756 { 678 {
757 // If body is aready heigher, use its height as target height 679 // If body is already heigher, use its height as target height
758 if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; 680 if (pos.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z;
759 } 682 }
760 if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
761 { 684 {
762 if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) 685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
763 { 686 {
764 m_prim.Position = pos; 687 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos;
765 } 689 }
766 } 690 }
767 else 691 else
768 { 692 {
769 float herr0 = pos.Z - m_VhoverTargetHeight; 693 float verticalError = pos.Z - m_VhoverTargetHeight;
694 // RA: where does the 50 come from?
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
770 // Replace Vertical speed with correction figure if significant 696 // Replace Vertical speed with correction figure if significant
771 if (Math.Abs(herr0) > 0.01f) 697 if (Math.Abs(verticalError) > 0.01f)
772 { 698 {
773 m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); 699 m_newVelocity.Z += verticalCorrectionVelocity;
774 //KF: m_VhoverEfficiency is not yet implemented 700 //KF: m_VhoverEfficiency is not yet implemented
775 } 701 }
702 else if (verticalError < -0.01)
703 {
704 m_newVelocity.Z -= verticalCorrectionVelocity;
705 }
776 else 706 else
777 { 707 {
778 m_dir.Z = 0f; 708 m_newVelocity.Z = 0f;
779 } 709 }
780 } 710 }
781 711
782 DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); 712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
783
784// m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped
785// m_VhoverTimescale = 0f; // time to acheive height
786// pTimestep is time since last frame,in secs
787 } 713 }
788 714
789 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 715 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero)
790 { 717 {
791 //Start Experimental Values 718 bool changed = false;
792 if (Zchange > .3) 719 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
793 { 720 {
794 grav.Z = (float)(grav.Z * 3); 721 pos.X -= posChange.X + 1;
722 changed = true;
795 } 723 }
796 if (Zchange > .15) 724 if (pos.Y >= (m_BlockingEndPoint.Y - (float)1))
797 { 725 {
798 grav.Z = (float)(grav.Z * 2); 726 pos.Y -= posChange.Y + 1;
727 changed = true;
799 } 728 }
800 if (Zchange > .75) 729 if (pos.Z >= (m_BlockingEndPoint.Z - (float)1))
801 { 730 {
802 grav.Z = (float)(grav.Z * 1.5); 731 pos.Z -= posChange.Z + 1;
732 changed = true;
803 } 733 }
804 if (Zchange > .05) 734 if (pos.X <= 0)
805 { 735 {
806 grav.Z = (float)(grav.Z * 1.25); 736 pos.X += posChange.X + 1;
737 changed = true;
807 } 738 }
808 if (Zchange > .025) 739 if (pos.Y <= 0)
809 { 740 {
810 grav.Z = (float)(grav.Z * 1.125); 741 pos.Y += posChange.Y + 1;
742 changed = true;
811 } 743 }
812 float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos); 744 if (changed)
813 float postemp = (pos.Z - terraintemp);
814 if (postemp > 2.5f)
815 { 745 {
816 grav.Z = (float)(grav.Z * 1.037125); 746 Prim.ForcePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
817 } 749 }
818 DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav);
819 //End Experimental Values
820 } 750 }
821 if ((m_flags & (VehicleFlag.NO_X)) != 0) 751
752 #region downForce
753 Vector3 downForce = Vector3.Zero;
754
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
822 { 756 {
823 m_dir.X = 0; 757 // If the vehicle is motoring into the sky, get it going back down.
758 // Is this an angular force or both linear and angular??
759 float distanceAboveGround = pos.Z - terrainHeight;
760 if (distanceAboveGround > 2f)
761 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround);
765 }
766 // TODO: this calculation is all wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should
769 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
771 Prim.LocalID, distanceAboveGround, downForce);
824 } 772 }
773 #endregion // downForce
774
775 // If not changing some axis, reduce out velocity
776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
777 m_newVelocity.X = 0;
825 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 778 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
826 { 779 m_newVelocity.Y = 0;
827 m_dir.Y = 0;
828 }
829 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
781 m_newVelocity.Z = 0;
782
783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
830 { 785 {
831 m_dir.Z = 0; 786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
832 } 788 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
833 791
834 m_lastPositionVector = m_prim.Position; 792 // Stuff new linear velocity into the vehicle
793 Prim.ForceVelocity = m_newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
835 795
836 // Apply velocity 796 Vector3 totalDownForce = downForce + grav;
837 m_prim.Velocity = m_dir; 797 if (totalDownForce != Vector3.Zero)
838 // apply gravity force 798 {
839 // Why is this set here? The physics engine already does gravity. 799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
840 // m_prim.AddForce(grav, false); 800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
841 // m_prim.Force = grav; 801 }
842
843 // Apply friction
844 Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep);
845 m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount;
846 802
847 DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", 803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
848 m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); 804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
849 805
850 } // end MoveLinear() 806 } // end MoveLinear()
851 807
808 // =======================================================================
809 // Apply the effect of the angular motor.
852 private void MoveAngular(float pTimestep) 810 private void MoveAngular(float pTimestep)
853 { 811 {
854 // m_angularMotorDirection // angular velocity requested by LSL motor 812 // m_angularMotorDirection // angular velocity requested by LSL motor
@@ -859,160 +817,263 @@ namespace OpenSim.Region.Physics.BulletSPlugin
859 // m_angularFrictionTimescale // body angular velocity decay rate 817 // m_angularFrictionTimescale // body angular velocity decay rate
860 // m_lastAngularVelocity // what was last applied to body 818 // m_lastAngularVelocity // what was last applied to body
861 819
862 // Get what the body is doing, this includes 'external' influences 820 if (m_angularMotorDirection.LengthSquared() > 0.0001)
863 Vector3 angularVelocity = m_prim.RotationalVelocity;
864
865 if (m_angularMotorApply > 0)
866 { 821 {
867 // Rather than snapping the angular motor velocity from the old value to 822 Vector3 origVel = m_angularMotorVelocity;
868 // a newly set velocity, this routine steps the value from the previous 823 Vector3 origDir = m_angularMotorDirection;
869 // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). 824
870 // There are m_angularMotorApply steps. 825 // new velocity += error / ( time to get there / step interval)
871 Vector3 origAngularVelocity = m_angularMotorVelocity; 826 // requested direction - current vehicle direction
872 // ramp up to new value 827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
873 // current velocity += error / (time to get there / step interval) 828 // decay requested direction
874 // requested speed - last motor speed 829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
875 m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); 830
876 m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); 831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
877 m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); 832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
878
879 DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}",
880 m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
881
882 m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected
883 // velocity may still be acheived.
884 } 833 }
885 else 834 else
886 { 835 {
887 // No motor recently applied, keep the body velocity 836 m_angularMotorVelocity = Vector3.Zero;
888 // and decay the velocity 837 }
889 m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); 838
890 } // end motor section 839 #region Vertical attactor
891 840
892 // Vertical attractor section
893 Vector3 vertattr = Vector3.Zero; 841 Vector3 vertattr = Vector3.Zero;
894 if (m_verticalAttractionTimescale < 300) 842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
895 { 847 {
896 float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); 848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
897 // get present body rotation 849 if (Prim.IsColliding)
898 Quaternion rotq = m_prim.Orientation; 850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
899 // make a vector pointing up 851
900 Vector3 verterr = Vector3.Zero; 852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
901 verterr.Z = 1.0f; 853
902 // rotate it to Body Angle 854 // Create a vector of the vehicle "up" in world coordinates
903 verterr = verterr * rotq; 855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
904 // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. 856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
905 // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go 857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
906 // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. 858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
907 if (verterr.Z < 0.0f) 859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
861
862 // Error is 0 (no error) to +/- 2 (max error)
863 if (verticalError.Z < 0.0f)
908 { 864 {
909 verterr.X = 2.0f - verterr.X; 865 verticalError.X = 2.0f - verticalError.X;
910 verterr.Y = 2.0f - verterr.Y; 866 verticalError.Y = 2.0f - verticalError.Y;
911 } 867 }
912 // Error is 0 (no error) to +/- 2 (max error) 868 // scale it by VAservo (timestep and timescale)
913 // scale it by VAservo 869 verticalError = verticalError * VAservo;
914 verterr = verterr * VAservo; 870
915 871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
916 // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so 872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
917 // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. 873 // Z is not changed.
918 vertattr.X = verterr.Y; 874 vertattr.X = verticalError.Y;
919 vertattr.Y = - verterr.X; 875 vertattr.Y = - verticalError.X;
920 vertattr.Z = 0f; 876 vertattr.Z = 0f;
921 877
922 // scaling appears better usingsquare-law 878 // scaling appears better usingsquare-law
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
923 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); 880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
924 vertattr.X += bounce * angularVelocity.X; 881 vertattr.X += bounce * angularVelocity.X;
925 vertattr.Y += bounce * angularVelocity.Y; 882 vertattr.Y += bounce * angularVelocity.Y;
926 883
927 DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", 884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
928 m_prim.LocalID, verterr, bounce, vertattr); 885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
929 886
930 } // else vertical attractor is off 887 }
888 #endregion // Vertical attactor
889
890 #region Deflection
891
892 if (m_angularDeflectionEfficiency != 0)
893 {
894 // Compute a scaled vector that points in the preferred axis (X direction)
895 Vector3 scaledDefaultDirection =
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
897 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
898 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900
901 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct.
907 deflection = Vector3.Zero;
908 }
909
910 #endregion
911
912 #region Banking
913
914 if (m_bankingEfficiency != 0)
915 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation;
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
918 //Changes which way it banks in and out of turns
931 919
932 // m_lastVertAttractor = vertattr; 920 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
922 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative!
933 924
934 // Bank section tba 925 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0)
927 {
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 {
930 Vector3 axisAngle;
931 float angle;
932 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
933 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
934 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
935 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
936 else
937 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
938 }*/
939 }
940 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 {
945 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix)
947 angVelZ = mix;
948 else if(angVelZ < -mix)
949 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
952 if (bankingRot.X > 3)
953 bankingRot.X = 3;
954 else if (bankingRot.X < -3)
955 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot;
958 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
962 }
935 963
936 // Deflection section tba 964 #endregion
965
966 m_lastVertAttractor = vertattr;
937 967
938 // Sum velocities 968 // Sum velocities
939 m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection 969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
940 970
971 #region Linear Motor Offset
972
973 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero)
975 {
976 //Offset of linear velocity doesn't change the linear velocity,
977 // but causes a torque to be applied, for example...
978 //
979 // IIIII >>> IIIII
980 // IIIII >>> IIIII
981 // IIIII >>> IIIII
982 // ^
983 // | Applying a force at the arrow will cause the object to move forward, but also rotate
984 //
985 //
986 // The torque created is the linear velocity crossed with the offset
987
988 // NOTE: this computation does should be in the linear section
989 // because there we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X))
993 torqueFromOffset.X = 0;
994 if (float.IsNaN(torqueFromOffset.Y))
995 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass;
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 }
1002
1003 #endregion
1004
941 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
942 { 1006 {
943 m_lastAngularVelocity.X = 0; 1007 m_lastAngularVelocity.X = 0;
944 m_lastAngularVelocity.Y = 0; 1008 m_lastAngularVelocity.Y = 0;
945 DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
946 } 1010 }
947 1011
948 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
949 { 1013 {
950 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
951 DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); 1015 Prim.ZeroAngularMotion(true);
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
1017 }
1018 else
1019 {
1020 // Apply to the body.
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless.
1022 // Since we are stuffing the angular velocity directly into the object, the computed
1023 // velocity needs to be scaled by the timestep.
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
1025 Prim.ForceRotationalVelocity = applyAngularForce;
1026
1027 // Decay the angular movement for next time
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
1029 m_lastAngularVelocity *= Vector3.One - decayamount;
1030
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
952 } 1033 }
953
954 // apply friction
955 Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep);
956 m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
957
958 // Apply to the body
959 m_prim.RotationalVelocity = m_lastAngularVelocity;
960
961 DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity);
962 } //end MoveAngular 1034 } //end MoveAngular
963 1035
964 internal void LimitRotation(float timestep) 1036 internal void LimitRotation(float timestep)
965 { 1037 {
966 Quaternion rotq = m_prim.Orientation; 1038 Quaternion rotq = Prim.ForceOrientation;
967 Quaternion m_rot = rotq; 1039 Quaternion m_rot = rotq;
968 bool changed = false;
969 if (m_RollreferenceFrame != Quaternion.Identity) 1040 if (m_RollreferenceFrame != Quaternion.Identity)
970 { 1041 {
971 if (rotq.X >= m_RollreferenceFrame.X) 1042 if (rotq.X >= m_RollreferenceFrame.X)
972 { 1043 {
973 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); 1044 m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2);
974 changed = true;
975 } 1045 }
976 if (rotq.Y >= m_RollreferenceFrame.Y) 1046 if (rotq.Y >= m_RollreferenceFrame.Y)
977 { 1047 {
978 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); 1048 m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2);
979 changed = true;
980 } 1049 }
981 if (rotq.X <= -m_RollreferenceFrame.X) 1050 if (rotq.X <= -m_RollreferenceFrame.X)
982 { 1051 {
983 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); 1052 m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2);
984 changed = true;
985 } 1053 }
986 if (rotq.Y <= -m_RollreferenceFrame.Y) 1054 if (rotq.Y <= -m_RollreferenceFrame.Y)
987 { 1055 {
988 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); 1056 m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2);
989 changed = true;
990 } 1057 }
991 changed = true;
992 } 1058 }
993 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 1059 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0)
994 { 1060 {
995 m_rot.X = 0; 1061 m_rot.X = 0;
996 m_rot.Y = 0; 1062 m_rot.Y = 0;
997 changed = true;
998 } 1063 }
999 if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) 1064 if (rotq != m_rot)
1000 { 1065 {
1001 m_rot.X = 0; 1066 Prim.ForceOrientation = m_rot;
1002 m_rot.Y = 0; 1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1003 changed = true;
1004 } 1068 }
1005 if (changed)
1006 m_prim.Orientation = m_rot;
1007 1069
1008 DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot);
1009 } 1070 }
1010 1071
1011 // Invoke the detailed logger and output something if it's enabled. 1072 // Invoke the detailed logger and output something if it's enabled.
1012 private void DetailLog(string msg, params Object[] args) 1073 private void VDetailLog(string msg, params Object[] args)
1013 { 1074 {
1014 if (m_prim.Scene.VehicleLoggingEnabled) 1075 if (Prim.PhysicsScene.VehicleLoggingEnabled)
1015 m_prim.Scene.PhysicsLogging.Write(msg, args); 1076 Prim.PhysicsScene.DetailLog(msg, args);
1016 } 1077 }
1017 } 1078 }
1018} 1079}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 087b9bb..0df4310 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,35 +32,80 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public abstract class BSLinkset
36{ 36{
37 private static string LogHeader = "[BULLETSIM LINKSET]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET]";
38 38
39 private BSPrim m_linksetRoot; 39 public enum LinksetImplementation
40 public BSPrim LinksetRoot { get { return m_linksetRoot; } } 40 {
41 Constraint = 0, // linkset tied together with constraints
42 Compound = 1, // linkset tied together as a compound object
43 Manual = 2 // linkset tied together manually (code moves all the pieces)
44 }
45 // Create the correct type of linkset for this child
46 public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
47 {
48 BSLinkset ret = null;
49
50 switch ((int)physScene.Params.linksetImplementation)
51 {
52 case (int)LinksetImplementation.Constraint:
53 ret = new BSLinksetConstraints(physScene, parent);
54 break;
55 case (int)LinksetImplementation.Compound:
56 ret = new BSLinksetCompound(physScene, parent);
57 break;
58 case (int)LinksetImplementation.Manual:
59 // ret = new BSLinksetManual(physScene, parent);
60 break;
61 default:
62 ret = new BSLinksetCompound(physScene, parent);
63 break;
64 }
65 return ret;
66 }
67
68 public BSPhysObject LinksetRoot { get; protected set; }
41 69
42 private BSScene m_physicsScene; 70 public BSScene PhysicsScene { get; private set; }
43 public BSScene PhysicsScene { get { return m_physicsScene; } }
44 71
45 // The children under the root in this linkset 72 static int m_nextLinksetID = 1;
46 private List<BSPrim> m_children; 73 public int LinksetID { get; private set; }
74
75 // The children under the root in this linkset.
76 protected HashSet<BSPhysObject> m_children;
47 77
48 // We lock the diddling of linkset classes to prevent any badness. 78 // We lock the diddling of linkset classes to prevent any badness.
49 // This locks the modification of the instances of this class. Changes 79 // This locks the modification of the instances of this class. Changes
50 // to the physical representation is done via the tainting mechenism. 80 // to the physical representation is done via the tainting mechenism.
51 private object m_linksetActivityLock = new Object(); 81 protected object m_linksetActivityLock = new Object();
82
83 // Some linksets have a preferred physical shape.
84 // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected.
85 public virtual BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
86 {
87 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 }
52 89
90 // Linksets move around the children so the linkset might need to compute the child position
91 public virtual OMV.Vector3 Position(BSPhysObject member)
92 { return member.RawPosition; }
93 public virtual OMV.Quaternion Orientation(BSPhysObject member)
94 { return member.RawOrientation; }
95 // TODO: does this need to be done for Velocity and RotationalVelocityy?
96
53 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 97 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
54 private float m_mass; 98 protected float m_mass;
55 public float LinksetMass 99 public float LinksetMass
56 { 100 {
57 get 101 get
58 { 102 {
59 m_mass = ComputeLinksetMass();
60 return m_mass; 103 return m_mass;
61 } 104 }
62 } 105 }
63 106
107 public virtual bool LinksetIsColliding { get { return false; } }
108
64 public OMV.Vector3 CenterOfMass 109 public OMV.Vector3 CenterOfMass
65 { 110 {
66 get { return ComputeLinksetCenterOfMass(); } 111 get { return ComputeLinksetCenterOfMass(); }
@@ -71,23 +116,31 @@ public class BSLinkset
71 get { return ComputeLinksetGeometricCenter(); } 116 get { return ComputeLinksetGeometricCenter(); }
72 } 117 }
73 118
74 public BSLinkset(BSScene scene, BSPrim parent) 119 protected void Initialize(BSScene scene, BSPhysObject parent)
75 { 120 {
76 // A simple linkset of one (no children) 121 // A simple linkset of one (no children)
77 m_physicsScene = scene; 122 LinksetID = m_nextLinksetID++;
78 m_linksetRoot = parent; 123 // We create LOTS of linksets.
79 m_children = new List<BSPrim>(); 124 if (m_nextLinksetID <= 0)
80 m_mass = parent.MassRaw; 125 m_nextLinksetID = 1;
126 PhysicsScene = scene;
127 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass;
81 } 130 }
82 131
83 // Link to a linkset where the child knows the parent. 132 // Link to a linkset where the child knows the parent.
84 // Parent changing should not happen so do some sanity checking. 133 // Parent changing should not happen so do some sanity checking.
85 // We return the parent's linkset so the child can track its membership. 134 // We return the parent's linkset so the child can track its membership.
86 public BSLinkset AddMeToLinkset(BSPrim child) 135 // Called at runtime.
136 public BSLinkset AddMeToLinkset(BSPhysObject child)
87 { 137 {
88 lock (m_linksetActivityLock) 138 lock (m_linksetActivityLock)
89 { 139 {
90 AddChildToLinkset(child); 140 // Don't add the root to its own linkset
141 if (!IsRoot(child))
142 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass();
91 } 144 }
92 return this; 145 return this;
93 } 146 }
@@ -95,36 +148,28 @@ public class BSLinkset
95 // Remove a child from a linkset. 148 // Remove a child from a linkset.
96 // Returns a new linkset for the child which is a linkset of one (just the 149 // Returns a new linkset for the child which is a linkset of one (just the
97 // orphened child). 150 // orphened child).
98 public BSLinkset RemoveMeFromLinkset(BSPrim child) 151 // Called at runtime.
152 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
99 { 153 {
100 lock (m_linksetActivityLock) 154 lock (m_linksetActivityLock)
101 { 155 {
102 if (IsRoot(child)) 156 if (IsRoot(child))
103 { 157 {
104 // if root of linkset, take the linkset apart 158 // Cannot remove the root from a linkset.
105 while (m_children.Count > 0) 159 return this;
106 {
107 // Note that we don't do a foreach because the remove routine
108 // takes it out of the list.
109 RemoveChildFromOtherLinkset(m_children[0]);
110 }
111 m_children.Clear(); // just to make sure
112 }
113 else
114 {
115 // Just removing a child from an existing linkset
116 RemoveChildFromLinkset(child);
117 } 160 }
161 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass();
118 } 163 }
119 164
120 // The child is down to a linkset of just itself 165 // The child is down to a linkset of just itself
121 return new BSLinkset(PhysicsScene, child); 166 return BSLinkset.Factory(PhysicsScene, child);
122 } 167 }
123 168
124 // Return 'true' if the passed object is the root object of this linkset 169 // Return 'true' if the passed object is the root object of this linkset
125 public bool IsRoot(BSPrim requestor) 170 public bool IsRoot(BSPhysObject requestor)
126 { 171 {
127 return (requestor.LocalID == m_linksetRoot.LocalID); 172 return (requestor.LocalID == LinksetRoot.LocalID);
128 } 173 }
129 174
130 public int NumberOfChildren { get { return m_children.Count; } } 175 public int NumberOfChildren { get { return m_children.Count; } }
@@ -133,12 +178,14 @@ public class BSLinkset
133 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 178 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
134 179
135 // Return 'true' if this child is in this linkset 180 // Return 'true' if this child is in this linkset
136 public bool HasChild(BSPrim child) 181 public bool HasChild(BSPhysObject child)
137 { 182 {
138 bool ret = false; 183 bool ret = false;
139 lock (m_linksetActivityLock) 184 lock (m_linksetActivityLock)
140 { 185 {
141 foreach (BSPrim bp in m_children) 186 ret = m_children.Contains(child);
187 /* Safer version but the above should work
188 foreach (BSPhysObject bp in m_children)
142 { 189 {
143 if (child.LocalID == bp.LocalID) 190 if (child.LocalID == bp.LocalID)
144 { 191 {
@@ -146,274 +193,132 @@ public class BSLinkset
146 break; 193 break;
147 } 194 }
148 } 195 }
196 */
149 } 197 }
150 return ret; 198 return ret;
151 } 199 }
152 200
153 private float ComputeLinksetMass() 201 // Perform an action on each member of the linkset including root prim.
154 { 202 // Depends on the action on whether this should be done at taint time.
155 float mass = m_linksetRoot.MassRaw; 203 public delegate bool ForEachMemberAction(BSPhysObject obj);
156 foreach (BSPrim bp in m_children) 204 public virtual bool ForEachMember(ForEachMemberAction action)
157 {
158 mass += bp.MassRaw;
159 }
160 return mass;
161 }
162
163 private OMV.Vector3 ComputeLinksetCenterOfMass()
164 { 205 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 206 bool ret = false;
166 float totalMass = m_linksetRoot.MassRaw;
167
168 lock (m_linksetActivityLock) 207 lock (m_linksetActivityLock)
169 { 208 {
170 foreach (BSPrim bp in m_children) 209 action(LinksetRoot);
210 foreach (BSPhysObject po in m_children)
171 { 211 {
172 com += bp.Position * bp.MassRaw; 212 if (action(po))
173 totalMass += bp.MassRaw; 213 break;
174 } 214 }
175 if (totalMass != 0f)
176 com /= totalMass;
177 } 215 }
178 216 return ret;
179 return com;
180 } 217 }
181 218
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 219 // I am the root of a linkset and a new child is being added
183 { 220 // Called while LinkActivity is locked.
184 OMV.Vector3 com = m_linksetRoot.Position; 221 protected abstract void AddChildToLinkset(BSPhysObject child);
185
186 lock (m_linksetActivityLock)
187 {
188 foreach (BSPrim bp in m_children)
189 {
190 com += bp.Position * bp.MassRaw;
191 }
192 com /= (m_children.Count + 1);
193 }
194 222
195 return com; 223 // I am the root of a linkset and one of my children is being removed.
196 } 224 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
197 226
198 // When physical properties are changed the linkset needs to recalculate 227 // When physical properties are changed the linkset needs to recalculate
199 // its internal properties. 228 // its internal properties.
200 public void Refresh(BSPrim requestor) 229 // May be called at runtime or taint-time.
201 { 230 public abstract void Refresh(BSPhysObject requestor);
202 // If there are no children, there aren't any constraints to recompute 231
203 if (!HasAnyChildren) 232 // The object is going dynamic (physical). Do any setup necessary
204 return; 233 // for a dynamic linkset.
205 234 // Only the state of the passed object can be modified. The rest of the linkset
206 // Only the root does the recomputation 235 // has not yet been fully constructed.
207 if (IsRoot(requestor)) 236 // Return 'true' if any properties updated on the passed object.
208 { 237 // Called at taint-time!
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 238 public abstract bool MakeDynamic(BSPhysObject child);
210 { 239
211 RecomputeLinksetConstraintVariables(); 240 // The object is going static (non-physical). Do any setup necessary
212 }); 241 // for a static linkset.
213 } 242 // Return 'true' if any properties updated on the passed object.
214 } 243 // Called at taint-time!
215 244 public abstract bool MakeStatic(BSPhysObject child);
216 // Call each of the constraints that make up this linkset and recompute the 245
217 // various transforms and variables. Used when objects are added or removed 246 // Called when a parameter update comes from the physics engine for any object
218 // from a linkset to make sure the constraints know about the new mass and 247 // of the linkset is received.
219 // geometry. 248 // Called at taint-time!!
220 // Must only be called at taint time!! 249 public abstract void UpdateProperties(BSPhysObject physObject);
221 private bool RecomputeLinksetConstraintVariables() 250
251 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root.
253 // This is called when the root body is changing.
254 // Returns 'true' of something was actually removed and would need restoring
255 // Called at taint-time!!
256 public abstract bool RemoveBodyDependencies(BSPrim child);
257
258 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
259 // this routine will restore the removed constraints.
260 // Called at taint-time!!
261 public abstract void RestoreBodyDependencies(BSPrim child);
262
263 // ================================================================
264 protected virtual float ComputeLinksetMass()
222 { 265 {
223 float linksetMass = LinksetMass; 266 float mass = LinksetRoot.RawMass;
224 lock (m_linksetActivityLock) 267 if (HasAnyChildren)
225 { 268 {
226 foreach (BSPrim child in m_children) 269 lock (m_linksetActivityLock)
227 { 270 {
228 BSConstraint constrain; 271 foreach (BSPhysObject bp in m_children)
229 if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain))
230 {
231 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
232 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
233 constrain.RecomputeConstraintVariables(linksetMass);
234 }
235 else
236 { 272 {
237 // Non-fatal error that can happen when children are being added to the linkset but 273 mass += bp.RawMass;
238 // their constraints have not been created yet.
239 // Caused by the fact that m_children is built at run time but building constraints
240 // happens at taint time.
241 // m_physicsScene.Logger.ErrorFormat("[BULLETSIM LINKSET] RecomputeLinksetConstraintVariables: constraint not found for root={0}, child={1}",
242 // m_linksetRoot.Body.ID, child.Body.ID);
243 } 274 }
244 } 275 }
245 } 276 }
246 return false; 277 return mass;
247 } 278 }
248 279
249 // I am the root of a linkset and a new child is being added 280 protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
250 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child)
252 { 281 {
253 if (!HasChild(child)) 282 OMV.Vector3 com;
283 lock (m_linksetActivityLock)
254 { 284 {
255 m_children.Add(child); 285 com = LinksetRoot.Position * LinksetRoot.RawMass;
286 float totalMass = LinksetRoot.RawMass;
256 287
257 BSPrim rootx = LinksetRoot; // capture the root as of now 288 foreach (BSPhysObject bp in m_children)
258 BSPrim childx = child;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate()
260 { 289 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); 290 com += bp.Position * bp.RawMass;
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 291 totalMass += bp.RawMass;
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 292 }
264 }); 293 if (totalMass != 0f)
294 com /= totalMass;
265 } 295 }
266 return;
267 }
268 296
269 // Forcefully removing a child from a linkset. 297 return com;
270 // This is not being called by the child so we have to make sure the child doesn't think
271 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild)
275 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild);
277 RemoveChildFromLinkset(pchild);
278 } 298 }
279 299
280 // I am the root of a linkset and one of my children is being removed. 300 protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
281 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child)
283 { 301 {
284 if (m_children.Remove(child)) 302 OMV.Vector3 com;
303 lock (m_linksetActivityLock)
285 { 304 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now 305 com = LinksetRoot.Position;
287 BSPrim childx = child;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
289 {
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
292
293 PhysicallyUnlinkAChildFromRoot(rootx, childx);
294 });
295 306
296 RecomputeLinksetConstraintVariables(); 307 foreach (BSPhysObject bp in m_children)
297 } 308 {
298 else 309 com += bp.Position * bp.RawMass;
299 { 310 }
300 // This will happen if we remove the root of the linkset first. Non-fatal occurance. 311 com /= (m_children.Count + 1);
301 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
302 } 312 }
303 return;
304 }
305
306 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim)
309 {
310 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion();
312
313 // Relative position normalized to the root prim
314 // Essentually a vector pointing from center of rootPrim to center of childPrim
315 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
316
317 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319
320 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
322 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
323 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}",
324 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint);
325 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body,
327 midPoint,
328 true,
329 true
330 );
331 /* NOTE: attempt to build constraint with full frame computation, etc.
332 * Using the midpoint is easier since it lets the Bullet code use the transforms
333 * of the objects.
334 * Code left here as an example.
335 // ==================================================================================
336 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
338 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
339
340 // relative rotation of the child to the parent
341 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
342 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
343
344 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
346 // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
347 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body,
350 OMV.Vector3.Zero,
351 OMV.Quaternion.Inverse(rootPrim.Orientation),
352 OMV.Vector3.Zero,
353 OMV.Quaternion.Inverse(childPrim.Orientation),
354 // A point half way between the parent and child
355 // childRelativePosition/2,
356 // childRelativeRotation,
357 // childRelativePosition/2,
358 // inverseChildRelativeRotation,
359 true,
360 true
361 );
362 // ==================================================================================
363 */
364
365 m_physicsScene.Constraints.AddConstraint(constrain);
366
367 // zero linear and angular limits makes the objects unable to move in relation to each other
368 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
369 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
370
371 // tweek the constraint to increase stability
372 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
373 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
377
378 RecomputeLinksetConstraintVariables();
379 }
380 313
381 // Remove linkage between myself and a particular child 314 return com;
382 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim)
384 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}",
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID);
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
388
389 // Find the constraint for this link and get rid of it from the overall collection and from my list
390 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body);
391
392 // Make the child refresh its location
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
394 }
395
396 // Remove linkage between myself and any possible children I might have
397 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim)
399 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
402
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body);
404 }
405
406 // Invoke the detailed logger and output something if it's enabled.
407 private void DebugLog(string msg, params Object[] args)
408 {
409 if (m_physicsScene.ShouldDebugLog)
410 m_physicsScene.Logger.DebugFormat(msg, args);
411 } 315 }
412 316
413 // Invoke the detailed logger and output something if it's enabled. 317 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 318 protected void DetailLog(string msg, params Object[] args)
415 { 319 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 320 if (PhysicsScene.PhysicsLogging.Enabled)
321 PhysicsScene.DetailLog(msg, args);
417 } 322 }
418 323
419} 324}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
new file mode 100755
index 0000000..b9c2cf9
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -0,0 +1,275 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetCompound : BSLinkset
36{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 {
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren)
49 {
50 ret = BSPhysicsShapeType.SHAPE_COMPOUND;
51 }
52 // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
53 return ret;
54 }
55
56 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor)
61 {
62 // External request for Refresh (from BSPrim) is not necessary
63 // InternalRefresh(requestor);
64 }
65
66 private void InternalRefresh(BSPhysObject requestor)
67 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
69 // Queue to happen after all the other taint processing
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
71 {
72 if (IsRoot(requestor) && HasAnyChildren)
73 RecomputeLinksetCompound();
74 });
75 }
76
77 // The object is going dynamic (physical). Do any setup necessary
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object.
82 // Called at taint-time!
83 public override bool MakeDynamic(BSPhysObject child)
84 {
85 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child))
88 {
89 // Physical children are removed from the world as the shape ofthe root compound
90 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
93 ret = true;
94 }
95 return ret;
96 }
97
98 // The object is going static (non-physical). Do any setup necessary for a static linkset.
99 // Return 'true' if any properties updated on the passed object.
100 // This doesn't normally happen -- OpenSim removes the objects from the physical
101 // world if it is a static linkset.
102 // Called at taint-time!
103 public override bool MakeStatic(BSPhysObject child)
104 {
105 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child))
108 {
109 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay.
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false);
113 ret = true;
114 }
115 return ret;
116 }
117
118 // Called at taint-time!!
119 public override void UpdateProperties(BSPhysObject updated)
120 {
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
134 }
135
136 // Routine called when rebuilding the body of some member of the linkset.
137 // Since we don't keep in world relationships, do nothing unless it's a child changing.
138 // Returns 'true' of something was actually removed and would need restoring
139 // Called at taint-time!!
140 public override bool RemoveBodyDependencies(BSPrim child)
141 {
142 bool ret = false;
143
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
146
147 if (!IsRoot(child))
148 {
149 // Cause the current shape to be freed and the new one to be built.
150 InternalRefresh(LinksetRoot);
151 ret = true;
152 }
153
154 return ret;
155 }
156
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints.
159 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child)
161 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
163 }
164
165 // ================================================================
166
167 // Add a new child to the linkset.
168 // Called while LinkActivity is locked.
169 protected override void AddChildToLinkset(BSPhysObject child)
170 {
171 if (!HasChild(child))
172 {
173 m_children.Add(child);
174
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176
177 // Cause constraints and assorted properties to be recomputed before the next simulation step.
178 InternalRefresh(LinksetRoot);
179 }
180 return;
181 }
182
183 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 {
187 if (m_children.Remove(child))
188 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"),
192 child.LocalID, child.PhysBody.ptr.ToString("X"));
193
194 // Cause the child's body to be rebuilt and thus restored to normal operation
195 child.ForceBodyShapeRebuild(false);
196
197 if (!HasAnyChildren)
198 {
199 // The linkset is now empty. The root needs rebuilding.
200 LinksetRoot.ForceBodyShapeRebuild(false);
201 }
202 else
203 {
204 // Schedule a rebuild of the linkset before the next simulation tick.
205 InternalRefresh(LinksetRoot);
206 }
207 }
208 return;
209 }
210
211 // Called before the simulation step to make sure the compound based linkset
212 // is all initialized.
213 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart.
215 // Called at taint time!!
216 private void RecomputeLinksetCompound()
217 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 {
227 if (!IsRoot(cPrim))
228 {
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
236
237 if (cPrim.PhysShape.isNativeShape)
238 {
239 // Native shapes are not shared so we need to create a new one.
240 // A mesh or hull is created because scale is not available on a native shape.
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
242 BulletShape saveShape = cPrim.PhysShape;
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
253 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
256 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262
263 // With all of the linkset packed into the root prim, it has the mass of everyone.
264 float linksetMass = LinksetMass;
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr);
268
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
272
273 }
274}
275} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..c855fda
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,327 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public sealed class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // This is queued in the 'post taint' queue so the
47 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor)
49 {
50 // Queue to happen after all the other taint processing
51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
52 {
53 if (HasAnyChildren && IsRoot(requestor))
54 RecomputeLinksetConstraints();
55 });
56 }
57
58 // The object is going dynamic (physical). Do any setup necessary
59 // for a dynamic linkset.
60 // Only the state of the passed object can be modified. The rest of the linkset
61 // has not yet been fully constructed.
62 // Return 'true' if any properties updated on the passed object.
63 // Called at taint-time!
64 public override bool MakeDynamic(BSPhysObject child)
65 {
66 // What is done for each object in BSPrim is what we want.
67 return false;
68 }
69
70 // The object is going static (non-physical). Do any setup necessary for a static linkset.
71 // Return 'true' if any properties updated on the passed object.
72 // This doesn't normally happen -- OpenSim removes the objects from the physical
73 // world if it is a static linkset.
74 // Called at taint-time!
75 public override bool MakeStatic(BSPhysObject child)
76 {
77 // What is done for each object in BSPrim is what we want.
78 return false;
79 }
80
81 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated)
83 {
84 // Nothing to do for constraints on property updates
85 }
86
87 // The children of the linkset are moved around by the constraints.
88 // Just grab the current values of wherever it is right now.
89 public override OMV.Vector3 Position(BSPhysObject member)
90 {
91 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
92 }
93
94 public override OMV.Quaternion Orientation(BSPhysObject member)
95 {
96 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
97 }
98
99 // Routine called when rebuilding the body of some member of the linkset.
100 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step.
102 // Returns 'true' of something was actually removed and would need restoring
103 // Called at taint-time!!
104 public override bool RemoveBodyDependencies(BSPrim child)
105 {
106 bool ret = false;
107
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"));
110
111 lock (m_linksetActivityLock)
112 {
113 // Just undo all the constraints for this linkset. Rebuild at the end of the step.
114 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
115 // Cause the constraints, et al to be rebuilt before the next simulation step.
116 Refresh(LinksetRoot);
117 }
118 return ret;
119 }
120
121 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
122 // this routine will restore the removed constraints.
123 // Called at taint-time!!
124 public override void RestoreBodyDependencies(BSPrim child)
125 {
126 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints.
127 }
128
129 // ================================================================
130
131 // Add a new child to the linkset.
132 // Called while LinkActivity is locked.
133 protected override void AddChildToLinkset(BSPhysObject child)
134 {
135 if (!HasChild(child))
136 {
137 m_children.Add(child);
138
139 DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
140
141 // Cause constraints and assorted properties to be recomputed before the next simulation step.
142 Refresh(LinksetRoot);
143 }
144 return;
145 }
146
147 // Remove the specified child from the linkset.
148 // Safe to call even if the child is not really in my linkset.
149 protected override void RemoveChildFromLinkset(BSPhysObject child)
150 {
151 if (m_children.Remove(child))
152 {
153 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
154 BSPhysObject childx = child;
155
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"),
159 childx.LocalID, childx.PhysBody.ptr.ToString("X"));
160
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 {
163 PhysicallyUnlinkAChildFromRoot(rootx, childx);
164 });
165 // See that the linkset parameters are recomputed at the end of the taint time.
166 Refresh(LinksetRoot);
167 }
168 else
169 {
170 // Non-fatal occurance.
171 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
172 }
173 return;
174 }
175
176 // Create a constraint between me (root of linkset) and the passed prim (the child).
177 // Called at taint time!
178 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
179 {
180 // Don't build the constraint when asked. Put it off until just before the simulation step.
181 Refresh(rootPrim);
182 }
183
184 private BSConstraint BuildConstraint(BSPhysObject rootPrim, BSPhysObject childPrim)
185 {
186 // Zero motion for children so they don't interpolate
187 childPrim.ZeroMotion(true);
188
189 // Relative position normalized to the root prim
190 // Essentually a vector pointing from center of rootPrim to center of childPrim
191 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
192
193 // real world coordinate of midpoint between the two objects
194 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
195
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"),
200 rootPrim.Position, childPrim.Position, midPoint);
201
202 // create a constraint that allows no freedom of movement between the two objects
203 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
204
205 BSConstraint6Dof constrain = new BSConstraint6Dof(
206 PhysicsScene.World, rootPrim.PhysBody, childPrim.PhysBody, midPoint, true, true );
207 // PhysicsScene.World, childPrim.BSBody, rootPrim.BSBody, midPoint, true, true );
208
209 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
210 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
211 * of the objects.
212 * Code left for future programmers.
213 // ==================================================================================
214 // relative position normalized to the root prim
215 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
216 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
217
218 // relative rotation of the child to the parent
219 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
220 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
221
222 DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
223 BS6DofConstraint constrain = new BS6DofConstraint(
224 PhysicsScene.World, rootPrim.Body, childPrim.Body,
225 OMV.Vector3.Zero,
226 OMV.Quaternion.Inverse(rootPrim.Orientation),
227 OMV.Vector3.Zero,
228 OMV.Quaternion.Inverse(childPrim.Orientation),
229 true,
230 true
231 );
232 // ==================================================================================
233 */
234
235 PhysicsScene.Constraints.AddConstraint(constrain);
236
237 // zero linear and angular limits makes the objects unable to move in relation to each other
238 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240
241 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
248 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
250 }
251 return constrain;
252 }
253
254 // Remove linkage between the linkset root and a particular child
255 // The root and child bodies are passed in because we need to remove the constraint between
256 // the bodies that were present at unlink time.
257 // Called at taint time!
258 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
259 {
260 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"),
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"));
265
266 // Find the constraint for this link and get rid of it from the overall collection and from my list
267 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 {
269 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr);
271 ret = true;
272 }
273
274 return ret;
275 }
276
277 // Remove linkage between myself and any possible children I might have.
278 // Returns 'true' of any constraints were destroyed.
279 // Called at taint time!
280 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
281 {
282 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
283
284 return PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody);
285 }
286
287 // Call each of the constraints that make up this linkset and recompute the
288 // various transforms and variables. Create constraints of not created yet.
289 // Called before the simulation step to make sure the constraint based linkset
290 // is all initialized.
291 // Called at taint time!!
292 private void RecomputeLinksetConstraints()
293 {
294 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
296
297 // DEBUG: see of inter-linkset collisions are causing problems
298 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
299 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
300 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
302
303 foreach (BSPhysObject child in m_children)
304 {
305 // A child in the linkset physically shows the mass of the whole linkset.
306 // This allows Bullet to apply enough force on the child to move the whole linkset.
307 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass);
309
310 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
312 {
313 // If constraint doesn't exist yet, create it.
314 constrain = BuildConstraint(LinksetRoot, child);
315 }
316 constrain.RecomputeConstraintVariables(linksetMass);
317
318 // DEBUG: see of inter-linkset collisions are causing problems
319 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
320 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
321
322 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
323 }
324
325 }
326}
327}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
new file mode 100755
index 0000000..bc6e4c4
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -0,0 +1,104 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4using OpenMetaverse;
5
6namespace OpenSim.Region.Physics.BulletSPlugin
7{
8public abstract class BSMotor
9{
10 public virtual void Reset() { }
11 public virtual void Zero() { }
12}
13// Can all the incremental stepping be replaced with motor classes?
14public class BSVMotor : BSMotor
15{
16 public Vector3 FrameOfReference { get; set; }
17 public Vector3 Offset { get; set; }
18
19 public float TimeScale { get; set; }
20 public float TargetValueDecayTimeScale { get; set; }
21 public Vector3 CurrentValueReductionTimescale { get; set; }
22 public float Efficiency { get; set; }
23
24 public Vector3 TargetValue { get; private set; }
25 public Vector3 CurrentValue { get; private set; }
26
27
28
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
30 {
31 TimeScale = timeScale;
32 TargetValueDecayTimeScale = decayTimeScale;
33 CurrentValueReductionTimescale = frictionTimeScale;
34 Efficiency = efficiency;
35 }
36 public void SetCurrent(Vector3 current)
37 {
38 CurrentValue = current;
39 }
40 public void SetTarget(Vector3 target)
41 {
42 TargetValue = target;
43 }
44 public Vector3 Step(float timeStep)
45 {
46 if (CurrentValue.LengthSquared() > 0.001f)
47 {
48 // Vector3 origDir = Target; // DEBUG
49 // Vector3 origVel = CurrentValue; // DEBUG
50
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
53 CurrentValue += addAmount;
54
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
56 TargetValue *= (1f - decayFactor);
57
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
59 CurrentValue *= (Vector3.One - frictionFactor);
60 }
61 else
62 {
63 // if what remains of direction is very small, zero it.
64 TargetValue = Vector3.Zero;
65 CurrentValue = Vector3.Zero;
66
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
68 }
69 return CurrentValue;
70 }
71}
72
73public class BSFMotor : BSMotor
74{
75 public float TimeScale { get; set; }
76 public float DecayTimeScale { get; set; }
77 public float Friction { get; set; }
78 public float Efficiency { get; set; }
79
80 public float Target { get; private set; }
81 public float CurrentValue { get; private set; }
82
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
84 {
85 }
86 public void SetCurrent(float target)
87 {
88 }
89 public void SetTarget(float target)
90 {
91 }
92 public float Step(float timeStep)
93 {
94 return 0f;
95 }
96}
97public class BSPIDMotor : BSMotor
98{
99 // TODO: write and use this one
100 BSPIDMotor()
101 {
102 }
103}
104}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
new file mode 100755
index 0000000..f6a890e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -0,0 +1,263 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */
48public abstract class BSPhysObject : PhysicsActor
49{
50 protected BSPhysObject()
51 {
52 }
53 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
54 {
55 PhysicsScene = parentScene;
56 LocalID = localID;
57 PhysObjectName = name;
58 TypeName = typeName;
59
60 Linkset = BSLinkset.Factory(PhysicsScene, this);
61 LastAssetBuildFailed = false;
62
63 CollisionCollection = new CollisionEventUpdate();
64 SubscribedEventsMs = 0;
65 CollidingStep = 0;
66 CollidingGroundStep = 0;
67 }
68
69 public BSScene PhysicsScene { get; protected set; }
70 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
71 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; }
73
74 public BSLinkset Linkset { get; set; }
75
76 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass);
80
81 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; }
83
84 // Reference to the physical body (btCollisionObject) of this object
85 public BulletBody PhysBody;
86 // Reference to the physical shape (btCollisionShape) of this object
87 public BulletShape PhysShape;
88
89 // 'true' if the mesh's underlying asset failed to build.
90 // This will keep us from looping after the first time the build failed.
91 public bool LastAssetBuildFailed { get; set; }
92
93 // The objects base shape information. Null if not a prim type shape.
94 public PrimitiveBaseShape BaseShape { get; protected set; }
95 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape
98 {
99 get { return BSPhysicsShapeType.SHAPE_UNKNOWN; }
100 }
101
102 // When the physical properties are updated, an EntityProperty holds the update values.
103 // Keep the current and last EntityProperties to enable computation of differences
104 // between the current update and the previous values.
105 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; }
107
108 public abstract OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; }
111
112 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime);
115
116 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
117 public virtual void StepVehicle(float timeStep) { }
118
119 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop);
121
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; }
127
128 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; }
130
131 public abstract OMV.Vector3 ForceVelocity { get; set; }
132
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
134
135 public abstract float ForceBuoyancy { get; set; }
136
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138
139 #region Collisions
140
141 // Requested number of milliseconds between collision events. Zero means disabled.
142 protected int SubscribedEventsMs { get; set; }
143 // Given subscription, the time that a collision may be passed up
144 protected int NextCollisionOkTime { get; set; }
145 // The simulation step that last had a collision
146 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; }
149 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; }
151
152 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection;
154
155 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up.
157 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 {
161 bool ret = false;
162
163 // The following lines make IsColliding() and IsCollidingGround() work
164 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 {
167 CollidingGroundStep = PhysicsScene.SimulationStep;
168 }
169
170 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
172 {
173 return ret;
174 }
175
176 // if someone has subscribed for collision events....
177 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
180 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);
181
182 ret = true;
183 }
184 return ret;
185 }
186
187 // Send the collected collisions into the simulator.
188 // Called at taint time from within the Step() function thus no locking problems
189 // with CollisionCollection and ObjectsWithNoMoreCollisions.
190 // Return 'true' if there were some actual collisions passed up
191 public virtual bool SendCollisions()
192 {
193 bool ret = true;
194 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0;
196
197 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
199 {
200 NextCollisionOkTime = PhysicsScene.SimulationNowTime + SubscribedEventsMs;
201
202 // We are called if we previously had collisions. If there are no collisions
203 // this time, send up one last empty event so OpenSim can sense collision end.
204 if (CollisionCollection.Count == 0)
205 {
206 // If I have no collisions this time, remove me from the list of objects with collisions.
207 ret = false;
208 }
209
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection);
212
213 // The collisionCollection structure is passed around in the simulator.
214 // Make sure we don't have a handle to that one and that a new one is used for next time.
215 CollisionCollection = new CollisionEventUpdate();
216 }
217 return ret;
218 }
219
220 // Subscribe for collision events.
221 // Parameter is the millisecond rate the caller wishes collision events to occur.
222 public override void SubscribeEvents(int ms) {
223 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
224 SubscribedEventsMs = ms;
225 if (ms > 0)
226 {
227 // make sure first collision happens
228 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
229
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 });
234 }
235 else
236 {
237 // Subscribing for zero or less is the same as unsubscribing
238 UnSubscribeEvents();
239 }
240 }
241 public override void UnSubscribeEvents() {
242 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
243 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 });
248 }
249 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0);
252 }
253
254 #endregion // Collisions
255
256 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args)
258 {
259 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args);
261 }
262}
263}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 0f027b8..20f5180 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -33,7 +33,7 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35 /// <summary> 35 /// <summary>
36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. 36 /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim.
37 /// This module interfaces to an unmanaged C++ library which makes the 37 /// This module interfaces to an unmanaged C++ library which makes the
38 /// actual calls into the Bullet physics engine. 38 /// actual calls into the Bullet physics engine.
39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. 39 /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/.
@@ -62,7 +62,7 @@ public class BSPlugin : IPhysicsPlugin
62 if (Util.IsWindows()) 62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll"); 63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the 64 // If not Windows, loading is performed by the
65 // Mono loader as specified in 65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". 66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67 67
68 _mScene = new BSScene(sceneIdentifier); 68 _mScene = new BSScene(sceneIdentifier);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 9c20004..2b3fa25 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -24,6 +24,7 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
27using System; 28using System;
28using System.Reflection; 29using System.Reflection;
29using System.Collections.Generic; 30using System.Collections.Generic;
@@ -36,32 +37,17 @@ using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36 37
37namespace OpenSim.Region.Physics.BulletSPlugin 38namespace OpenSim.Region.Physics.BulletSPlugin
38{ 39{
40
39 [Serializable] 41 [Serializable]
40public sealed class BSPrim : PhysicsActor 42public sealed class BSPrim : BSPhysObject
41{ 43{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
44 46
45 private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); } 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
46 48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
47 private IMesh _mesh;
48 private PrimitiveBaseShape _pbs;
49 private ShapeData.PhysicsShapeType _shapeType;
50 private ulong _meshKey;
51 private ulong _hullKey;
52 private List<ConvexResult> _hulls;
53
54 private BSScene _scene;
55 public BSScene Scene { get { return _scene; } }
56 private String _avName;
57 private uint _localID = 0;
58
59 // _size is what the user passed. _scale is what we pass to the physics engine with the mesh.
60 // Often _scale is unity because the meshmerizer will apply _size when creating the mesh.
61 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
62 private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
63 50
64 private bool _stopped;
65 private bool _grabbed; 51 private bool _grabbed;
66 private bool _isSelected; 52 private bool _isSelected;
67 private bool _isVolumeDetect; 53 private bool _isVolumeDetect;
@@ -89,25 +75,6 @@ public sealed class BSPrim : PhysicsActor
89 private bool _kinematic; 75 private bool _kinematic;
90 private float _buoyancy; 76 private float _buoyancy;
91 77
92 // Membership in a linkset is controlled by this class.
93 private BSLinkset _linkset;
94 public BSLinkset Linkset
95 {
96 get { return _linkset; }
97 set { _linkset = value; }
98 }
99
100 private int _subscribedEventsMs = 0;
101 private int _nextCollisionOkTime = 0;
102 long _collidingStep;
103 long _collidingGroundStep;
104
105 private BulletBody m_body;
106 public BulletBody Body {
107 get { return m_body; }
108 set { m_body = value; }
109 }
110
111 private BSDynamics _vehicle; 78 private BSDynamics _vehicle;
112 79
113 private OMV.Vector3 _PIDTarget; 80 private OMV.Vector3 _PIDTarget;
@@ -120,110 +87,116 @@ public sealed class BSPrim : PhysicsActor
120 87
121 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
122 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
90 : base(parent_scene, localID, primName, "BSPrim")
123 { 91 {
124 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); 92 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
125 _localID = localID; 93 _physicsActorType = (int)ActorTypes.Prim;
126 _avName = primName;
127 _scene = parent_scene;
128 _position = pos; 94 _position = pos;
129 _size = size; 95 _size = size;
130 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type 96 Scale = size; // the scale will be set by CreateGeom depending on object type
131 _orientation = rotation; 97 _orientation = rotation;
132 _buoyancy = 1f; 98 _buoyancy = 1f;
133 _velocity = OMV.Vector3.Zero; 99 _velocity = OMV.Vector3.Zero;
134 _rotationalVelocity = OMV.Vector3.Zero; 100 _rotationalVelocity = OMV.Vector3.Zero;
135 _hullKey = 0; 101 BaseShape = pbs;
136 _meshKey = 0;
137 _pbs = pbs;
138 _isPhysical = pisPhysical; 102 _isPhysical = pisPhysical;
139 _isVolumeDetect = false; 103 _isVolumeDetect = false;
140 _subscribedEventsMs = 0; 104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
141 _friction = _scene.Params.defaultFriction; // TODO: compute based on object material 105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
142 _density = _scene.Params.defaultDensity; // TODO: compute based on object material 106 _restitution = PhysicsScene.Params.defaultRestitution;
143 _restitution = _scene.Params.defaultRestitution; 107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
144 _linkset = new BSLinkset(_scene, this); // a linkset of one
145 _vehicle = new BSDynamics(this); // add vehicleness
146 _mass = CalculateMass(); 108 _mass = CalculateMass();
147 // do the actual object creation at taint time 109
110 // No body or shape yet
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero);
112 PhysShape = new BulletShape(IntPtr.Zero);
113
148 DetailLog("{0},BSPrim.constructor,call", LocalID); 114 DetailLog("{0},BSPrim.constructor,call", LocalID);
149 _scene.TaintedObject("BSPrim.create", delegate() 115 // do the actual object creation at taint time
116 PhysicsScene.TaintedObject("BSPrim.create", delegate()
150 { 117 {
151 RecreateGeomAndObject(); 118 CreateGeomAndObject(true);
152 119
153 // Get the pointer to the physical body for this object. 120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
154 // At the moment, we're still letting BulletSim manage the creation and destruction
155 // of the object. Someday we'll move that into the C# code.
156 m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
157 }); 121 });
158 } 122 }
159 123
160 // called when this prim is being destroyed and we should free all the resources 124 // called when this prim is being destroyed and we should free all the resources
161 public void Destroy() 125 public override void Destroy()
162 { 126 {
163 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
164 128
165 // Undo any links between me and any other object 129 // Undo any links between me and any other object
166 BSPrim parentBefore = _linkset.LinksetRoot; 130 BSPhysObject parentBefore = Linkset.LinksetRoot;
167 int childrenBefore = _linkset.NumberOfChildren; 131 int childrenBefore = Linkset.NumberOfChildren;
168 132
169 _linkset = _linkset.RemoveMeFromLinkset(this); 133 Linkset = Linkset.RemoveMeFromLinkset(this);
170 134
171 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}", 135 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
172 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 136 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
173 137
174 // Undo any vehicle properties 138 // Undo any vehicle properties
175 this.VehicleType = (int)Vehicle.TYPE_NONE; 139 this.VehicleType = (int)Vehicle.TYPE_NONE;
176 140
177 _scene.TaintedObject("BSPrim.destroy", delegate() 141 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
178 { 142 {
179 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
180 // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. 144 // If there are physical body and shape, release my use of same.
181 BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); 145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
182 }); 147 });
183 } 148 }
184 149
185 public override bool Stopped { 150 // No one uses this property.
186 get { return _stopped; } 151 public override bool Stopped {
152 get { return false; }
187 } 153 }
188 public override OMV.Vector3 Size { 154 public override OMV.Vector3 Size {
189 get { return _size; } 155 get { return _size; }
190 set { 156 set {
157 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built.
191 _size = value; 159 _size = value;
192 _scene.TaintedObject("BSPrim.setSize", delegate() 160 ForceBodyShapeRebuild(false);
193 { 161 }
194 _mass = CalculateMass(); // changing size changes the mass
195 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
196 // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
197 RecreateGeomAndObject();
198 });
199 }
200 } 162 }
201 public override PrimitiveBaseShape Shape { 163 // Scale is what we set in the physics engine. It is different than 'size' in that
164 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
165 public override OMV.Vector3 Scale { get; set; }
166
167 public override PrimitiveBaseShape Shape {
202 set { 168 set {
203 _pbs = value; 169 BaseShape = value;
204 _scene.TaintedObject("BSPrim.setShape", delegate() 170 ForceBodyShapeRebuild(false);
205 { 171 }
206 _mass = CalculateMass(); // changing the shape changes the mass
207 RecreateGeomAndObject();
208 });
209 }
210 } 172 }
211 public override uint LocalID { 173 // Whatever the linkset wants is what I want.
212 set { _localID = value; } 174 public override BSPhysicsShapeType PreferredPhysicalShape
213 get { return _localID; } 175 { get { return Linkset.PreferredPhysicalShape(this); } }
176
177 public override bool ForceBodyShapeRebuild(bool inTaintTime)
178 {
179 LastAssetBuildFailed = false;
180 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
181 {
182 _mass = CalculateMass(); // changing the shape changes the mass
183 CreateGeomAndObject(true);
184 });
185 return true;
214 } 186 }
215 public override bool Grabbed { 187 public override bool Grabbed {
216 set { _grabbed = value; 188 set { _grabbed = value;
217 } 189 }
218 } 190 }
219 public override bool Selected { 191 public override bool Selected {
220 set { 192 set {
221 _isSelected = value; 193 _isSelected = value;
222 _scene.TaintedObject("BSPrim.setSelected", delegate() 194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
223 { 195 {
224 SetObjectDynamic(); 196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
197 SetObjectDynamic(false);
225 }); 198 });
226 } 199 }
227 } 200 }
228 public override void CrossingFailure() { return; } 201 public override void CrossingFailure() { return; }
229 202
@@ -232,158 +205,260 @@ public sealed class BSPrim : PhysicsActor
232 BSPrim parent = obj as BSPrim; 205 BSPrim parent = obj as BSPrim;
233 if (parent != null) 206 if (parent != null)
234 { 207 {
235 DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID); 208 BSPhysObject parentBefore = Linkset.LinksetRoot;
236 BSPrim parentBefore = _linkset.LinksetRoot; 209 int childrenBefore = Linkset.NumberOfChildren;
237 int childrenBefore = _linkset.NumberOfChildren;
238 210
239 _linkset = parent.Linkset.AddMeToLinkset(this); 211 Linkset = parent.Linkset.AddMeToLinkset(this);
240 212
241 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 213 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
242 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 214 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
243 } 215 }
244 return; 216 return;
245 } 217 }
246 218
247 // delink me from my linkset 219 // delink me from my linkset
248 public override void delink() { 220 public override void delink() {
249 // TODO: decide if this parent checking needs to happen at taint time 221 // TODO: decide if this parent checking needs to happen at taint time
250 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen 222 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
251 DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID,
252 _linkset.LinksetRoot._avName+"/"+_linkset.LinksetRoot.LocalID.ToString());
253 223
254 BSPrim parentBefore = _linkset.LinksetRoot; 224 BSPhysObject parentBefore = Linkset.LinksetRoot;
255 int childrenBefore = _linkset.NumberOfChildren; 225 int childrenBefore = Linkset.NumberOfChildren;
256 226
257 _linkset = _linkset.RemoveMeFromLinkset(this); 227 Linkset = Linkset.RemoveMeFromLinkset(this);
258 228
259 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 229 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
260 LocalID, parentBefore.LocalID, childrenBefore, _linkset.LinksetRoot.LocalID, _linkset.NumberOfChildren); 230 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
261 return; 231 return;
262 } 232 }
263 233
264 // Set motion values to zero. 234 // Set motion values to zero.
265 // Do it to the properties so the values get set in the physics engine. 235 // Do it to the properties so the values get set in the physics engine.
266 // Push the setting of the values to the viewer. 236 // Push the setting of the values to the viewer.
267 // Called at taint time! 237 // Called at taint time!
268 public void ZeroMotion() 238 public override void ZeroMotion(bool inTaintTime)
269 { 239 {
270 _velocity = OMV.Vector3.Zero; 240 _velocity = OMV.Vector3.Zero;
271 _acceleration = OMV.Vector3.Zero; 241 _acceleration = OMV.Vector3.Zero;
272 _rotationalVelocity = OMV.Vector3.Zero; 242 _rotationalVelocity = OMV.Vector3.Zero;
273 243
274 // Zero some other properties directly into the physics engine 244 // Zero some other properties in the physics engine
275 BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); 245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
276 BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero); 246 {
277 BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); 247 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
278 BulletSimAPI.ClearForces2(Body.Ptr); 248 });
249 }
250 public override void ZeroAngularMotion(bool inTaintTime)
251 {
252 _rotationalVelocity = OMV.Vector3.Zero;
253 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
258 });
279 } 259 }
280 260
281 public override void LockAngularMotion(OMV.Vector3 axis) 261 public override void LockAngularMotion(OMV.Vector3 axis)
282 { 262 {
283 // DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); 263 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
284 return; 264 return;
285 } 265 }
286 266
287 public override OMV.Vector3 Position { 267 public override OMV.Vector3 RawPosition
288 get { 268 {
289 if (!_linkset.IsRoot(this)) 269 get { return _position; }
290 // child prims move around based on their parent. Need to get the latest location 270 set { _position = value; }
291 _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 271 }
272 public override OMV.Vector3 Position {
273 get {
274 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this);
292 277
293 // don't do the GetObjectPosition for root elements because this function is called a zillion times 278 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
294 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
295 return _position; 280 return _position;
296 } 281 }
297 set { 282 set {
283 // If the position must be forced into the physics engine, use ForcePosition.
284 if (_position == value)
285 {
286 return;
287 }
298 _position = value; 288 _position = value;
299 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? 289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
300 _scene.TaintedObject("BSPrim.setPosition", delegate() 290 PositionSanityCheck(false);
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
301 { 292 {
302 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
303 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
295 ActivateIfPhysical(false);
304 }); 296 });
305 } 297 }
298 }
299 public override OMV.Vector3 ForcePosition {
300 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
302 return _position;
303 }
304 set {
305 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better.
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
308 ActivateIfPhysical(false);
309 }
310 }
311
312 // Check that the current position is sane and, if not, modify the position to make it so.
313 // Check for being below terrain and being out of bounds.
314 // Returns 'true' of the position was made sane by some action.
315 private bool PositionSanityCheck(bool inTaintTime)
316 {
317 bool ret = false;
318
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight)
322 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
326 upForce.Z = (terrainHeight - Position.Z) * 1f;
327 ret = true;
328 }
329
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f)
335 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f;
338 ret = true;
339 }
340 }
341
342 // TODO: check for out of bounds
343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
345 if (ret)
346 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
348 {
349 // Apply upforce and overcome gravity.
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
351 });
352 }
353 return ret;
306 } 354 }
307 355
308 // Return the effective mass of the object. 356 // Return the effective mass of the object.
309 // If there are multiple items in the linkset, add them together for the root 357 // If there are multiple items in the linkset, add them together for the root
310 public override float Mass 358 public override float Mass
311 { 359 {
312 get 360 get
313 { 361 {
314 return _linkset.LinksetMass; 362 return Linkset.LinksetMass;
363 // return _mass;
315 } 364 }
316 } 365 }
317 366
318 // used when we only want this prim's mass and not the linkset thing 367 // used when we only want this prim's mass and not the linkset thing
319 public float MassRaw { get { return _mass; } } 368 public override float RawMass {
369 get { return _mass; }
370 }
371 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass)
374 {
375 if (IsStatic)
376 {
377 Inertia = OMV.Vector3.Zero;
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
380 }
381 else
382 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
386 // center of mass is at the zero of the object
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
389 }
390 }
320 391
321 // Is this used? 392 // Is this used?
322 public override OMV.Vector3 CenterOfMass 393 public override OMV.Vector3 CenterOfMass
323 { 394 {
324 get { return _linkset.CenterOfMass; } 395 get { return Linkset.CenterOfMass; }
325 } 396 }
326 397
327 // Is this used? 398 // Is this used?
328 public override OMV.Vector3 GeometricCenter 399 public override OMV.Vector3 GeometricCenter
329 { 400 {
330 get { return _linkset.GeometricCenter; } 401 get { return Linkset.GeometricCenter; }
331 } 402 }
332 403
333 public override OMV.Vector3 Force { 404 public override OMV.Vector3 Force {
334 get { return _force; } 405 get { return _force; }
335 set { 406 set {
336 _force = value; 407 _force = value;
337 _scene.TaintedObject("BSPrim.setForce", delegate() 408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
338 { 409 {
339 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
340 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); 411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
341 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
342 }); 412 });
343 } 413 }
344 } 414 }
345 415
346 public override int VehicleType { 416 public override int VehicleType {
347 get { 417 get {
348 return (int)_vehicle.Type; // if we are a vehicle, return that type 418 return (int)_vehicle.Type; // if we are a vehicle, return that type
349 } 419 }
350 set { 420 set {
351 Vehicle type = (Vehicle)value; 421 Vehicle type = (Vehicle)value;
352 BSPrim vehiclePrim = this; 422
353 _scene.TaintedObject("setVehicleType", delegate() 423 // Tell the scene about the vehicle so it will get processing each frame.
424 PhysicsScene.VehicleInSceneTypeChanged(this, type);
425
426 PhysicsScene.TaintedObject("setVehicleType", delegate()
354 { 427 {
355 // Done at taint time so we're sure the physics engine is not using the variables 428 // Done at taint time so we're sure the physics engine is not using the variables
356 // Vehicle code changes the parameters for this vehicle type. 429 // Vehicle code changes the parameters for this vehicle type.
357 _vehicle.ProcessTypeChange(type); 430 _vehicle.ProcessTypeChange(type);
358 // Tell the scene about the vehicle so it will get processing each frame. 431 ActivateIfPhysical(false);
359 _scene.VehicleInSceneTypeChanged(this, type);
360 }); 432 });
361 } 433 }
362 } 434 }
363 public override void VehicleFloatParam(int param, float value) 435 public override void VehicleFloatParam(int param, float value)
364 { 436 {
365 _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate() 437 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
366 { 438 {
367 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 439 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
440 ActivateIfPhysical(false);
368 }); 441 });
369 } 442 }
370 public override void VehicleVectorParam(int param, OMV.Vector3 value) 443 public override void VehicleVectorParam(int param, OMV.Vector3 value)
371 { 444 {
372 _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate() 445 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
373 { 446 {
374 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); 447 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
448 ActivateIfPhysical(false);
375 }); 449 });
376 } 450 }
377 public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 451 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
378 { 452 {
379 _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate() 453 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
380 { 454 {
381 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); 455 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
456 ActivateIfPhysical(false);
382 }); 457 });
383 } 458 }
384 public override void VehicleFlags(int param, bool remove) 459 public override void VehicleFlags(int param, bool remove)
385 { 460 {
386 _scene.TaintedObject("BSPrim.VehicleFlags", delegate() 461 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
387 { 462 {
388 _vehicle.ProcessVehicleFlags(param, remove); 463 _vehicle.ProcessVehicleFlags(param, remove);
389 }); 464 });
@@ -391,143 +466,356 @@ public sealed class BSPrim : PhysicsActor
391 466
392 // Called each simulation step to advance vehicle characteristics. 467 // Called each simulation step to advance vehicle characteristics.
393 // Called from Scene when doing simulation step so we're in taint processing time. 468 // Called from Scene when doing simulation step so we're in taint processing time.
394 public void StepVehicle(float timeStep) 469 public override void StepVehicle(float timeStep)
395 { 470 {
396 if (IsPhysical) 471 if (IsPhysical && _vehicle.IsActive)
472 {
397 _vehicle.Step(timeStep); 473 _vehicle.Step(timeStep);
474 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
475 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
476 {
477 // This resets the interpolation values and recomputes the tensor variables
478 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
479 });
480 */
481 }
398 } 482 }
399 483
400 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 484 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
401 public override void SetVolumeDetect(int param) { 485 public override void SetVolumeDetect(int param) {
402 bool newValue = (param != 0); 486 bool newValue = (param != 0);
403 _isVolumeDetect = newValue; 487 if (_isVolumeDetect != newValue)
404 _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
405 { 488 {
406 SetObjectDynamic(); 489 _isVolumeDetect = newValue;
407 }); 490 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
408 return; 491 {
492 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
493 SetObjectDynamic(true);
494 });
495 }
496 return;
409 } 497 }
410 498 public override OMV.Vector3 Velocity {
411 public override OMV.Vector3 Velocity { 499 get { return _velocity; }
412 get { return _velocity; }
413 set { 500 set {
414 _velocity = value; 501 _velocity = value;
415 _scene.TaintedObject("BSPrim.setVelocity", delegate() 502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
416 { 503 {
417 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
418 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); 505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
419 }); 506 });
420 } 507 }
508 }
509 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; }
511 set {
512 _velocity = value;
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
514 }
421 } 515 }
422 public override OMV.Vector3 Torque { 516 public override OMV.Vector3 Torque {
423 get { return _torque; } 517 get { return _torque; }
424 set { _torque = value; 518 set {
519 _torque = value;
520 AddAngularForce(_torque, false, false);
425 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
426 } 522 }
427 } 523 }
428 public override float CollisionScore { 524 public override float CollisionScore {
429 get { return _collisionScore; } 525 get { return _collisionScore; }
430 set { _collisionScore = value; 526 set { _collisionScore = value;
431 } 527 }
432 } 528 }
433 public override OMV.Vector3 Acceleration { 529 public override OMV.Vector3 Acceleration {
434 get { return _acceleration; } 530 get { return _acceleration; }
435 set { _acceleration = value; } 531 set { _acceleration = value; }
436 } 532 }
437 public override OMV.Quaternion Orientation { 533 public override OMV.Quaternion RawOrientation
534 {
535 get { return _orientation; }
536 set { _orientation = value; }
537 }
538 public override OMV.Quaternion Orientation {
438 get { 539 get {
439 if (!_linkset.IsRoot(this)) 540 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this))
440 { 542 {
441 // Children move around because tied to parent. Get a fresh value. 543 _orientation = Linkset.Orientation(this);
442 _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID);
443 } 544 }
444 return _orientation; 545 return _orientation;
445 } 546 }
446 set { 547 set {
548 if (_orientation == value)
549 return;
447 _orientation = value; 550 _orientation = value;
448 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
449 _scene.TaintedObject("BSPrim.setOrientation", delegate() 552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
450 { 553 {
451 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); 554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
452 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
453 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); 556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
454 }); 557 });
455 } 558 }
559 }
560 // Go directly to Bullet to get/set the value.
561 public override OMV.Quaternion ForceOrientation
562 {
563 get
564 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
566 return _orientation;
567 }
568 set
569 {
570 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
572 }
456 } 573 }
457 public override int PhysicsActorType { 574 public override int PhysicsActorType {
458 get { return _physicsActorType; } 575 get { return _physicsActorType; }
459 set { _physicsActorType = value; 576 set { _physicsActorType = value; }
460 }
461 } 577 }
462 public override bool IsPhysical { 578 public override bool IsPhysical {
463 get { return _isPhysical; } 579 get { return _isPhysical; }
464 set { 580 set {
465 _isPhysical = value; 581 if (_isPhysical != value)
466 _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
467 { 582 {
468 SetObjectDynamic(); 583 _isPhysical = value;
469 }); 584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
470 } 585 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true);
590 });
591 }
592 }
471 } 593 }
472 594
473 // An object is static (does not move) if selected or not physical 595 // An object is static (does not move) if selected or not physical
474 private bool IsStatic 596 public override bool IsStatic
475 { 597 {
476 get { return _isSelected || !IsPhysical; } 598 get { return _isSelected || !IsPhysical; }
477 } 599 }
478 600
479 // An object is solid if it's not phantom and if it's not doing VolumeDetect 601 // An object is solid if it's not phantom and if it's not doing VolumeDetect
480 private bool IsSolid 602 public override bool IsSolid
481 { 603 {
482 get { return !IsPhantom && !_isVolumeDetect; } 604 get { return !IsPhantom && !_isVolumeDetect; }
483 } 605 }
484 606
485 // Make gravity work if the object is physical and not selected 607 // Make gravity work if the object is physical and not selected
486 // No locking here because only called when it is safe 608 // Called at taint-time!!
487 private void SetObjectDynamic() 609 private void SetObjectDynamic(bool forceRebuild)
610 {
611 // Recreate the physical object if necessary
612 CreateGeomAndObject(forceRebuild);
613 }
614
615 // Convert the simulator's physical properties into settings on BulletSim objects.
616 // There are four flags we're interested in:
617 // IsStatic: Object does not move, otherwise the object has mass and moves
618 // isSolid: other objects bounce off of this object
619 // isVolumeDetect: other objects pass through but can generate collisions
620 // collisionEvents: whether this object returns collision events
621 private void UpdatePhysicalParameters()
488 { 622 {
489 // RA: remove this for the moment. 623 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
490 // The problem is that dynamic objects are hulls so if we are becoming physical 624
491 // the shape has to be checked and possibly built. 625 // Mangling all the physical properties requires the object not be in the physical world.
492 // Maybe a VerifyCorrectPhysicalShape() routine? 626 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
493 // RecreateGeomAndObject(); 627 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
628
629 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic);
631
632 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
633 _vehicle.Refresh();
494 634
495 // Bullet wants static objects to have a mass of zero 635 // Arrange for collision events if the simulator wants them
496 float mass = IsStatic ? 0f : _mass; 636 EnableCollisions(SubscribedEvents());
497 637
498 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); 638 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid);
499 640
500 // recompute any linkset parameters 641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
501 _linkset.Refresh(this);
502 642
503 CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr); 643 // Rebuild its shape
504 // DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf); 644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
645
646 // Collision filter can be set only when the object is in the world
647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
648 {
649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
650 }
651
652 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that
654 // had been automatically disabled when the mass was set to zero.
655 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this);
657
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
659 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
660 }
661
662 // "Making dynamic" means changing to and from static.
663 // When static, gravity does not effect the object and it is fixed in space.
664 // When dynamic, the object can fall and be pushed by others.
665 // This is independent of its 'solidness' which controls what passes through
666 // this object and what interacts with it.
667 private void MakeDynamic(bool makeStatic)
668 {
669 if (makeStatic)
670 {
671 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement
674 ZeroMotion(true);
675 // Center of mass is at the center of the object
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
677 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f);
679 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
681 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
684 }
685 // There can be special things needed for implementing linksets
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
691
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
694 }
695 else
696 {
697 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
699
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution);
703
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
705 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
707
708 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
710
711 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
713
714 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass);
716
717 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f)
719 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
722 }
723
724 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
729
730 // There might be special things needed for implementing linksets.
731 Linkset.MakeDynamic(this);
732
733 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask;
740 }
741 }
742
743 // "Making solid" means that other object will not pass through this object.
744 // To make transparent, we create a Bullet ghost object.
745 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
746 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid)
748 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
750 if (makeSolid)
751 {
752 // Verify the previous code created the correct shape for this type of thing.
753 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
754 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 }
759 else
760 {
761 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
762 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
768 }
769 }
770
771 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
772 // they need waking up when parameters are changed.
773 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt)
775 {
776 if (IsPhysical)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
778 }
779
780 // Turn on or off the flag controlling whether collision events are returned to the simulator.
781 private void EnableCollisions(bool wantsCollisionEvents)
782 {
783 if (wantsCollisionEvents)
784 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
786 }
787 else
788 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
790 }
505 } 791 }
506 792
507 // prims don't fly 793 // prims don't fly
508 public override bool Flying { 794 public override bool Flying {
509 get { return _flying; } 795 get { return _flying; }
510 set { _flying = value; } 796 set {
797 _flying = value;
798 }
511 } 799 }
512 public override bool SetAlwaysRun { 800 public override bool SetAlwaysRun {
513 get { return _setAlwaysRun; } 801 get { return _setAlwaysRun; }
514 set { _setAlwaysRun = value; } 802 set { _setAlwaysRun = value; }
515 } 803 }
516 public override bool ThrottleUpdates { 804 public override bool ThrottleUpdates {
517 get { return _throttleUpdates; } 805 get { return _throttleUpdates; }
518 set { _throttleUpdates = value; } 806 set { _throttleUpdates = value; }
519 } 807 }
520 public override bool IsColliding { 808 public override bool IsColliding {
521 get { return (_collidingStep == _scene.SimulationStep); } 809 get { return (CollidingStep == PhysicsScene.SimulationStep); }
522 set { _isColliding = value; } 810 set { _isColliding = value; }
523 } 811 }
524 public override bool CollidingGround { 812 public override bool CollidingGround {
525 get { return (_collidingGroundStep == _scene.SimulationStep); } 813 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
526 set { _collidingGround = value; } 814 set { _collidingGround = value; }
527 } 815 }
528 public override bool CollidingObj { 816 public override bool CollidingObj {
529 get { return _collidingObj; } 817 get { return _collidingObj; }
530 set { _collidingObj = value; } 818 set { _collidingObj = value; }
531 } 819 }
532 public bool IsPhantom { 820 public bool IsPhantom {
533 get { 821 get {
@@ -537,10 +825,19 @@ public sealed class BSPrim : PhysicsActor
537 return false; 825 return false;
538 } 826 }
539 } 827 }
540 public override bool FloatOnWater { 828 public override bool FloatOnWater {
541 set { _floatOnWater = value; } 829 set {
830 _floatOnWater = value;
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 {
833 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
835 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
837 });
838 }
542 } 839 }
543 public override OMV.Vector3 RotationalVelocity { 840 public override OMV.Vector3 RotationalVelocity {
544 get { 841 get {
545 /* 842 /*
546 OMV.Vector3 pv = OMV.Vector3.Zero; 843 OMV.Vector3 pv = OMV.Vector3.Zero;
@@ -552,58 +849,76 @@ public sealed class BSPrim : PhysicsActor
552 */ 849 */
553 850
554 return _rotationalVelocity; 851 return _rotationalVelocity;
555 } 852 }
556 set { 853 set {
557 _rotationalVelocity = value; 854 _rotationalVelocity = value;
558 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); 855 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
559 _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
560 { 857 {
561 // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
562 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); 859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
563 }); 860 });
564 } 861 }
565 } 862 }
566 public override bool Kinematic { 863 public override OMV.Vector3 ForceRotationalVelocity {
567 get { return _kinematic; } 864 get {
568 set { _kinematic = value; 865 return _rotationalVelocity;
866 }
867 set {
868 _rotationalVelocity = value;
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
870 }
871 }
872 public override bool Kinematic {
873 get { return _kinematic; }
874 set { _kinematic = value;
569 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); 875 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
570 } 876 }
571 } 877 }
572 public override float Buoyancy { 878 public override float Buoyancy {
573 get { return _buoyancy; } 879 get { return _buoyancy; }
574 set { 880 set {
575 _buoyancy = value; 881 _buoyancy = value;
576 _scene.TaintedObject("BSPrim.setBuoyancy", delegate() 882 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
577 { 883 {
578 // DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 884 ForceBuoyancy = _buoyancy;
579 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
580 }); 885 });
581 } 886 }
887 }
888 public override float ForceBuoyancy {
889 get { return _buoyancy; }
890 set {
891 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
896 }
582 } 897 }
583 898
584 // Used for MoveTo 899 // Used for MoveTo
585 public override OMV.Vector3 PIDTarget { 900 public override OMV.Vector3 PIDTarget {
586 set { _PIDTarget = value; } 901 set { _PIDTarget = value; }
587 } 902 }
588 public override bool PIDActive { 903 public override bool PIDActive {
589 set { _usePID = value; } 904 set { _usePID = value; }
590 } 905 }
591 public override float PIDTau { 906 public override float PIDTau {
592 set { _PIDTau = value; } 907 set { _PIDTau = value; }
593 } 908 }
594 909
595 // Used for llSetHoverHeight and maybe vehicle height 910 // Used for llSetHoverHeight and maybe vehicle height
596 // Hover Height will override MoveTo target's Z 911 // Hover Height will override MoveTo target's Z
597 public override bool PIDHoverActive { 912 public override bool PIDHoverActive {
598 set { _useHoverPID = value; } 913 set { _useHoverPID = value; }
599 } 914 }
600 public override float PIDHoverHeight { 915 public override float PIDHoverHeight {
601 set { _PIDHoverHeight = value; } 916 set { _PIDHoverHeight = value; }
602 } 917 }
603 public override PIDHoverType PIDHoverType { 918 public override PIDHoverType PIDHoverType {
604 set { _PIDHoverType = value; } 919 set { _PIDHoverType = value; }
605 } 920 }
606 public override float PIDHoverTau { 921 public override float PIDHoverTau {
607 set { _PIDHoverTao = value; } 922 set { _PIDHoverTao = value; }
608 } 923 }
609 924
@@ -615,6 +930,10 @@ public sealed class BSPrim : PhysicsActor
615 930
616 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); 931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
617 public override void AddForce(OMV.Vector3 force, bool pushforce) { 932 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false);
934 }
935 // Applying a force just adds this to the total force on the object.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
618 // for an object, doesn't matter if force is a pushforce or not 937 // for an object, doesn't matter if force is a pushforce or not
619 if (force.IsFinite()) 938 if (force.IsFinite())
620 { 939 {
@@ -624,56 +943,88 @@ public sealed class BSPrim : PhysicsActor
624 } 943 }
625 else 944 else
626 { 945 {
627 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); 946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
628 return; 947 return;
629 } 948 }
630 _scene.TaintedObject("BSPrim.AddForce", delegate() 949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
631 { 950 {
632 OMV.Vector3 fSum = OMV.Vector3.Zero; 951 OMV.Vector3 fSum = OMV.Vector3.Zero;
633 lock (m_accumulatedForces) 952 lock (m_accumulatedForces)
634 { 953 {
954 // Sum the accumulated additional forces for one big force to apply once.
635 foreach (OMV.Vector3 v in m_accumulatedForces) 955 foreach (OMV.Vector3 v in m_accumulatedForces)
636 { 956 {
637 fSum += v; 957 fSum += v;
638 } 958 }
639 m_accumulatedForces.Clear(); 959 m_accumulatedForces.Clear();
640 } 960 }
641 // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force); 961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
642 BulletSimAPI.AddObjectForce2(Body.Ptr, fSum); 962 if (fSum != OMV.Vector3.Zero)
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
643 }); 964 });
644 } 965 }
645 966
646 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 967 // An impulse force is scaled by the mass of the object.
647 // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); 968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
648 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); 969 {
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
975 });
649 } 976 }
650 public override void SetMomentum(OMV.Vector3 momentum) { 977
651 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum); 978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false);
652 } 981 }
653 public override void SubscribeEvents(int ms) { 982 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
654 _subscribedEventsMs = ms; 983 {
655 if (ms > 0) 984 if (force.IsFinite())
656 { 985 {
657 // make sure first collision happens 986 // _force += force;
658 _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; 987 lock (m_accumulatedAngularForces)
659 988 m_accumulatedAngularForces.Add(new OMV.Vector3(force));
660 Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
661 {
662 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
663 });
664 } 989 }
665 } 990 else
666 public override void UnSubscribeEvents() { 991 {
667 _subscribedEventsMs = 0; 992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
668 Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate() 993 return;
994 }
995 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
669 { 996 {
670 BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 997 OMV.Vector3 fSum = OMV.Vector3.Zero;
998 lock (m_accumulatedAngularForces)
999 {
1000 // Sum the accumulated additional forces for one big force to apply once.
1001 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
1002 {
1003 fSum += v;
1004 }
1005 m_accumulatedAngularForces.Clear();
1006 }
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero)
1009 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum;
1012 }
671 }); 1013 });
672 } 1014 }
673 public override bool SubscribedEvents() { 1015 // A torque impulse.
674 return (_subscribedEventsMs > 0); 1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 {
1018 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1022 });
675 } 1023 }
676 1024
1025 public override void SetMomentum(OMV.Vector3 momentum) {
1026 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1027 }
677 #region Mass Calculation 1028 #region Mass Calculation
678 1029
679 private float CalculateMass() 1030 private float CalculateMass()
@@ -682,19 +1033,19 @@ public sealed class BSPrim : PhysicsActor
682 float tmp; 1033 float tmp;
683 1034
684 float returnMass = 0; 1035 float returnMass = 0;
685 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f; 1036 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
686 float hollowVolume = hollowAmount * hollowAmount; 1037 float hollowVolume = hollowAmount * hollowAmount;
687 1038
688 switch (_pbs.ProfileShape) 1039 switch (BaseShape.ProfileShape)
689 { 1040 {
690 case ProfileShape.Square: 1041 case ProfileShape.Square:
691 // default box 1042 // default box
692 1043
693 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1044 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
694 { 1045 {
695 if (hollowAmount > 0.0) 1046 if (hollowAmount > 0.0)
696 { 1047 {
697 switch (_pbs.HollowShape) 1048 switch (BaseShape.HollowShape)
698 { 1049 {
699 case HollowShape.Square: 1050 case HollowShape.Square:
700 case HollowShape.Same: 1051 case HollowShape.Same:
@@ -718,19 +1069,19 @@ public sealed class BSPrim : PhysicsActor
718 } 1069 }
719 } 1070 }
720 1071
721 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1072 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
722 { 1073 {
723 //a tube 1074 //a tube
724 1075
725 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX); 1076 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
726 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY); 1077 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
727 volume -= volume*tmp*tmp; 1078 volume -= volume*tmp*tmp;
728 1079
729 if (hollowAmount > 0.0) 1080 if (hollowAmount > 0.0)
730 { 1081 {
731 hollowVolume *= hollowAmount; 1082 hollowVolume *= hollowAmount;
732 1083
733 switch (_pbs.HollowShape) 1084 switch (BaseShape.HollowShape)
734 { 1085 {
735 case HollowShape.Square: 1086 case HollowShape.Square:
736 case HollowShape.Same: 1087 case HollowShape.Same:
@@ -755,13 +1106,13 @@ public sealed class BSPrim : PhysicsActor
755 1106
756 case ProfileShape.Circle: 1107 case ProfileShape.Circle:
757 1108
758 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1109 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
759 { 1110 {
760 volume *= 0.78539816339f; // elipse base 1111 volume *= 0.78539816339f; // elipse base
761 1112
762 if (hollowAmount > 0.0) 1113 if (hollowAmount > 0.0)
763 { 1114 {
764 switch (_pbs.HollowShape) 1115 switch (BaseShape.HollowShape)
765 { 1116 {
766 case HollowShape.Same: 1117 case HollowShape.Same:
767 case HollowShape.Circle: 1118 case HollowShape.Circle:
@@ -783,19 +1134,19 @@ public sealed class BSPrim : PhysicsActor
783 } 1134 }
784 } 1135 }
785 1136
786 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1137 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
787 { 1138 {
788 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX); 1139 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
789 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1140 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
790 volume *= (1.0f - tmp * tmp); 1141 volume *= (1.0f - tmp * tmp);
791 1142
792 if (hollowAmount > 0.0) 1143 if (hollowAmount > 0.0)
793 { 1144 {
794 1145
795 // calculate the hollow volume by it's shape compared to the prim shape 1146 // calculate the hollow volume by it's shape compared to the prim shape
796 hollowVolume *= hollowAmount; 1147 hollowVolume *= hollowAmount;
797 1148
798 switch (_pbs.HollowShape) 1149 switch (BaseShape.HollowShape)
799 { 1150 {
800 case HollowShape.Same: 1151 case HollowShape.Same:
801 case HollowShape.Circle: 1152 case HollowShape.Circle:
@@ -819,7 +1170,7 @@ public sealed class BSPrim : PhysicsActor
819 break; 1170 break;
820 1171
821 case ProfileShape.HalfCircle: 1172 case ProfileShape.HalfCircle:
822 if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1173 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
823 { 1174 {
824 volume *= 0.52359877559829887307710723054658f; 1175 volume *= 0.52359877559829887307710723054658f;
825 } 1176 }
@@ -827,7 +1178,7 @@ public sealed class BSPrim : PhysicsActor
827 1178
828 case ProfileShape.EquilateralTriangle: 1179 case ProfileShape.EquilateralTriangle:
829 1180
830 if (_pbs.PathCurve == (byte)Extrusion.Straight) 1181 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
831 { 1182 {
832 volume *= 0.32475953f; 1183 volume *= 0.32475953f;
833 1184
@@ -835,7 +1186,7 @@ public sealed class BSPrim : PhysicsActor
835 { 1186 {
836 1187
837 // calculate the hollow volume by it's shape compared to the prim shape 1188 // calculate the hollow volume by it's shape compared to the prim shape
838 switch (_pbs.HollowShape) 1189 switch (BaseShape.HollowShape)
839 { 1190 {
840 case HollowShape.Same: 1191 case HollowShape.Same:
841 case HollowShape.Triangle: 1192 case HollowShape.Triangle:
@@ -860,11 +1211,11 @@ public sealed class BSPrim : PhysicsActor
860 volume *= (1.0f - hollowVolume); 1211 volume *= (1.0f - hollowVolume);
861 } 1212 }
862 } 1213 }
863 else if (_pbs.PathCurve == (byte)Extrusion.Curve1) 1214 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
864 { 1215 {
865 volume *= 0.32475953f; 1216 volume *= 0.32475953f;
866 volume *= 0.01f * (float)(200 - _pbs.PathScaleX); 1217 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
867 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY); 1218 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
868 volume *= (1.0f - tmp * tmp); 1219 volume *= (1.0f - tmp * tmp);
869 1220
870 if (hollowAmount > 0.0) 1221 if (hollowAmount > 0.0)
@@ -872,7 +1223,7 @@ public sealed class BSPrim : PhysicsActor
872 1223
873 hollowVolume *= hollowAmount; 1224 hollowVolume *= hollowAmount;
874 1225
875 switch (_pbs.HollowShape) 1226 switch (BaseShape.HollowShape)
876 { 1227 {
877 case HollowShape.Same: 1228 case HollowShape.Same:
878 case HollowShape.Triangle: 1229 case HollowShape.Triangle:
@@ -912,26 +1263,26 @@ public sealed class BSPrim : PhysicsActor
912 float profileBegin; 1263 float profileBegin;
913 float profileEnd; 1264 float profileEnd;
914 1265
915 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible) 1266 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
916 { 1267 {
917 taperX1 = _pbs.PathScaleX * 0.01f; 1268 taperX1 = BaseShape.PathScaleX * 0.01f;
918 if (taperX1 > 1.0f) 1269 if (taperX1 > 1.0f)
919 taperX1 = 2.0f - taperX1; 1270 taperX1 = 2.0f - taperX1;
920 taperX = 1.0f - taperX1; 1271 taperX = 1.0f - taperX1;
921 1272
922 taperY1 = _pbs.PathScaleY * 0.01f; 1273 taperY1 = BaseShape.PathScaleY * 0.01f;
923 if (taperY1 > 1.0f) 1274 if (taperY1 > 1.0f)
924 taperY1 = 2.0f - taperY1; 1275 taperY1 = 2.0f - taperY1;
925 taperY = 1.0f - taperY1; 1276 taperY = 1.0f - taperY1;
926 } 1277 }
927 else 1278 else
928 { 1279 {
929 taperX = _pbs.PathTaperX * 0.01f; 1280 taperX = BaseShape.PathTaperX * 0.01f;
930 if (taperX < 0.0f) 1281 if (taperX < 0.0f)
931 taperX = -taperX; 1282 taperX = -taperX;
932 taperX1 = 1.0f - taperX; 1283 taperX1 = 1.0f - taperX;
933 1284
934 taperY = _pbs.PathTaperY * 0.01f; 1285 taperY = BaseShape.PathTaperY * 0.01f;
935 if (taperY < 0.0f) 1286 if (taperY < 0.0f)
936 taperY = -taperY; 1287 taperY = -taperY;
937 taperY1 = 1.0f - taperY; 1288 taperY1 = 1.0f - taperY;
@@ -941,20 +1292,18 @@ public sealed class BSPrim : PhysicsActor
941 1292
942 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); 1293 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
943 1294
944 pathBegin = (float)_pbs.PathBegin * 2.0e-5f; 1295 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
945 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f; 1296 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
946 volume *= (pathEnd - pathBegin); 1297 volume *= (pathEnd - pathBegin);
947 1298
948 // this is crude aproximation 1299 // this is crude aproximation
949 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f; 1300 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
950 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f; 1301 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
951 volume *= (profileEnd - profileBegin); 1302 volume *= (profileEnd - profileBegin);
952 1303
953 returnMass = _density * volume; 1304 returnMass = _density * volume;
954 1305
955 /* 1306 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
956 * This change means each object keeps its own mass and the Mass property
957 * will return the sum if we're part of a linkset.
958 if (IsRootOfLinkset) 1307 if (IsRootOfLinkset)
959 { 1308 {
960 foreach (BSPrim prim in _childrenPrims) 1309 foreach (BSPrim prim in _childrenPrims)
@@ -967,296 +1316,49 @@ public sealed class BSPrim : PhysicsActor
967 if (returnMass <= 0) 1316 if (returnMass <= 0)
968 returnMass = 0.0001f; 1317 returnMass = 0.0001f;
969 1318
970 if (returnMass > _scene.MaximumObjectMass) 1319 if (returnMass > PhysicsScene.MaximumObjectMass)
971 returnMass = _scene.MaximumObjectMass; 1320 returnMass = PhysicsScene.MaximumObjectMass;
972 1321
973 return returnMass; 1322 return returnMass;
974 }// end CalculateMass 1323 }// end CalculateMass
975 #endregion Mass Calculation 1324 #endregion Mass Calculation
976 1325
977 // Create the geometry information in Bullet for later use 1326 // Rebuild the geometry and object.
978 // The objects needs a hull if it's physical otherwise a mesh is enough 1327 // This is called when the shape changes so we need to recreate the mesh/hull.
979 // No locking here because this is done when we know physics is not simulating 1328 // Called at taint-time!!!
980 // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used 1329 private void CreateGeomAndObject(bool forceRebuild)
981 // Returns 'true' if the geometry was rebuilt
982 private bool CreateGeom(bool forceRebuild)
983 {
984 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
985 bool ret = false;
986 if (!_scene.NeedsMeshing(_pbs))
987 {
988 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
989 {
990 // if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
991 // {
992 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
993 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
994 {
995 // DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
996 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
997 // Bullet native objects are scaled by the Bullet engine so pass the size in
998 _scale = _size;
999 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1000 ret = true;
1001 }
1002 // }
1003 }
1004 else
1005 {
1006 // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size);
1007 if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX))
1008 {
1009 // DetailLog("{0},BSPrim.CreateGeom,box (force={1})", LocalID, forceRebuild);
1010 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
1011 _scale = _size;
1012 // TODO: do we need to check for and destroy a mesh or hull that might have been left from before?
1013 ret = true;
1014 }
1015 }
1016 }
1017 else
1018 {
1019 if (IsPhysical)
1020 {
1021 if (forceRebuild || _hullKey == 0)
1022 {
1023 // physical objects require a hull for interaction.
1024 // This will create the mesh if it doesn't already exist
1025 CreateGeomHull();
1026 ret = true;
1027 }
1028 }
1029 else
1030 {
1031 if (forceRebuild || _meshKey == 0)
1032 {
1033 // Static (non-physical) objects only need a mesh for bumping into
1034 CreateGeomMesh();
1035 ret = true;
1036 }
1037 }
1038 }
1039 return ret;
1040 }
1041
1042 // No locking here because this is done when we know physics is not simulating
1043 private void CreateGeomMesh()
1044 {
1045 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD;
1046 ulong newMeshKey = (ulong)_pbs.GetMeshKey(_size, lod);
1047 // m_log.DebugFormat("{0}: CreateGeomMesh: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _meshKey, newMeshKey);
1048
1049 // if this new shape is the same as last time, don't recreate the mesh
1050 if (_meshKey == newMeshKey) return;
1051
1052 // DetailLog("{0},BSPrim.CreateGeomMesh,create,key={1}", LocalID, newMeshKey);
1053 // Since we're recreating new, get rid of any previously generated shape
1054 if (_meshKey != 0)
1055 {
1056 // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey);
1057 // DetailLog("{0},BSPrim.CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey);
1058 BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey);
1059 _mesh = null;
1060 _meshKey = 0;
1061 }
1062
1063 _meshKey = newMeshKey;
1064 // always pass false for physicalness as this creates some sort of bounding box which we don't need
1065 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, lod, false);
1066
1067 int[] indices = _mesh.getIndexListAsInt();
1068 List<OMV.Vector3> vertices = _mesh.getVertexList();
1069
1070 float[] verticesAsFloats = new float[vertices.Count * 3];
1071 int vi = 0;
1072 foreach (OMV.Vector3 vv in vertices)
1073 {
1074 verticesAsFloats[vi++] = vv.X;
1075 verticesAsFloats[vi++] = vv.Y;
1076 verticesAsFloats[vi++] = vv.Z;
1077 }
1078
1079 // m_log.DebugFormat("{0}: CreateGeomMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
1080 // LogHeader, _localID, _meshKey, indices.Length, vertices.Count);
1081 BulletSimAPI.CreateMesh(_scene.WorldID, _meshKey, indices.GetLength(0), indices,
1082 vertices.Count, verticesAsFloats);
1083
1084 _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH;
1085 // meshes are already scaled by the meshmerizer
1086 _scale = new OMV.Vector3(1f, 1f, 1f);
1087 // DetailLog("{0},BSPrim.CreateGeomMesh,done", LocalID);
1088 return;
1089 }
1090
1091 // No locking here because this is done when we know physics is not simulating
1092 private void CreateGeomHull()
1093 { 1330 {
1094 float lod = _pbs.SculptEntry ? _scene.SculptLOD : _scene.MeshLOD; 1331 // If this prim is part of a linkset, we must remove and restore the physical
1095 ulong newHullKey = (ulong)_pbs.GetMeshKey(_size, lod); 1332 // links if the body is rebuilt.
1096 // m_log.DebugFormat("{0}: CreateGeomHull: lID={1}, oldKey={2}, newKey={3}", LogHeader, _localID, _hullKey, newHullKey); 1333 bool needToRestoreLinkset = false;
1097 1334 bool needToRestoreVehicle = false;
1098 // if the hull hasn't changed, don't rebuild it 1335
1099 if (newHullKey == _hullKey) return; 1336 // Create the correct physical representation for this type of object.
1100 1337 // Updates PhysBody and PhysShape with the new information.
1101 // DetailLog("{0},BSPrim.CreateGeomHull,create,oldKey={1},newKey={2}", LocalID, _hullKey, newHullKey); 1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1102 1339 // Returns 'true' if either the body or the shape was changed.
1103 // Since we're recreating new, get rid of any previously generated shape 1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1104 if (_hullKey != 0)
1105 {
1106 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
1107 // DetailLog("{0},BSPrim.CreateGeomHull,deleteOldHull,key={1}", LocalID, _hullKey);
1108 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1109 _hullKey = 0;
1110 }
1111
1112 _hullKey = newHullKey;
1113
1114 // Make sure the underlying mesh exists and is correct
1115 CreateGeomMesh();
1116
1117 int[] indices = _mesh.getIndexListAsInt();
1118 List<OMV.Vector3> vertices = _mesh.getVertexList();
1119
1120 //format conversion from IMesh format to DecompDesc format
1121 List<int> convIndices = new List<int>();
1122 List<float3> convVertices = new List<float3>();
1123 for (int ii = 0; ii < indices.GetLength(0); ii++)
1124 {
1125 convIndices.Add(indices[ii]);
1126 }
1127 foreach (OMV.Vector3 vv in vertices)
1128 { 1341 {
1129 convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); 1342 // Called if the current prim body is about to be destroyed.
1130 } 1343 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 });
1131 1348
1132 // setup and do convex hull conversion 1349 if (needToRestoreLinkset)
1133 _hulls = new List<ConvexResult>();
1134 DecompDesc dcomp = new DecompDesc();
1135 dcomp.mIndices = convIndices;
1136 dcomp.mVertices = convVertices;
1137 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
1138 // create the hull into the _hulls variable
1139 convexBuilder.process(dcomp);
1140
1141 // Convert the vertices and indices for passing to unmanaged.
1142 // The hull information is passed as a large floating point array.
1143 // The format is:
1144 // convHulls[0] = number of hulls
1145 // convHulls[1] = number of vertices in first hull
1146 // convHulls[2] = hull centroid X coordinate
1147 // convHulls[3] = hull centroid Y coordinate
1148 // convHulls[4] = hull centroid Z coordinate
1149 // convHulls[5] = first hull vertex X
1150 // convHulls[6] = first hull vertex Y
1151 // convHulls[7] = first hull vertex Z
1152 // convHulls[8] = second hull vertex X
1153 // ...
1154 // convHulls[n] = number of vertices in second hull
1155 // convHulls[n+1] = second hull centroid X coordinate
1156 // ...
1157 //
1158 // TODO: is is very inefficient. Someday change the convex hull generator to return
1159 // data structures that do not need to be converted in order to pass to Bullet.
1160 // And maybe put the values directly into pinned memory rather than marshaling.
1161 int hullCount = _hulls.Count;
1162 int totalVertices = 1; // include one for the count of the hulls
1163 foreach (ConvexResult cr in _hulls)
1164 { 1350 {
1165 totalVertices += 4; // add four for the vertex count and centroid 1351 // If physical body dependencies were removed, restore them
1166 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles 1352 Linkset.RestoreBodyDependencies(this);
1167 } 1353 }
1168 float[] convHulls = new float[totalVertices]; 1354 if (needToRestoreVehicle)
1169
1170 convHulls[0] = (float)hullCount;
1171 int jj = 1;
1172 foreach (ConvexResult cr in _hulls)
1173 { 1355 {
1174 // copy vertices for index access 1356 // If physical body dependencies were removed, restore them
1175 float3[] verts = new float3[cr.HullVertices.Count]; 1357 _vehicle.RestoreBodyDependencies(this);
1176 int kk = 0;
1177 foreach (float3 ff in cr.HullVertices)
1178 {
1179 verts[kk++] = ff;
1180 }
1181
1182 // add to the array one hull's worth of data
1183 convHulls[jj++] = cr.HullIndices.Count;
1184 convHulls[jj++] = 0f; // centroid x,y,z
1185 convHulls[jj++] = 0f;
1186 convHulls[jj++] = 0f;
1187 foreach (int ind in cr.HullIndices)
1188 {
1189 convHulls[jj++] = verts[ind].x;
1190 convHulls[jj++] = verts[ind].y;
1191 convHulls[jj++] = verts[ind].z;
1192 }
1193 } 1358 }
1194 1359
1195 // create the hull definition in Bullet 1360 // Make sure the properties are set on the new object
1196 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); 1361 UpdatePhysicalParameters();
1197 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1198 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1199 // meshes are already scaled by the meshmerizer
1200 _scale = new OMV.Vector3(1f, 1f, 1f);
1201 // DetailLog("{0},BSPrim.CreateGeomHull,done", LocalID);
1202 return;
1203 }
1204
1205 // Callback from convex hull creater with a newly created hull.
1206 // Just add it to the collection of hulls for this shape.
1207 private void HullReturn(ConvexResult result)
1208 {
1209 _hulls.Add(result);
1210 return;
1211 }
1212
1213 // Create an object in Bullet if it has not already been created
1214 // No locking here because this is done when the physics engine is not simulating
1215 // Returns 'true' if an object was actually created.
1216 private bool CreateObject()
1217 {
1218 // this routine is called when objects are rebuilt.
1219
1220 // the mesh or hull must have already been created in Bullet
1221 ShapeData shape;
1222 FillShapeInfo(out shape);
1223 // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type);
1224 bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape);
1225
1226 // the CreateObject() may have recreated the rigid body. Make sure we have the latest.
1227 Body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
1228
1229 return ret;
1230 }
1231
1232 // Copy prim's info into the BulletSim shape description structure
1233 public void FillShapeInfo(out ShapeData shape)
1234 {
1235 shape.ID = _localID;
1236 shape.Type = _shapeType;
1237 shape.Position = _position;
1238 shape.Rotation = _orientation;
1239 shape.Velocity = _velocity;
1240 shape.Scale = _scale;
1241 shape.Mass = _isPhysical ? _mass : 0f;
1242 shape.Buoyancy = _buoyancy;
1243 shape.HullKey = _hullKey;
1244 shape.MeshKey = _meshKey;
1245 shape.Friction = _friction;
1246 shape.Restitution = _restitution;
1247 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1248 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1249 }
1250
1251
1252 // Rebuild the geometry and object.
1253 // This is called when the shape changes so we need to recreate the mesh/hull.
1254 // No locking here because this is done when the physics engine is not simulating
1255 private void RecreateGeomAndObject()
1256 {
1257 // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID);
1258 if (CreateGeom(true))
1259 CreateObject();
1260 return; 1362 return;
1261 } 1363 }
1262 1364
@@ -1277,7 +1379,7 @@ public sealed class BSPrim : PhysicsActor
1277 const float ACCELERATION_TOLERANCE = 0.01f; 1379 const float ACCELERATION_TOLERANCE = 0.01f;
1278 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; 1380 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1279 1381
1280 public void UpdateProperties(EntityProperties entprop) 1382 public override void UpdateProperties(EntityProperties entprop)
1281 { 1383 {
1282 /* 1384 /*
1283 UpdatedProperties changed = 0; 1385 UpdatedProperties changed = 0;
@@ -1315,7 +1417,7 @@ public sealed class BSPrim : PhysicsActor
1315 if (changed != 0) 1417 if (changed != 0)
1316 { 1418 {
1317 // Only update the position of single objects and linkset roots 1419 // Only update the position of single objects and linkset roots
1318 if (this._parentPrim == null) 1420 if (Linkset.IsRoot(this))
1319 { 1421 {
1320 base.RequestPhysicsterseUpdate(); 1422 base.RequestPhysicsterseUpdate();
1321 } 1423 }
@@ -1325,78 +1427,46 @@ public sealed class BSPrim : PhysicsActor
1325 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. 1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1326 1428
1327 // Updates only for individual prims and for the root object of a linkset. 1429 // Updates only for individual prims and for the root object of a linkset.
1328 if (_linkset.IsRoot(this)) 1430 if (Linkset.IsRoot(this))
1329 { 1431 {
1330 // Assign to the local variables so the normal set action does not happen 1432 // Assign directly to the local variables so the normal set action does not happen
1331 _position = entprop.Position; 1433 _position = entprop.Position;
1332 _orientation = entprop.Rotation; 1434 _orientation = entprop.Rotation;
1333 _velocity = entprop.Velocity; 1435 _velocity = entprop.Velocity;
1334 _acceleration = entprop.Acceleration; 1436 _acceleration = entprop.Acceleration;
1335 _rotationalVelocity = entprop.RotationalVelocity; 1437 _rotationalVelocity = entprop.RotationalVelocity;
1336 1438
1337 // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", 1439 // The sanity check can change the velocity and/or position.
1338 // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1440 if (PositionSanityCheck(true))
1339 // DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1441 {
1340 // LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 1442 entprop.Position = _position;
1443 entprop.Velocity = _velocity;
1444 }
1445
1446 // remember the current and last set values
1447 LastEntityProperties = CurrentEntityProperties;
1448 CurrentEntityProperties = entprop;
1449
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
1341 1455
1342 base.RequestPhysicsterseUpdate(); 1456 base.RequestPhysicsterseUpdate();
1343 } 1457 }
1344 /* 1458 /*
1345 else 1459 else
1346 { 1460 {
1347 // For debugging, we also report the movement of children 1461 // For debugging, report the movement of children
1348 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 1462 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1349 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 1463 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1350 entprop.Acceleration, entprop.RotationalVelocity); 1464 entprop.Acceleration, entprop.RotationalVelocity);
1351 } 1465 }
1352 */ 1466 */
1353 }
1354
1355 // I've collided with something
1356 CollisionEventUpdate collisionCollection;
1357 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1358 {
1359 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1360
1361 // The following lines make IsColliding() and IsCollidingGround() work
1362 _collidingStep = _scene.SimulationStep;
1363 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1364 {
1365 _collidingGroundStep = _scene.SimulationStep;
1366 }
1367
1368 // DetailLog("{0},BSPrim.Collison,call,with={1}", LocalID, collidingWith);
1369
1370 // if someone is subscribed to collision events....
1371 if (_subscribedEventsMs != 0) {
1372 // throttle the collisions to the number of milliseconds specified in the subscription
1373 int nowTime = _scene.SimulationNowTime;
1374 if (nowTime >= _nextCollisionOkTime) {
1375 _nextCollisionOkTime = nowTime + _subscribedEventsMs;
1376 1467
1377 if (collisionCollection == null) 1468 // The linkset implimentation might want to know about this.
1378 collisionCollection = new CollisionEventUpdate(); 1469 Linkset.UpdateProperties(this);
1379 collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1380 }
1381 }
1382 }
1383
1384 // The scene is telling us it's time to pass our collected collisions into the simulator
1385 public void SendCollisions()
1386 {
1387 if (collisionCollection != null && collisionCollection.Count > 0)
1388 {
1389 base.SendCollisionUpdate(collisionCollection);
1390 // The collisionCollection structure is passed around in the simulator.
1391 // Make sure we don't have a handle to that one and that a new one is used next time.
1392 collisionCollection = null;
1393 }
1394 }
1395
1396 // Invoke the detailed logger and output something if it's enabled.
1397 private void DetailLog(string msg, params Object[] args)
1398 {
1399 Scene.PhysicsLogging.Write(msg, args);
1400 } 1470 }
1401} 1471}
1402} 1472}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index a31c578..27a78d1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,96 +39,88 @@ using log4net;
39using OpenMetaverse; 39using OpenMetaverse;
40 40
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) 41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Debug linkset 42// Test sculpties (verified that they don't work)
43// Test with multiple regions in one simulator
44// Adjust character capsule size when height is adjusted (ScenePresence.SetHeight)
45// Test sculpties
46// Compute physics FPS reasonably 43// Compute physics FPS reasonably
47// Based on material, set density and friction 44// Based on material, set density and friction
48// More efficient memory usage when passing hull information from BSPrim to BulletSim 45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
49// Move all logic out of the C++ code and into the C# code for easier future modifications.
50// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? 46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
51// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) 47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
52// At the moment, physical and phantom causes object to drop through the terrain 48// At the moment, physical and phantom causes object to drop through the terrain
53// Physical phantom objects and related typing (collision options ) 49// Physical phantom objects and related typing (collision options )
54// Use collision masks for collision with terrain and phantom objects
55// Check out llVolumeDetect. Must do something for that. 50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
56// Should prim.link() and prim.delink() membership checking happen at taint time? 53// Should prim.link() and prim.delink() membership checking happen at taint time?
57// changing the position and orientation of a linked prim must rebuild the constraint with the root. 54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
58// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once
59// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect 55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
60// Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions)
61// Implement LockAngularMotion 56// Implement LockAngularMotion
62// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) 57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
63// Does NeedsMeshing() really need to exclude all the different shapes?
64// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. 58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
65// Add PID movement operations. What does ScenePresence.MoveToTarget do? 59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
66// Check terrain size. 128 or 127? 60// Check terrain size. 128 or 127?
67// Raycast 61// Raycast
68// 62//
69namespace OpenSim.Region.Physics.BulletSPlugin 63namespace OpenSim.Region.Physics.BulletSPlugin
70{ 64{
71public class BSScene : PhysicsScene, IPhysicsParameters 65public sealed class BSScene : PhysicsScene, IPhysicsParameters
72{ 66{
73 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
74 private static readonly string LogHeader = "[BULLETS SCENE]"; 68 private static readonly string LogHeader = "[BULLETS SCENE]";
75 69
76 public void DebugLog(string mm, params Object[] xx) { if (ShouldDebugLog) m_log.DebugFormat(mm, xx); } 70 // The name of the region we're working for.
71 public string RegionName { get; private set; }
77 72
78 public string BulletSimVersion = "?"; 73 public string BulletSimVersion = "?";
79 74
80 private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); 75 public Dictionary<uint, BSPhysObject> PhysObjects;
81 private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); 76 public BSShapeCollection Shapes;
82 private HashSet<BSCharacter> m_avatarsWithCollisions = new HashSet<BSCharacter>();
83 private HashSet<BSPrim> m_primsWithCollisions = new HashSet<BSPrim>();
84 private List<BSPrim> m_vehicles = new List<BSPrim>();
85 private float[] m_heightMap;
86 private float m_waterLevel;
87 private uint m_worldID;
88 public uint WorldID { get { return m_worldID; } }
89 77
90 // let my minuions use my logger 78 // Keeping track of the objects with collisions so we can report begin and end of a collision
91 public ILog Logger { get { return m_log; } } 79 public HashSet<BSPhysObject> ObjectsWithCollisions = new HashSet<BSPhysObject>();
80 public HashSet<BSPhysObject> ObjectsWithNoMoreCollisions = new HashSet<BSPhysObject>();
81 // Keep track of all the avatars so we can send them a collision event
82 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
92 84
93 private bool m_initialized = false; 85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
94 88
95 private int m_detailedStatsStep = 0; 89 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } }
96 91
97 public IMesher mesher; 92 public IMesher mesher;
98 private float m_meshLOD; 93 // Level of Detail values kept as float because that's what the Meshmerizer wants
99 public float MeshLOD 94 public float MeshLOD { get; private set; }
100 { 95 public float MeshMegaPrimLOD { get; private set; }
101 get { return m_meshLOD; } 96 public float MeshMegaPrimThreshold { get; private set; }
102 } 97 public float SculptLOD { get; private set; }
103 private float m_sculptLOD;
104 public float SculptLOD
105 {
106 get { return m_sculptLOD; }
107 }
108 98
109 private BulletSim m_worldSim; 99 public uint WorldID { get; private set; }
110 public BulletSim World 100 public BulletSim World { get; private set; }
111 { 101
112 get { return m_worldSim; } 102 // All the constraints that have been allocated in this instance.
113 } 103 public BSConstraintCollection Constraints { get; private set; }
114 private BSConstraintCollection m_constraintCollection;
115 public BSConstraintCollection Constraints
116 {
117 get { return m_constraintCollection; }
118 }
119 104
105 // Simulation parameters
120 private int m_maxSubSteps; 106 private int m_maxSubSteps;
121 private float m_fixedTimeStep; 107 private float m_fixedTimeStep;
122 private long m_simulationStep = 0; 108 private long m_simulationStep = 0;
123 public long SimulationStep { get { return m_simulationStep; } } 109 public long SimulationStep { get { return m_simulationStep; } }
124 110 private int m_taintsToProcessPerStep;
125 public float LastSimulatedTimestep { get; private set; }
126 111
127 // 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
128 // 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
129 private int m_simulationNowTime; 114 public int SimulationNowTime { get; private set; }
130 public int SimulationNowTime { get { return m_simulationNowTime; } } 115
116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false;
118
119 // Flag which is true when processing taints.
120 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
121 public bool InTaintTime { get; private set; }
131 122
123 // Pinned memory used to pass step information between managed and unmanaged
132 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
133 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
134 private GCHandle m_collisionArrayPinnedHandle; 126 private GCHandle m_collisionArrayPinnedHandle;
@@ -137,14 +129,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
137 private EntityProperties[] m_updateArray; 129 private EntityProperties[] m_updateArray;
138 private GCHandle m_updateArrayPinnedHandle; 130 private GCHandle m_updateArrayPinnedHandle;
139 131
140 private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed 132 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
141 private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes 133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
134 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
142 135
143 public float PID_D { get; private set; } // derivative 136 public float PID_D { get; private set; } // derivative
144 public float PID_P { get; private set; } // proportional 137 public float PID_P { get; private set; } // proportional
145 138
146 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
147 public const uint GROUNDPLANE_ID = 1; 140 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142
143 private float m_waterLevel;
144 public BSTerrainManager TerrainManager { get; private set; }
148 145
149 public ConfigurationParameters Params 146 public ConfigurationParameters Params
150 { 147 {
@@ -154,13 +151,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
154 { 151 {
155 get { return new Vector3(0f, 0f, Params.gravity); } 152 get { return new Vector3(0f, 0f, Params.gravity); }
156 } 153 }
157 154 // Just the Z value of the gravity
158 private float m_maximumObjectMass; 155 public float DefaultGravityZ
159 public float MaximumObjectMass
160 { 156 {
161 get { return m_maximumObjectMass; } 157 get { return Params.gravity; }
162 } 158 }
163 159
160 public float MaximumObjectMass { get; private set; }
161
162 // When functions in the unmanaged code must be called, it is only
163 // done at a known time just before the simulation step. The taint
164 // system saves all these function calls and executes them in
165 // order before the simulation.
164 public delegate void TaintCallback(); 166 public delegate void TaintCallback();
165 private struct TaintCallbackEntry 167 private struct TaintCallbackEntry
166 { 168 {
@@ -172,15 +174,19 @@ public class BSScene : PhysicsScene, IPhysicsParameters
172 callback = c; 174 callback = c;
173 } 175 }
174 } 176 }
175 private List<TaintCallbackEntry> _taintedObjects; 177 private Object _taintLock = new Object(); // lock for using the next object
176 private Object _taintLock = new Object(); 178 private List<TaintCallbackEntry> _taintOperations;
179 private Dictionary<string, TaintCallbackEntry> _postTaintOperations;
180 private List<TaintCallbackEntry> _postStepOperations;
177 181
178 // A pointer to an instance if this structure is passed to the C++ code 182 // A pointer to an instance if this structure is passed to the C++ code
183 // Used to pass basic configuration values to the unmanaged code.
179 ConfigurationParameters[] m_params; 184 ConfigurationParameters[] m_params;
180 GCHandle m_paramsHandle; 185 GCHandle m_paramsHandle;
181 186
182 public bool ShouldDebugLog { get; private set; } 187 // Handle to the callback used by the unmanaged code to call into the managed code.
183 188 // Used for debug logging.
189 // Need to store the handle in a persistant variable so it won't be freed.
184 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; 190 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
185 191
186 // Sometimes you just have to log everything. 192 // Sometimes you just have to log everything.
@@ -189,17 +195,26 @@ public class BSScene : PhysicsScene, IPhysicsParameters
189 private string m_physicsLoggingDir; 195 private string m_physicsLoggingDir;
190 private string m_physicsLoggingPrefix; 196 private string m_physicsLoggingPrefix;
191 private int m_physicsLoggingFileMinutes; 197 private int m_physicsLoggingFileMinutes;
198 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; }
192 200
193 private bool m_vehicleLoggingEnabled; 201 #region Construction and Initialization
194 public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } }
195
196 public BSScene(string identifier) 202 public BSScene(string identifier)
197 { 203 {
198 m_initialized = false; 204 m_initialized = false;
205 // we are passed the name of the region we're working for.
206 RegionName = identifier;
199 } 207 }
200 208
201 public override void Initialise(IMesher meshmerizer, IConfigSource config) 209 public override void Initialise(IMesher meshmerizer, IConfigSource config)
202 { 210 {
211 mesher = meshmerizer;
212 _taintOperations = new List<TaintCallbackEntry>();
213 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
214 _postStepOperations = new List<TaintCallbackEntry>();
215 PhysObjects = new Dictionary<uint, BSPhysObject>();
216 Shapes = new BSShapeCollection(this);
217
203 // Allocate pinned memory to pass parameters. 218 // Allocate pinned memory to pass parameters.
204 m_params = new ConfigurationParameters[1]; 219 m_params = new ConfigurationParameters[1];
205 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); 220 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
@@ -215,7 +230,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
215 230
216 // Enable very detailed logging. 231 // Enable very detailed logging.
217 // By creating an empty logger when not logging, the log message invocation code 232 // By creating an empty logger when not logging, the log message invocation code
218 // can be left in and every call doesn't have to check for null. 233 // can be left in and every call doesn't have to check for null.
219 if (m_physicsLoggingEnabled) 234 if (m_physicsLoggingEnabled)
220 { 235 {
221 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
@@ -225,39 +240,43 @@ public class BSScene : PhysicsScene, IPhysicsParameters
225 PhysicsLogging = new Logging.LogWriter(); 240 PhysicsLogging = new Logging.LogWriter();
226 } 241 }
227 242
228 // Get the version of the DLL 243 // If Debug logging level, enable logging from the unmanaged code
229 // TODO: this doesn't work yet. Something wrong with marshaling the returned string. 244 m_DebugLogCallbackHandle = null;
230 // BulletSimVersion = BulletSimAPI.GetVersion();
231 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
232
233 // if Debug, enable logging from the unmanaged code
234 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 245 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled)
235 { 246 {
236 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); 247 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
237 if (PhysicsLogging.Enabled) 248 if (PhysicsLogging.Enabled)
249 // The handle is saved in a variable to make sure it doesn't get freed after this call
238 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); 250 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
239 else 251 else
240 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); 252 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
241 // the handle is saved in a variable to make sure it doesn't get freed after this call
242 BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
243 } 253 }
244 254
245 _taintedObjects = new List<TaintCallbackEntry>(); 255 // Get the version of the DLL
256 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
257 // BulletSimVersion = BulletSimAPI.GetVersion();
258 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
246 259
247 mesher = meshmerizer; 260 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
248 // The bounding box for the simulated world 261 // a child in a mega-region.
249 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 8192f); 262 // Bullet actually doesn't care about the extents of the simulated
263 // area. It tracks active objects no matter where they are.
264 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
250 265
251 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 266 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader);
252 m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), 267 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
253 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), 268 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
254 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); 269 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
270 m_DebugLogCallbackHandle));
271
272 Constraints = new BSConstraintCollection(World);
255 273
256 // Initialization to support the transition to a new API which puts most of the logic 274 TerrainManager = new BSTerrainManager(this);
257 // into the C# code so it is easier to modify and add to. 275 TerrainManager.CreateInitialGroundPlaneAndTerrain();
258 m_worldSim = new BulletSim(m_worldID, this, BulletSimAPI.GetSimHandle2(m_worldID));
259 m_constraintCollection = new BSConstraintCollection(World);
260 276
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
278
279 InTaintTime = false;
261 m_initialized = true; 280 m_initialized = true;
262 } 281 }
263 282
@@ -281,10 +300,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
281 // Very detailed logging for physics debugging 300 // Very detailed logging for physics debugging
282 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 301 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
283 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
284 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); 303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
285 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
286 // Very detailed logging for vehicle debugging 305 // Very detailed logging for vehicle debugging
287 m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
307
308 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
288 } 310 }
289 } 311 }
290 } 312 }
@@ -309,13 +331,51 @@ public class BSScene : PhysicsScene, IPhysicsParameters
309 { 331 {
310 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 332 m_log.Debug("[BULLETS UNMANAGED]:" + msg);
311 } 333 }
312 334
313 // Called directly from unmanaged code so don't do much 335 // Called directly from unmanaged code so don't do much
314 private void BulletLoggerPhysLog(string msg) 336 private void BulletLoggerPhysLog(string msg)
315 { 337 {
316 PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); 338 DetailLog("[BULLETS UNMANAGED]:" + msg);
317 } 339 }
318 340
341 public override void Dispose()
342 {
343 // m_log.DebugFormat("{0}: Dispose()", LogHeader);
344
345 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false;
347
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 {
352 kvp.Value.Destroy();
353 }
354 PhysObjects.Clear();
355
356 // Now that the prims are all cleaned up, there should be no constraints left
357 if (Constraints != null)
358 {
359 Constraints.Dispose();
360 Constraints = null;
361 }
362
363 if (Shapes != null)
364 {
365 Shapes.Dispose();
366 Shapes = null;
367 }
368
369 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr);
371
372 // Not logging any more
373 PhysicsLogging.Close();
374 }
375 #endregion // Construction and Initialization
376
377 #region Prim and Avatar addition and removal
378
319 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) 379 public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying)
320 { 380 {
321 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader); 381 m_log.ErrorFormat("{0}: CALL TO AddAvatar in BSScene. NOT IMPLEMENTED", LogHeader);
@@ -329,7 +389,13 @@ public class BSScene : PhysicsScene, IPhysicsParameters
329 if (!m_initialized) return null; 389 if (!m_initialized) return null;
330 390
331 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying); 391 BSCharacter actor = new BSCharacter(localID, avName, this, position, size, isFlying);
332 lock (m_avatars) m_avatars.Add(localID, actor); 392 lock (PhysObjects) PhysObjects.Add(localID, actor);
393
394 // TODO: Remove kludge someday.
395 // We must generate a collision for avatars whether they collide or not.
396 // This is required by OpenSim to update avatar animations, etc.
397 lock (m_avatars) m_avatars.Add(actor);
398
333 return actor; 399 return actor;
334 } 400 }
335 401
@@ -344,7 +410,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters
344 { 410 {
345 try 411 try
346 { 412 {
347 lock (m_avatars) m_avatars.Remove(actor.LocalID); 413 lock (PhysObjects) PhysObjects.Remove(actor.LocalID);
414 // Remove kludge someday
415 lock (m_avatars) m_avatars.Remove(bsactor);
348 } 416 }
349 catch (Exception e) 417 catch (Exception e)
350 { 418 {
@@ -362,11 +430,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
362 BSPrim bsprim = prim as BSPrim; 430 BSPrim bsprim = prim as BSPrim;
363 if (bsprim != null) 431 if (bsprim != null)
364 { 432 {
365 // DetailLog("{0},RemovePrim,call", bsprim.LocalID); 433 DetailLog("{0},RemovePrim,call", bsprim.LocalID);
366 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); 434 // m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID);
367 try 435 try
368 { 436 {
369 lock (m_prims) m_prims.Remove(bsprim.LocalID); 437 lock (PhysObjects) PhysObjects.Remove(bsprim.LocalID);
370 } 438 }
371 catch (Exception e) 439 catch (Exception e)
372 { 440 {
@@ -388,18 +456,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters
388 456
389 if (!m_initialized) return null; 457 if (!m_initialized) return null;
390 458
391 // DetailLog("{0},AddPrimShape,call", localID); 459 DetailLog("{0},AddPrimShape,call", localID);
392 460
393 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); 461 BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical);
394 lock (m_prims) m_prims.Add(localID, prim); 462 lock (PhysObjects) PhysObjects.Add(localID, prim);
395 return prim; 463 return prim;
396 } 464 }
397 465
398 // This is a call from the simulator saying that some physical property has been updated. 466 // This is a call from the simulator saying that some physical property has been updated.
399 // The BulletSim driver senses the changing of relevant properties so this taint 467 // The BulletSim driver senses the changing of relevant properties so this taint
400 // information call is not needed. 468 // information call is not needed.
401 public override void AddPhysicsActorTaint(PhysicsActor prim) { } 469 public override void AddPhysicsActorTaint(PhysicsActor prim) { }
402 470
471 #endregion // Prim and Avatar addition and removal
472
473 #region Simulation
403 // Simulate one timestep 474 // Simulate one timestep
404 public override float Simulate(float timeStep) 475 public override float Simulate(float timeStep)
405 { 476 {
@@ -408,14 +479,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters
408 int collidersCount = 0; 479 int collidersCount = 0;
409 IntPtr collidersPtr; 480 IntPtr collidersPtr;
410 481
411 LastSimulatedTimestep = timeStep; 482 int beforeTime = 0;
483 int simTime = 0;
412 484
413 // prevent simulation until we've been initialized 485 // prevent simulation until we've been initialized
414 if (!m_initialized) return 10.0f; 486 if (!m_initialized) return 5.0f;
415
416 int simulateStartTime = Util.EnvironmentTickCount();
417 487
418 // update the prim states while we know the physics engine is not busy 488 // update the prim states while we know the physics engine is not busy
489 int numTaints = _taintOperations.Count;
419 ProcessTaints(); 490 ProcessTaints();
420 491
421 // Some of the prims operate with special vehicle properties 492 // Some of the prims operate with special vehicle properties
@@ -425,25 +496,34 @@ public class BSScene : PhysicsScene, IPhysicsParameters
425 // step the physical world one interval 496 // step the physical world one interval
426 m_simulationStep++; 497 m_simulationStep++;
427 int numSubSteps = 0; 498 int numSubSteps = 0;
499
428 try 500 try
429 { 501 {
430 numSubSteps = BulletSimAPI.PhysicsStep(m_worldID, timeStep, m_maxSubSteps, m_fixedTimeStep, 502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
504
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
431 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); 506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
432 // DetailLog("{0},Simulate,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 507
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
433 } 512 }
434 catch (Exception e) 513 catch (Exception e)
435 { 514 {
436 m_log.WarnFormat("{0},PhysicsStep Exception: substeps={1}, updates={2}, colliders={3}, e={4}", LogHeader, numSubSteps, updatedEntityCount, collidersCount, e); 515 m_log.WarnFormat("{0},PhysicsStep Exception: nTaints={1}, substeps={2}, updates={3}, colliders={4}, e={5}",
437 // DetailLog("{0},PhysicsStepException,call, substeps={1}, updates={2}, colliders={3}", DetailLogZero, numSubSteps, updatedEntityCount, collidersCount); 516 LogHeader, numTaints, numSubSteps, updatedEntityCount, collidersCount, e);
438 // updatedEntityCount = 0; 517 DetailLog("{0},PhysicsStepException,call, nTaints={1}, substeps={2}, updates={3}, colliders={4}",
518 DetailLogZero, numTaints, numSubSteps, updatedEntityCount, collidersCount);
519 updatedEntityCount = 0;
439 collidersCount = 0; 520 collidersCount = 0;
440 } 521 }
441 522
442
443 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
444 524
445 // Get a value for 'now' so all the collision and update routines don't have to get their own 525 // Get a value for 'now' so all the collision and update routines don't have to get their own
446 m_simulationNowTime = Util.EnvironmentTickCount(); 526 SimulationNowTime = Util.EnvironmentTickCount();
447 527
448 // If there were collisions, process them by sending the event to the prim. 528 // If there were collisions, process them by sending the event to the prim.
449 // Collisions must be processed before updates. 529 // Collisions must be processed before updates.
@@ -462,19 +542,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters
462 542
463 // The above SendCollision's batch up the collisions on the objects. 543 // The above SendCollision's batch up the collisions on the objects.
464 // Now push the collisions into the simulator. 544 // Now push the collisions into the simulator.
465 foreach (BSPrim bsp in m_primsWithCollisions) 545 if (ObjectsWithCollisions.Count > 0)
466 bsp.SendCollisions(); 546 {
467 m_primsWithCollisions.Clear(); 547 foreach (BSPhysObject bsp in ObjectsWithCollisions)
468 548 if (!bsp.SendCollisions())
469 // This is a kludge to get avatar movement updated. 549 {
470 // Don't send collisions only if there were collisions -- send everytime. 550 // If the object is done colliding, see that it's removed from the colliding list
471 // ODE sends collisions even if there are none and this is used to update 551 ObjectsWithNoMoreCollisions.Add(bsp);
472 // avatar animations and stuff. 552 }
473 // foreach (BSCharacter bsc in m_avatarsWithCollisions) 553 }
474 // bsc.SendCollisions(); 554
475 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 555 // This is a kludge to get avatar movement updates.
476 kvp.Value.SendCollisions(); 556 // The simulator expects collisions for avatars even if there are have been no collisions.
477 m_avatarsWithCollisions.Clear(); 557 // The event updates avatar animations and stuff.
558 // If you fix avatar animation updates, remove this overhead and let normal collision processing happen.
559 foreach (BSPhysObject bsp in m_avatars)
560 if (!ObjectsWithCollisions.Contains(bsp)) // don't call avatars twice
561 bsp.SendCollisions();
562
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions.
565 if (ObjectsWithNoMoreCollisions.Count > 0)
566 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear();
570 }
478 571
479 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
480 if (updatedEntityCount > 0) 573 if (updatedEntityCount > 0)
@@ -482,320 +575,316 @@ public class BSScene : PhysicsScene, IPhysicsParameters
482 for (int ii = 0; ii < updatedEntityCount; ii++) 575 for (int ii = 0; ii < updatedEntityCount; ii++)
483 { 576 {
484 EntityProperties entprop = m_updateArray[ii]; 577 EntityProperties entprop = m_updateArray[ii];
485 BSPrim prim; 578 BSPhysObject pobj;
486 if (m_prims.TryGetValue(entprop.ID, out prim)) 579 if (PhysObjects.TryGetValue(entprop.ID, out pobj))
487 {
488 prim.UpdateProperties(entprop);
489 continue;
490 }
491 BSCharacter actor;
492 if (m_avatars.TryGetValue(entprop.ID, out actor))
493 { 580 {
494 actor.UpdateProperties(entprop); 581 pobj.UpdateProperties(entprop);
495 continue;
496 } 582 }
497 } 583 }
498 } 584 }
499 585
500 // If enabled, call into the physics engine to dump statistics 586 ProcessPostStepTaints();
501 if (m_detailedStatsStep > 0)
502 {
503 if ((m_simulationStep % m_detailedStatsStep) == 0)
504 {
505 BulletSimAPI.DumpBulletStatistics();
506 }
507 }
508 587
509 // this is a waste since the outside routine also calcuates the physics simulation 588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world.
510 // period. TODO: There should be a way of computing physics frames from simulator computation. 589 // Only enable this in a limited test world with few objects.
511 // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG
512 // return (timeStep * (float)simulateTotalTime); 591
513 592 // The physics engine returns the number of milliseconds it simulated this call.
514 // TODO: FIX THIS: fps calculation possibly wrong. 593 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
515 // This calculation says 1/timeStep is the ideal frame rate. Any time added to 594 // We multiply by 55 to give a recognizable running rate (55 or less).
516 // that by the physics simulation gives a slower frame rate. 595 return numSubSteps * m_fixedTimeStep * 1000 * 55;
517 long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime); 596 // return timeStep * 1000 * 55;
518 if (totalSimulationTime >= timeStep)
519 return 0;
520 return 1f / (timeStep + totalSimulationTime);
521 } 597 }
522 598
523 // Something has collided 599 // Something has collided
524 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penitration) 600 private void SendCollision(uint localID, uint collidingWith, Vector3 collidePoint, Vector3 collideNormal, float penetration)
525 { 601 {
526 if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) 602 if (localID <= TerrainManager.HighestTerrainID)
527 { 603 {
528 return; // don't send collisions to the terrain 604 return; // don't send collisions to the terrain
529 } 605 }
530 606
531 ActorTypes type = ActorTypes.Prim; 607 BSPhysObject collider;
532 if (collidingWith == TERRAIN_ID || collidingWith == GROUNDPLANE_ID) 608 if (!PhysObjects.TryGetValue(localID, out collider))
533 type = ActorTypes.Ground; 609 {
534 else if (m_avatars.ContainsKey(collidingWith)) 610 // If the object that is colliding cannot be found, just ignore the collision.
535 type = ActorTypes.Agent; 611 DetailLog("{0},BSScene.SendCollision,colliderNotInObjectList,id={1},with={2}", DetailLogZero, localID, collidingWith);
536
537 BSPrim prim;
538 if (m_prims.TryGetValue(localID, out prim)) {
539 prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration);
540 m_primsWithCollisions.Add(prim);
541 return; 612 return;
542 } 613 }
543 BSCharacter actor; 614
544 if (m_avatars.TryGetValue(localID, out actor)) { 615 // The terrain is not in the physical object list so 'collidee' can be null when Collide() is called.
545 actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); 616 BSPhysObject collidee = null;
546 m_avatarsWithCollisions.Add(actor); 617 PhysObjects.TryGetValue(collidingWith, out collidee);
547 return; 618
619 // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith);
620
621 if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration))
622 {
623 // If a collision was posted, remember to send it to the simulator
624 ObjectsWithCollisions.Add(collider);
548 } 625 }
626
549 return; 627 return;
550 } 628 }
551 629
630 #endregion // Simulation
631
552 public override void GetResults() { } 632 public override void GetResults() { }
553 633
634 #region Terrain
635
554 public override void SetTerrain(float[] heightMap) { 636 public override void SetTerrain(float[] heightMap) {
555 m_heightMap = heightMap; 637 TerrainManager.SetTerrain(heightMap);
556 this.TaintedObject("BSScene.SetTerrain", delegate()
557 {
558 BulletSimAPI.SetHeightmap(m_worldID, m_heightMap);
559 });
560 } 638 }
561 639
562 // Someday we will have complex terrain with caves and tunnels 640 public override void SetWaterLevel(float baseheight)
563 // For the moment, it's flat and convex
564 public float GetTerrainHeightAtXYZ(Vector3 loc)
565 { 641 {
566 return GetTerrainHeightAtXY(loc.X, loc.Y); 642 m_waterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
567 } 648 }
568 649
569 public float GetTerrainHeightAtXY(float tX, float tY) 650 public override void DeleteTerrain()
570 { 651 {
571 if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize) 652 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader);
572 return 30;
573 return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)];
574 } 653 }
575 654
576 public override void SetWaterLevel(float baseheight) 655 // Although no one seems to check this, I do support combining.
656 public override bool SupportsCombining()
577 { 657 {
578 m_waterLevel = baseheight; 658 return TerrainManager.SupportsCombining();
579 // TODO: pass to physics engine so things will float?
580 } 659 }
581 public float GetWaterLevel() 660 // This call says I am a child to region zero in a mega-region. 'pScene' is that
661 // of region zero, 'offset' is my offset from regions zero's origin, and
662 // 'extents' is the largest XY that is handled in my region.
663 public override void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
582 { 664 {
583 return m_waterLevel; 665 TerrainManager.Combine(pScene, offset, extents);
584 } 666 }
585 667
586 public override void DeleteTerrain() 668 // Unhook all the combining that I know about.
669 public override void UnCombine(PhysicsScene pScene)
587 { 670 {
588 // m_log.DebugFormat("{0}: DeleteTerrain()", LogHeader); 671 TerrainManager.UnCombine(pScene);
589 } 672 }
590 673
591 public override void Dispose() 674 #endregion // Terrain
675
676 public override Dictionary<uint, float> GetTopColliders()
592 { 677 {
593 // m_log.DebugFormat("{0}: Dispose()", LogHeader); 678 return new Dictionary<uint, float>();
679 }
594 680
595 // make sure no stepping happens while we're deleting stuff 681 public override bool IsThreaded { get { return false; } }
596 m_initialized = false;
597 682
598 foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) 683 #region Taints
599 {
600 kvp.Value.Destroy();
601 }
602 m_avatars.Clear();
603 684
604 foreach (KeyValuePair<uint, BSPrim> kvp in m_prims) 685 // Calls to the PhysicsActors can't directly call into the physics engine
605 { 686 // because it might be busy. We delay changes to a known time.
606 kvp.Value.Destroy(); 687 // We rely on C#'s closure to save and restore the context for the delegate.
607 } 688 public void TaintedObject(String ident, TaintCallback callback)
608 m_prims.Clear(); 689 {
690 if (!m_initialized) return;
609 691
610 // Now that the prims are all cleaned up, there should be no constraints left 692 lock (_taintLock)
611 if (m_constraintCollection != null)
612 { 693 {
613 m_constraintCollection.Dispose(); 694 _taintOperations.Add(new TaintCallbackEntry(ident, callback));
614 m_constraintCollection = null;
615 } 695 }
616 696
617 // Anything left in the unmanaged code should be cleaned out 697 return;
618 BulletSimAPI.Shutdown(WorldID);
619
620 // Not logging any more
621 PhysicsLogging.Close();
622 } 698 }
623 699
624 public override Dictionary<uint, float> GetTopColliders() 700 // Sometimes a potentially tainted operation can be used in and out of taint time.
701 // This routine executes the command immediately if in taint-time otherwise it is queued.
702 public void TaintedObject(bool inTaintTime, string ident, TaintCallback callback)
625 { 703 {
626 return new Dictionary<uint, float>(); 704 if (inTaintTime)
705 callback();
706 else
707 TaintedObject(ident, callback);
627 } 708 }
628 709
629 public override bool IsThreaded { get { return false; } } 710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
630 711 // a callback into itself to do the actual property change. That callback is called
631 /// <summary> 712 // here just before the physics engine is called to step the simulation.
632 /// Routine to figure out if we need to mesh this prim with our mesher 713 public void ProcessTaints()
633 /// </summary>
634 /// <param name="pbs"></param>
635 /// <returns>true if the prim needs meshing</returns>
636 public bool NeedsMeshing(PrimitiveBaseShape pbs)
637 { 714 {
638 // most of this is redundant now as the mesher will return null if it cant mesh a prim 715 InTaintTime = true; // Only used for debugging so locking is not necessary.
639 // but we still need to check for sculptie meshing being enabled so this is the most 716 ProcessRegularTaints();
640 // convenient place to do it for now... 717 ProcessPostTaintTaints();
641 718 InTaintTime = false;
642 // int iPropertiesNotSupportedDefault = 0; 719 }
643
644 if (pbs.SculptEntry && !_meshSculptedPrim)
645 {
646 // Render sculpties as boxes
647 return false;
648 }
649 720
650 // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet 721 private void ProcessRegularTaints()
651 // can use an internal representation for the prim 722 {
652 if (!_forceSimplePrimMeshing) 723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
653 { 724 {
654 if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) 725 /*
655 || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 726 // Code to limit the number of taints processed per step. Meant to limit step time.
656 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) 727 // Unsure if a good idea as code assumes that taints are done before the step.
728 int taintCount = m_taintsToProcessPerStep;
729 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
730 while (_taintOperations.Count > 0 && taintCount-- > 0)
657 { 731 {
658 732 bool gotOne = false;
659 if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 733 lock (_taintLock)
660 && pbs.ProfileHollow == 0
661 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
662 && pbs.PathBegin == 0 && pbs.PathEnd == 0
663 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
664 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
665 && pbs.PathShearX == 0 && pbs.PathShearY == 0)
666 { 734 {
667 return false; 735 if (_taintOperations.Count > 0)
736 {
737 oneCallback = _taintOperations[0];
738 _taintOperations.RemoveAt(0);
739 gotOne = true;
740 }
741 }
742 if (gotOne)
743 {
744 try
745 {
746 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
747 oneCallback.callback();
748 }
749 catch (Exception e)
750 {
751 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
752 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
753 }
668 } 754 }
669 } 755 }
670 } 756 if (_taintOperations.Count > 0)
671
672 /* TODO: verify that the mesher will now do all these shapes
673 if (pbs.ProfileHollow != 0)
674 iPropertiesNotSupportedDefault++;
675
676 if ((pbs.PathBegin != 0) || pbs.PathEnd != 0)
677 iPropertiesNotSupportedDefault++;
678
679 if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0))
680 iPropertiesNotSupportedDefault++;
681
682 if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
683 iPropertiesNotSupportedDefault++;
684
685 if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
686 iPropertiesNotSupportedDefault++;
687
688 if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
689 iPropertiesNotSupportedDefault++;
690
691 if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
692 iPropertiesNotSupportedDefault++;
693
694 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X))
695 iPropertiesNotSupportedDefault++;
696
697 if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1)
698 iPropertiesNotSupportedDefault++;
699
700 // test for torus
701 if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
702 {
703 if (pbs.PathCurve == (byte)Extrusion.Curve1)
704 { 757 {
705 iPropertiesNotSupportedDefault++; 758 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
706 } 759 }
707 } 760 */
708 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) 761
709 { 762 // swizzle a new list into the list location so we can process what's there
710 if (pbs.PathCurve == (byte)Extrusion.Straight) 763 List<TaintCallbackEntry> oldList;
764 lock (_taintLock)
711 { 765 {
712 iPropertiesNotSupportedDefault++; 766 oldList = _taintOperations;
767 _taintOperations = new List<TaintCallbackEntry>();
713 } 768 }
714 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits 769
715 else if (pbs.PathCurve == (byte)Extrusion.Curve1) 770 foreach (TaintCallbackEntry tcbe in oldList)
716 { 771 {
717 iPropertiesNotSupportedDefault++; 772 try
773 {
774 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
775 tcbe.callback();
776 }
777 catch (Exception e)
778 {
779 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
780 }
718 } 781 }
782 oldList.Clear();
719 } 783 }
720 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) 784 }
785
786 // Schedule an update to happen after all the regular taints are processed.
787 // Note that new requests for the same operation ("ident") for the same object ("ID")
788 // will replace any previous operation by the same object.
789 public void PostTaintObject(String ident, uint ID, TaintCallback callback)
790 {
791 string uniqueIdent = ident + "-" + ID.ToString();
792 lock (_taintLock)
721 { 793 {
722 if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) 794 _postTaintOperations[uniqueIdent] = new TaintCallbackEntry(uniqueIdent, callback);
723 {
724 iPropertiesNotSupportedDefault++;
725 }
726 } 795 }
727 else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) 796
797 return;
798 }
799
800 private void ProcessPostTaintTaints()
801 {
802 if (_postTaintOperations.Count > 0)
728 { 803 {
729 if (pbs.PathCurve == (byte)Extrusion.Straight) 804 Dictionary<string, TaintCallbackEntry> oldList;
805 lock (_taintLock)
730 { 806 {
731 iPropertiesNotSupportedDefault++; 807 oldList = _postTaintOperations;
808 _postTaintOperations = new Dictionary<string, TaintCallbackEntry>();
732 } 809 }
733 else if (pbs.PathCurve == (byte)Extrusion.Curve1) 810
811 foreach (KeyValuePair<string,TaintCallbackEntry> kvp in oldList)
734 { 812 {
735 iPropertiesNotSupportedDefault++; 813 try
814 {
815 DetailLog("{0},BSScene.ProcessPostTaintTaints,doTaint,id={1}", DetailLogZero, kvp.Key); // DEBUG DEBUG DEBUG
816 kvp.Value.callback();
817 }
818 catch (Exception e)
819 {
820 m_log.ErrorFormat("{0}: ProcessPostTaintTaints: {1}: Exception: {2}", LogHeader, kvp.Key, e);
821 }
736 } 822 }
823 oldList.Clear();
737 } 824 }
738 if (iPropertiesNotSupportedDefault == 0)
739 {
740 return false;
741 }
742 */
743 return true;
744 } 825 }
745 826
746 // Calls to the PhysicsActors can't directly call into the physics engine 827 public void PostStepTaintObject(String ident, TaintCallback callback)
747 // because it might be busy. We delay changes to a known time.
748 // We rely on C#'s closure to save and restore the context for the delegate.
749 public void TaintedObject(String ident, TaintCallback callback)
750 { 828 {
751 if (!m_initialized) return; 829 if (!m_initialized) return;
752 830
753 lock (_taintLock) 831 lock (_taintLock)
754 _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); 832 {
833 _postStepOperations.Add(new TaintCallbackEntry(ident, callback));
834 }
835
755 return; 836 return;
756 } 837 }
757 838
758 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 839 private void ProcessPostStepTaints()
759 // a callback into itself to do the actual property change. That callback is called
760 // here just before the physics engine is called to step the simulation.
761 public void ProcessTaints()
762 { 840 {
763 if (_taintedObjects.Count > 0) // save allocating new list if there is nothing to process 841 if (_postStepOperations.Count > 0)
764 { 842 {
765 // swizzle a new list into the list location so we can process what's there
766 List<TaintCallbackEntry> oldList; 843 List<TaintCallbackEntry> oldList;
767 lock (_taintLock) 844 lock (_taintLock)
768 { 845 {
769 oldList = _taintedObjects; 846 oldList = _postStepOperations;
770 _taintedObjects = new List<TaintCallbackEntry>(); 847 _postStepOperations = new List<TaintCallbackEntry>();
771 } 848 }
772 849
773 foreach (TaintCallbackEntry tcbe in oldList) 850 foreach (TaintCallbackEntry tcbe in oldList)
774 { 851 {
775 try 852 try
776 { 853 {
854 DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
777 tcbe.callback(); 855 tcbe.callback();
778 } 856 }
779 catch (Exception e) 857 catch (Exception e)
780 { 858 {
781 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e); 859 m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
782 } 860 }
783 } 861 }
784 oldList.Clear(); 862 oldList.Clear();
785 } 863 }
786 } 864 }
787 865
866 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom)
868 {
869 if (!InTaintTime)
870 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
872 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
873 Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
874 }
875 return InTaintTime;
876 }
877
878 #endregion // Taints
879
788 #region Vehicles 880 #region Vehicles
789 881
790 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType) 882 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
791 { 883 {
792 if (newType == Vehicle.TYPE_NONE) 884 RemoveVehiclePrim(vehic);
885 if (newType != Vehicle.TYPE_NONE)
793 { 886 {
794 RemoveVehiclePrim(vehic); 887 // make it so the scene will call us each tick to do vehicle things
795 }
796 else
797 {
798 // make it so the scene will call us each tick to do vehicle things
799 AddVehiclePrim(vehic); 888 AddVehiclePrim(vehic);
800 } 889 }
801 } 890 }
@@ -827,21 +916,22 @@ public class BSScene : PhysicsScene, IPhysicsParameters
827 } 916 }
828 917
829 // Some prims have extra vehicle actions 918 // Some prims have extra vehicle actions
830 // no locking because only called when physics engine is not busy 919 // Called at taint time!
831 private void ProcessVehicles(float timeStep) 920 private void ProcessVehicles(float timeStep)
832 { 921 {
833 foreach (BSPrim prim in m_vehicles) 922 foreach (BSPhysObject pobj in m_vehicles)
834 { 923 {
835 prim.StepVehicle(timeStep); 924 pobj.StepVehicle(timeStep);
836 } 925 }
837 } 926 }
838 #endregion Vehicles 927 #endregion Vehicles
839 928
840 #region Parameters 929 #region INI and command line parameter processing
841 930
842 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val); 931 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
843 delegate float ParamGet(BSScene scene); 932 delegate float ParamGet(BSScene scene);
844 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val); 933 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
934 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
845 935
846 private struct ParameterDefn 936 private struct ParameterDefn
847 { 937 {
@@ -851,6 +941,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
851 public ParamUser userParam; // get the value from the configuration file 941 public ParamUser userParam; // get the value from the configuration file
852 public ParamGet getter; // return the current value stored for this parameter 942 public ParamGet getter; // return the current value stored for this parameter
853 public ParamSet setter; // set the current value for this parameter 943 public ParamSet setter; // set the current value for this parameter
944 public SetOnObject onObject; // set the value on an object in the physical domain
854 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s) 945 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
855 { 946 {
856 name = n; 947 name = n;
@@ -859,6 +950,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
859 userParam = u; 950 userParam = u;
860 getter = g; 951 getter = g;
861 setter = s; 952 setter = s;
953 onObject = null;
954 }
955 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
956 {
957 name = n;
958 desc = d;
959 defaultValue = v;
960 userParam = u;
961 getter = g;
962 setter = s;
963 onObject = o;
862 } 964 }
863 } 965 }
864 966
@@ -869,7 +971,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
869 // getters and setters. 971 // getters and setters.
870 // It is easiest to find an existing definition and copy it. 972 // It is easiest to find an existing definition and copy it.
871 // Parameter values are floats. Booleans are converted to a floating value. 973 // Parameter values are floats. Booleans are converted to a floating value.
872 // 974 //
873 // A ParameterDefn() takes the following parameters: 975 // A ParameterDefn() takes the following parameters:
874 // -- the text name of the parameter. This is used for console input and ini file. 976 // -- the text name of the parameter. This is used for console input and ini file.
875 // -- a short text description of the parameter. This shows up in the console listing. 977 // -- a short text description of the parameter. This shows up in the console listing.
@@ -880,6 +982,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
880 // 982 //
881 // The single letter parameters for the delegates are: 983 // The single letter parameters for the delegates are:
882 // s = BSScene 984 // s = BSScene
985 // o = BSPhysObject
883 // p = string parameter name 986 // p = string parameter name
884 // l = localID of referenced object 987 // l = localID of referenced object
885 // v = float value 988 // v = float value
@@ -888,25 +991,40 @@ public class BSScene : PhysicsScene, IPhysicsParameters
888 { 991 {
889 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", 992 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
890 ConfigurationParameters.numericTrue, 993 ConfigurationParameters.numericTrue,
891 (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, 994 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
892 (s) => { return s.NumericBool(s._meshSculptedPrim); }, 995 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
893 (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), 996 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
894 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", 997 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
895 ConfigurationParameters.numericFalse, 998 ConfigurationParameters.numericFalse,
896 (s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, 999 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
897 (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, 1000 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
898 (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), 1001 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
1002 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
1003 ConfigurationParameters.numericTrue,
1004 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
1005 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
1006 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
899 1007
900 new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 1008 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
901 8f, 1009 8f,
902 (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); }, 1010 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
903 (s) => { return (float)s.m_meshLOD; }, 1011 (s) => { return s.MeshLOD; },
904 (s,p,l,v) => { s.m_meshLOD = (int)v; } ), 1012 (s,p,l,v) => { s.MeshLOD = v; } ),
905 new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", 1013 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
1014 16f,
1015 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
1016 (s) => { return s.MeshMegaPrimLOD; },
1017 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
1018 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
1019 10f,
1020 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
1021 (s) => { return s.MeshMegaPrimThreshold; },
1022 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
1023 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
906 32f, 1024 32f,
907 (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); }, 1025 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
908 (s) => { return (float)s.m_sculptLOD; }, 1026 (s) => { return s.SculptLOD; },
909 (s,p,l,v) => { s.m_sculptLOD = (int)v; } ), 1027 (s,p,l,v) => { s.SculptLOD = v; } ),
910 1028
911 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", 1029 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
912 10f, 1030 10f,
@@ -928,11 +1046,16 @@ public class BSScene : PhysicsScene, IPhysicsParameters
928 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); }, 1046 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
929 (s) => { return (float)s.m_maxUpdatesPerFrame; }, 1047 (s) => { return (float)s.m_maxUpdatesPerFrame; },
930 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), 1048 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
1049 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
1050 500f,
1051 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
1052 (s) => { return (float)s.m_taintsToProcessPerStep; },
1053 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
931 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", 1054 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
932 10000.01f, 1055 10000.01f,
933 (s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); }, 1056 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
934 (s) => { return (float)s.m_maximumObjectMass; }, 1057 (s) => { return (float)s.MaximumObjectMass; },
935 (s,p,l,v) => { s.m_maximumObjectMass = v; } ), 1058 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
936 1059
937 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", 1060 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
938 2200f, 1061 2200f,
@@ -969,104 +1092,128 @@ public class BSScene : PhysicsScene, IPhysicsParameters
969 -9.80665f, 1092 -9.80665f,
970 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); }, 1093 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
971 (s) => { return s.m_params[0].gravity; }, 1094 (s) => { return s.m_params[0].gravity; },
972 (s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ), 1095 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
1096 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
973 1097
974 1098
975 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", 1099 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
976 0f, 1100 0f,
977 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); }, 1101 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
978 (s) => { return s.m_params[0].linearDamping; }, 1102 (s) => { return s.m_params[0].linearDamping; },
979 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ), 1103 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
1104 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
980 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", 1105 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
981 0f, 1106 0f,
982 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); }, 1107 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
983 (s) => { return s.m_params[0].angularDamping; }, 1108 (s) => { return s.m_params[0].angularDamping; },
984 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ), 1109 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
1110 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
985 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", 1111 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
986 0.2f, 1112 0.2f,
987 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); }, 1113 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
988 (s) => { return s.m_params[0].deactivationTime; }, 1114 (s) => { return s.m_params[0].deactivationTime; },
989 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ), 1115 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
1116 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
990 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", 1117 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
991 0.8f, 1118 0.8f,
992 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); }, 1119 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
993 (s) => { return s.m_params[0].linearSleepingThreshold; }, 1120 (s) => { return s.m_params[0].linearSleepingThreshold; },
994 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ), 1121 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
1122 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
995 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", 1123 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
996 1.0f, 1124 1.0f,
997 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); }, 1125 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
998 (s) => { return s.m_params[0].angularSleepingThreshold; }, 1126 (s) => { return s.m_params[0].angularSleepingThreshold; },
999 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ), 1127 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
1128 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
1000 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , 1129 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1001 0f, // set to zero to disable 1130 0f, // set to zero to disable
1002 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); }, 1131 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1003 (s) => { return s.m_params[0].ccdMotionThreshold; }, 1132 (s) => { return s.m_params[0].ccdMotionThreshold; },
1004 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ), 1133 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1134 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
1005 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , 1135 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1006 0f, 1136 0f,
1007 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); }, 1137 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1008 (s) => { return s.m_params[0].ccdSweptSphereRadius; }, 1138 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1009 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ), 1139 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1140 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
1010 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" , 1141 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1011 0.1f, 1142 0.1f,
1012 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); }, 1143 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1013 (s) => { return s.m_params[0].contactProcessingThreshold; }, 1144 (s) => { return s.m_params[0].contactProcessingThreshold; },
1014 (s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ), 1145 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1015 1146 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1147
1148 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
1149 (float)BSTerrainPhys.TerrainImplementation.Mesh,
1150 (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
1151 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1016 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1017 0.5f, 1154 0.5f,
1018 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, 1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1019 (s) => { return s.m_params[0].terrainFriction; }, 1156 (s) => { return s.m_params[0].terrainFriction; },
1020 (s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ), 1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
1021 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , 1158 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
1022 0.8f, 1159 0.8f,
1023 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); }, 1160 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
1024 (s) => { return s.m_params[0].terrainHitFraction; }, 1161 (s) => { return s.m_params[0].terrainHitFraction; },
1025 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ), 1162 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
1026 new ParameterDefn("TerrainRestitution", "Bouncyness" , 1163 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
1027 0f, 1164 0f,
1028 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, 1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1029 (s) => { return s.m_params[0].terrainRestitution; }, 1166 (s) => { return s.m_params[0].terrainRestitution; },
1030 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ), 1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1031 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1032 0.5f, 1169 0.2f,
1033 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, 1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1034 (s) => { return s.m_params[0].avatarFriction; }, 1171 (s) => { return s.m_params[0].avatarFriction; },
1035 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ), 1172 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1173 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1174 10f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
1036 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", 1178 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1037 60f, 1179 60f,
1038 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); }, 1180 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1039 (s) => { return s.m_params[0].avatarDensity; }, 1181 (s) => { return s.m_params[0].avatarDensity; },
1040 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ), 1182 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1041 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", 1183 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1042 0f, 1184 0f,
1043 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); }, 1185 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1044 (s) => { return s.m_params[0].avatarRestitution; }, 1186 (s) => { return s.m_params[0].avatarRestitution; },
1045 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ), 1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1046 new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar", 1188 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
1047 0.37f, 1189 0.6f,
1048 (s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); }, 1190 (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
1049 (s) => { return s.m_params[0].avatarCapsuleRadius; }, 1191 (s) => { return s.m_params[0].avatarCapsuleWidth; },
1050 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ), 1192 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
1193 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
1194 0.45f,
1195 (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
1196 (s) => { return s.m_params[0].avatarCapsuleDepth; },
1197 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
1051 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", 1198 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1052 1.5f, 1199 1.5f,
1053 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); }, 1200 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1054 (s) => { return s.m_params[0].avatarCapsuleHeight; }, 1201 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1055 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ), 1202 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1056 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", 1203 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1057 0.1f, 1204 0.1f,
1058 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); }, 1205 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1059 (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, 1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1060 (s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), 1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1061 1208
1062 1209
1063 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1064 0f, // zero to disable 1211 0f,
1065 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); }, 1212 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1066 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; }, 1213 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1067 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ), 1214 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1068 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", 1215 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1069 0f, // zero to disable 1216 0f,
1070 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); }, 1217 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1071 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; }, 1218 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1072 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ), 1219 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
@@ -1081,12 +1228,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1081 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; }, 1228 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1082 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ), 1229 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1083 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", 1230 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1084 ConfigurationParameters.numericFalse, 1231 ConfigurationParameters.numericTrue,
1085 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1232 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1086 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; }, 1233 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1087 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ), 1234 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1088 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", 1235 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1089 ConfigurationParameters.numericFalse, 1236 ConfigurationParameters.numericTrue,
1090 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1237 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1091 (s) => { return s.m_params[0].shouldSplitSimulationIslands; }, 1238 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1092 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ), 1239 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
@@ -1101,6 +1248,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1101 (s) => { return s.m_params[0].numberOfSolverIterations; }, 1248 (s) => { return s.m_params[0].numberOfSolverIterations; },
1102 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), 1249 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1103 1250
1251 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1252 (float)BSLinkset.LinksetImplementation.Compound,
1253 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1254 (s) => { return s.m_params[0].linksetImplementation; },
1255 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
1104 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", 1256 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1105 ConfigurationParameters.numericFalse, 1257 ConfigurationParameters.numericFalse,
1106 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); }, 1258 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
@@ -1121,28 +1273,27 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1121 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); }, 1273 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1122 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; }, 1274 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1123 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ), 1275 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1124 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=none, 1=all. Default=0", 1276 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1125 0.0f, 1277 0.1f,
1126 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); }, 1278 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1127 (s) => { return s.m_params[0].linkConstraintCFM; }, 1279 (s) => { return s.m_params[0].linkConstraintCFM; },
1128 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ), 1280 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1129 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", 1281 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1130 0.2f, 1282 0.1f,
1131 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); }, 1283 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].linkConstraintERP; }, 1284 (s) => { return s.m_params[0].linkConstraintERP; },
1133 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ), 1285 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1286 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1287 40,
1288 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1289 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1290 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1134 1291
1135 new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 1292 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1136 0f, 1293 0f,
1137 (s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); }, 1294 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1138 (s) => { return (float)s.m_detailedStatsStep; }, 1295 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1139 (s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ), 1296 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1140 new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
1141 ConfigurationParameters.numericFalse,
1142 (s,cf,p,v) => { s.ShouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
1143 (s) => { return s.NumericBool(s.ShouldDebugLog); },
1144 (s,p,l,v) => { s.ShouldDebugLog = s.BoolNumeric(v); } ),
1145
1146 }; 1297 };
1147 1298
1148 // Convert a boolean to our numeric true and false values 1299 // Convert a boolean to our numeric true and false values
@@ -1200,11 +1351,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1200 1351
1201 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; 1352 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1202 1353
1354 // This creates an array in the correct format for returning the list of
1355 // parameters. This is used by the 'list' option of the 'physics' command.
1203 private void BuildParameterTable() 1356 private void BuildParameterTable()
1204 { 1357 {
1205 if (SettableParameters.Length < ParameterDefinitions.Length) 1358 if (SettableParameters.Length < ParameterDefinitions.Length)
1206 { 1359 {
1207
1208 List<PhysParameterEntry> entries = new List<PhysParameterEntry>(); 1360 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1209 for (int ii = 0; ii < ParameterDefinitions.Length; ii++) 1361 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1210 { 1362 {
@@ -1249,60 +1401,54 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1249 return ret; 1401 return ret;
1250 } 1402 }
1251 1403
1252 // check to see if we are updating a parameter for a particular or all of the prims
1253 protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
1254 {
1255 List<uint> operateOn;
1256 lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
1257 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1258 }
1259
1260 // check to see if we are updating a parameter for a particular or all of the avatars
1261 protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
1262 {
1263 List<uint> operateOn;
1264 lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
1265 UpdateParameterSet(operateOn, ref loc, parm, localID, val);
1266 }
1267
1268 // update all the localIDs specified 1404 // update all the localIDs specified
1269 // If the local ID is APPLY_TO_NONE, just change the default value 1405 // If the local ID is APPLY_TO_NONE, just change the default value
1270 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 1406 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1271 // If the localID is a specific object, apply the parameter change to only that object 1407 // If the localID is a specific object, apply the parameter change to only that object
1272 protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) 1408 private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
1273 { 1409 {
1410 List<uint> objectIDs = new List<uint>();
1274 switch (localID) 1411 switch (localID)
1275 { 1412 {
1276 case PhysParameterEntry.APPLY_TO_NONE: 1413 case PhysParameterEntry.APPLY_TO_NONE:
1277 defaultLoc = val; // setting only the default value 1414 defaultLoc = val; // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val);
1278 break; 1418 break;
1279 case PhysParameterEntry.APPLY_TO_ALL: 1419 case PhysParameterEntry.APPLY_TO_ALL:
1280 defaultLoc = val; // setting ALL also sets the default value 1420 defaultLoc = val; // setting ALL also sets the default value
1281 List<uint> objectIDs = lIDs; 1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1282 string xparm = parm.ToLower(); 1422 TaintedUpdateParameter(parm, objectIDs, val);
1283 float xval = val;
1284 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1285 foreach (uint lID in objectIDs)
1286 {
1287 BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
1288 }
1289 });
1290 break; 1423 break;
1291 default: 1424 default:
1292 // setting only one localID 1425 // setting only one localID
1293 TaintedUpdateParameter(parm, localID, val); 1426 objectIDs.Add(localID);
1427 TaintedUpdateParameter(parm, objectIDs, val);
1294 break; 1428 break;
1295 } 1429 }
1296 } 1430 }
1297 1431
1298 // schedule the actual updating of the paramter to when the phys engine is not busy 1432 // schedule the actual updating of the paramter to when the phys engine is not busy
1299 protected void TaintedUpdateParameter(string parm, uint localID, float val) 1433 private void TaintedUpdateParameter(string parm, List<uint> lIDs, float val)
1300 { 1434 {
1301 uint xlocalID = localID;
1302 string xparm = parm.ToLower();
1303 float xval = val; 1435 float xval = val;
1304 TaintedObject("BSScene.TaintedUpdateParameter", delegate() { 1436 List<uint> xlIDs = lIDs;
1305 BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval); 1437 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam;
1440 if (TryGetParameter(xparm, out thisParam))
1441 {
1442 if (thisParam.onObject != null)
1443 {
1444 foreach (uint lID in xlIDs)
1445 {
1446 BSPhysObject theObject = null;
1447 PhysObjects.TryGetValue(lID, out theObject);
1448 thisParam.onObject(this, theObject, xval);
1449 }
1450 }
1451 }
1306 }); 1452 });
1307 } 1453 }
1308 1454
@@ -1326,12 +1472,24 @@ public class BSScene : PhysicsScene, IPhysicsParameters
1326 1472
1327 #endregion Runtime settable parameters 1473 #endregion Runtime settable parameters
1328 1474
1475 // Debugging routine for dumping detailed physical information for vehicle prims
1476 private void DumpVehicles()
1477 {
1478 foreach (BSPrim prim in m_vehicles)
1479 {
1480 BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
1481 BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
1482 }
1483 }
1484
1329 // Invoke the detailed logger and output something if it's enabled. 1485 // Invoke the detailed logger and output something if it's enabled.
1330 public void DetailLog(string msg, params Object[] args) 1486 public void DetailLog(string msg, params Object[] args)
1331 { 1487 {
1332 PhysicsLogging.Write(msg, args); 1488 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush();
1333 } 1491 }
1334 // used to fill in the LocalID when there isn't one 1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1335 public const string DetailLogZero = "0000000000"; 1493 public const string DetailLogZero = "0000000000";
1336 1494
1337} 1495}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
new file mode 100755
index 0000000..892c34b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -0,0 +1,1001 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Physics.Manager;
33using OpenSim.Region.Physics.ConvexDecompositionDotNet;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public sealed class BSShapeCollection : IDisposable
38{
39 private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]";
40
41 private BSScene PhysicsScene { get; set; }
42
43 private Object m_collectionActivityLock = new Object();
44
45 // Description of a Mesh
46 private struct MeshDesc
47 {
48 public IntPtr ptr;
49 public int referenceCount;
50 public DateTime lastReferenced;
51 public UInt64 shapeKey;
52 }
53
54 // Description of a hull.
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc
57 {
58 public IntPtr ptr;
59 public int referenceCount;
60 public DateTime lastReferenced;
61 public UInt64 shapeKey;
62 }
63
64 // The sharable set of meshes and hulls. Indexed by their shape hash.
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67
68 public BSShapeCollection(BSScene physScene)
69 {
70 PhysicsScene = physScene;
71 }
72
73 public void Dispose()
74 {
75 // TODO!!!!!!!!!
76 }
77
78 // Callbacks called just before either the body or shape is destroyed.
79 // Mostly used for changing bodies out from under Linksets.
80 // Useful for other cases where parameters need saving.
81 // Passing 'null' says no callback.
82 public delegate void ShapeDestructionCallback(BulletShape shape);
83 public delegate void BodyDestructionCallback(BulletBody body);
84
85 // Called to update/change the body and shape for an object.
86 // First checks the shape and updates that if necessary then makes
87 // sure the body is of the right type.
88 // Return 'true' if either the body or the shape changed.
89 // 'shapeCallback' and 'bodyCallback' are, if non-null, functions called just before
90 // the current shape or body is destroyed. This allows the caller to remove any
91 // higher level dependencies on the shape or body. Mostly used for LinkSets to
92 // remove the physical constraints before the body is destroyed.
93 // Called at taint-time!!
94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
96 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
98
99 bool ret = false;
100
101 // This lock could probably be pushed down lower but building shouldn't take long
102 lock (m_collectionActivityLock)
103 {
104 // Do we have the correct geometry for this type of object?
105 // Updates prim.BSShape with information/pointers to shape.
106 // Returns 'true' of BSShape is changed to a new shape.
107 bool newGeom = CreateGeom(forceRebuild, prim, shapeCallback);
108 // If we had to select a new shape geometry for the object,
109 // rebuild the body around it.
110 // Updates prim.BSBody with information/pointers to requested body
111 // Returns 'true' if BSBody was changed.
112 bool newBody = CreateBody((newGeom || forceRebuild), prim, PhysicsScene.World,
113 prim.PhysShape, bodyCallback);
114 ret = newGeom || newBody;
115 }
116 DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
117 prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);
118
119 return ret;
120 }
121
122 // Track another user of a body.
123 // We presume the caller has allocated the body.
124 // Bodies only have one user so the body is just put into the world if not already there.
125 public void ReferenceBody(BulletBody body, bool inTaintTime)
126 {
127 lock (m_collectionActivityLock)
128 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
131 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr))
133 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 }
137 });
138 }
139 }
140
141 // Release the usage of a body.
142 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
144 {
145 if (body.ptr == IntPtr.Zero)
146 return;
147
148 lock (m_collectionActivityLock)
149 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body);
156
157 if (BulletSimAPI.IsInWorld2(body.ptr))
158 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 }
162
163 // Zero any reference to the shape so it is not freed when the body is deleted.
164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
166 });
167 }
168 }
169
170 // Track the datastructures and use count for a shape.
171 // When creating a hull, this is called first to reference the mesh
172 // and then again to reference the hull.
173 // Meshes and hulls for the same shape have the same hash key.
174 // NOTE that native shapes are not added to the mesh list or removed.
175 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
176 public bool ReferenceShape(BulletShape shape)
177 {
178 bool ret = false;
179 switch (shape.type)
180 {
181 case BSPhysicsShapeType.SHAPE_MESH:
182 MeshDesc meshDesc;
183 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
184 {
185 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 }
190 else
191 {
192 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr;
194 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true;
200 }
201 meshDesc.lastReferenced = System.DateTime.Now;
202 Meshes[shape.shapeKey] = meshDesc;
203 break;
204 case BSPhysicsShapeType.SHAPE_HULL:
205 HullDesc hullDesc;
206 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
207 {
208 // There is an existing instance of this hull.
209 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 }
213 else
214 {
215 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr;
217 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true;
222
223 }
224 hullDesc.lastReferenced = System.DateTime.Now;
225 Hulls[shape.shapeKey] = hullDesc;
226 break;
227 case BSPhysicsShapeType.SHAPE_UNKNOWN:
228 break;
229 default:
230 // Native shapes are not tracked and they don't go into any list
231 break;
232 }
233 return ret;
234 }
235
236 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
238 {
239 if (shape.ptr == IntPtr.Zero)
240 return;
241
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 {
244 if (shape.ptr != IntPtr.Zero)
245 {
246 if (shape.isNativeShape)
247 {
248 // Native shapes are not tracked and are released immediately
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)
257 {
258 case BSPhysicsShapeType.SHAPE_HULL:
259 DereferenceHull(shape, shapeCallback);
260 break;
261 case BSPhysicsShapeType.SHAPE_MESH:
262 DereferenceMesh(shape, shapeCallback);
263 break;
264 case BSPhysicsShapeType.SHAPE_COMPOUND:
265 DereferenceCompound(shape, shapeCallback);
266 break;
267 case BSPhysicsShapeType.SHAPE_UNKNOWN:
268 break;
269 default:
270 break;
271 }
272 }
273 }
274 });
275 }
276
277 // Count down the reference count for a mesh shape
278 // Called at taint-time.
279 private void DereferenceMesh(BulletShape shape, ShapeDestructionCallback shapeCallback)
280 {
281 MeshDesc meshDesc;
282 if (Meshes.TryGetValue(shape.shapeKey, out meshDesc))
283 {
284 meshDesc.referenceCount--;
285 // TODO: release the Bullet storage
286 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291
292 }
293 }
294
295 // Count down the reference count for a hull shape
296 // Called at taint-time.
297 private void DereferenceHull(BulletShape shape, ShapeDestructionCallback shapeCallback)
298 {
299 HullDesc hullDesc;
300 if (Hulls.TryGetValue(shape.shapeKey, out hullDesc))
301 {
302 hullDesc.referenceCount--;
303 // TODO: release the Bullet storage (aging old entries?)
304
305 // Tell upper layers that, if they have dependencies on this shape, this link is going away
306 if (shapeCallback != null) shapeCallback(shape);
307
308 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 }
313 }
314
315 // Remove a reference to a compound shape.
316 // Taking a compound shape apart is a little tricky because if you just delete the
317 // physical shape, it will free all the underlying children. We can't do that because
318 // they could be shared. So, this removes each of the children from the compound and
319 // dereferences them separately before destroying the compound collision object itself.
320 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr))
324 {
325 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X"));
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
330 return;
331 }
332
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335
336 for (int ii = numChildren - 1; ii >= 0; ii--)
337 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
339 DereferenceAnonCollisionShape(childShape);
340 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr);
342 }
343
344 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine.
346 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape)
348 {
349 MeshDesc meshDesc;
350 HullDesc hullDesc;
351
352 BulletShape shapeInfo = new BulletShape(cShape);
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey;
357 }
358 else
359 {
360 if (TryGetHullByPtr(cShape, out hullDesc))
361 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey;
364 }
365 else
366 {
367 if (BulletSimAPI.IsCompound2(cShape))
368 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 }
371 else
372 {
373 if (BulletSimAPI.IsNativeShape2(cShape))
374 {
375 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
377 }
378 }
379 }
380 }
381
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 {
386 DereferenceShape(shapeInfo, true, null);
387 }
388 else
389 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X"));
392 }
393 }
394
395 // Create the geometry information in Bullet for later use.
396 // The objects needs a hull if it's physical otherwise a mesh is enough.
397 // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
398 // shared geometries will be used. If the parameters of the existing shape are the same
399 // as this request, the shape is not rebuilt.
400 // Info in prim.BSShape is updated to the new shape.
401 // Returns 'true' if the geometry was rebuilt.
402 // Called at taint-time!
403 private bool CreateGeom(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
404 {
405 bool ret = false;
406 bool haveShape = false;
407
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 {
410 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE,
412 FixedShapeKey.KEY_CAPSULE, shapeCallback);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true;
415 haveShape = true;
416 }
417
418 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true;
425 }
426
427 if (!haveShape)
428 {
429 ret = CreateGeomNonSpecial(forceRebuild, prim, shapeCallback);
430 }
431
432 return ret;
433 }
434
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 {
438 bool ret = false;
439 bool haveShape = false;
440 bool nativeShapePossible = true;
441 PrimitiveBaseShape pbs = prim.BaseShape;
442
443 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape
445 && pbs != null
446 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
449 && pbs.ProfileHollow == 0
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
451 && pbs.PathBegin == 0 && pbs.PathEnd == 0
452 && pbs.PathTaperX == 0 && pbs.PathTaperY == 0
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 {
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 {
460 haveShape = true;
461 if (forceRebuild
462 || prim.Scale != prim.Size
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 )
465 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape);
470 }
471 }
472 if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
473 {
474 haveShape = true;
475 if (forceRebuild
476 || prim.Scale != prim.Size
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 )
479 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape);
484 }
485 }
486 }
487
488 // If a simple shape is not happening, create a mesh and possibly a hull.
489 if (!haveShape && pbs != null)
490 {
491 ret = CreateGeomMeshOrHull(prim, shapeCallback);
492 }
493
494 return ret;
495 }
496
497 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
498 {
499
500 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
504 {
505 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 }
510 else
511 {
512 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 }
516 return ret;
517 }
518
519 // Creates a native shape and assignes it to prim.BSShape.
520 // "Native" shapes are never shared. they are created here and destroyed in DereferenceShape().
521 private bool GetReferenceToNativeShape(BSPhysObject prim,
522 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey,
523 ShapeDestructionCallback shapeCallback)
524 {
525 // release any previous shape
526 DereferenceShape(prim.PhysShape, true, shapeCallback);
527
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale);
533
534 prim.PhysShape = newShape;
535 return true;
536 }
537
538 private BulletShape BuildPhysicalNativeShape(BSPhysObject prim, BSPhysicsShapeType shapeType,
539 FixedShapeKey shapeKey)
540 {
541 BulletShape newShape;
542 // Need to make sure the passed shape information is for the native type.
543 ShapeData nativeShapeData = new ShapeData();
544 nativeShapeData.Type = shapeType;
545 nativeShapeData.ID = prim.LocalID;
546 nativeShapeData.Scale = prim.Scale;
547 nativeShapeData.Size = prim.Scale; // unneeded, I think.
548 nativeShapeData.MeshKey = (ulong)shapeKey;
549 nativeShapeData.HullKey = (ulong)shapeKey;
550
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 {
553 // The proper scale has been calculated in the prim.
554 newShape = new BulletShape(
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale)
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 }
559 else
560 {
561 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size;
563 nativeShapeData.Scale = prim.Scale;
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 }
566 if (newShape.ptr == IntPtr.Zero)
567 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType);
570 }
571 newShape.shapeKey = (System.UInt64)shapeKey;
572 newShape.isNativeShape = true;
573
574 return newShape;
575 }
576
577 // Builds a mesh shape in the physical world and updates prim.BSShape.
578 // Dereferences previous shape in BSShape and adds a reference for this new shape.
579 // Returns 'true' of a mesh was actually built. Otherwise .
580 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero);
584
585 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
587
588 // if this new shape is the same as last time, don't recreate the mesh
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false;
591
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594
595 // Since we're recreating new, get rid of the reference to the previous shape
596 DereferenceShape(prim.PhysShape, true, shapeCallback);
597
598 newShape = CreatePhysicalMesh(prim.PhysObjectName, newMeshKey, prim.BaseShape, prim.Size, lod);
599 // Take evasive action if the mesh was not constructed.
600 newShape = VerifyMeshCreated(newShape, prim);
601
602 ReferenceShape(newShape);
603
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape;
607
608 return true; // 'true' means a new shape has been added to this prim
609 }
610
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 {
613 IMesh meshData = null;
614 IntPtr meshPtr = IntPtr.Zero;
615 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 {
618 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr;
620 }
621 else
622 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625
626 if (meshData != null)
627 {
628 int[] indices = meshData.getIndexListAsInt();
629 List<OMV.Vector3> vertices = meshData.getVertexList();
630
631 float[] verticesAsFloats = new float[vertices.Count * 3];
632 int vi = 0;
633 foreach (OMV.Vector3 vv in vertices)
634 {
635 verticesAsFloats[vi++] = vv.X;
636 verticesAsFloats[vi++] = vv.Y;
637 verticesAsFloats[vi++] = vv.Z;
638 }
639
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
642
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
645 }
646 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey;
649
650 return newShape;
651 }
652
653 // See that hull shape exists in the physical world and update prim.BSShape.
654 // We could be creating the hull because scale changed or whatever.
655 private bool GetReferenceToHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
656 {
657 BulletShape newShape;
658
659 float lod;
660 System.UInt64 newHullKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
661
662 // if the hull hasn't changed, don't rebuild it
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false;
665
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668
669 // Remove usage of the previous shape.
670 DereferenceShape(prim.PhysShape, true, shapeCallback);
671
672 newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, prim.BaseShape, prim.Size, lod);
673 newShape = VerifyMeshCreated(newShape, prim);
674
675 ReferenceShape(newShape);
676
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim
681 }
682
683 List<ConvexResult> m_hulls;
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 {
686
687 IntPtr hullPtr = IntPtr.Zero;
688 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 {
691 // If the hull shape already is created, just use it.
692 hullPtr = hullDesc.ptr;
693 }
694 else
695 {
696 // Build a new hull in the physical world
697 // Pass false for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
699 if (meshData != null)
700 {
701
702 int[] indices = meshData.getIndexListAsInt();
703 List<OMV.Vector3> vertices = meshData.getVertexList();
704
705 //format conversion from IMesh format to DecompDesc format
706 List<int> convIndices = new List<int>();
707 List<float3> convVertices = new List<float3>();
708 for (int ii = 0; ii < indices.GetLength(0); ii++)
709 {
710 convIndices.Add(indices[ii]);
711 }
712 foreach (OMV.Vector3 vv in vertices)
713 {
714 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
715 }
716
717 // setup and do convex hull conversion
718 m_hulls = new List<ConvexResult>();
719 DecompDesc dcomp = new DecompDesc();
720 dcomp.mIndices = convIndices;
721 dcomp.mVertices = convVertices;
722 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
723 // create the hull into the _hulls variable
724 convexBuilder.process(dcomp);
725
726 // Convert the vertices and indices for passing to unmanaged.
727 // The hull information is passed as a large floating point array.
728 // The format is:
729 // convHulls[0] = number of hulls
730 // convHulls[1] = number of vertices in first hull
731 // convHulls[2] = hull centroid X coordinate
732 // convHulls[3] = hull centroid Y coordinate
733 // convHulls[4] = hull centroid Z coordinate
734 // convHulls[5] = first hull vertex X
735 // convHulls[6] = first hull vertex Y
736 // convHulls[7] = first hull vertex Z
737 // convHulls[8] = second hull vertex X
738 // ...
739 // convHulls[n] = number of vertices in second hull
740 // convHulls[n+1] = second hull centroid X coordinate
741 // ...
742 //
743 // TODO: is is very inefficient. Someday change the convex hull generator to return
744 // data structures that do not need to be converted in order to pass to Bullet.
745 // And maybe put the values directly into pinned memory rather than marshaling.
746 int hullCount = m_hulls.Count;
747 int totalVertices = 1; // include one for the count of the hulls
748 foreach (ConvexResult cr in m_hulls)
749 {
750 totalVertices += 4; // add four for the vertex count and centroid
751 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
752 }
753 float[] convHulls = new float[totalVertices];
754
755 convHulls[0] = (float)hullCount;
756 int jj = 1;
757 foreach (ConvexResult cr in m_hulls)
758 {
759 // copy vertices for index access
760 float3[] verts = new float3[cr.HullVertices.Count];
761 int kk = 0;
762 foreach (float3 ff in cr.HullVertices)
763 {
764 verts[kk++] = ff;
765 }
766
767 // add to the array one hull's worth of data
768 convHulls[jj++] = cr.HullIndices.Count;
769 convHulls[jj++] = 0f; // centroid x,y,z
770 convHulls[jj++] = 0f;
771 convHulls[jj++] = 0f;
772 foreach (int ind in cr.HullIndices)
773 {
774 convHulls[jj++] = verts[ind].x;
775 convHulls[jj++] = verts[ind].y;
776 convHulls[jj++] = verts[ind].z;
777 }
778 }
779 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls);
781 }
782 }
783
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey;
786
787 return newShape; // 'true' means a new shape has been added to this prim
788 }
789
790 // Callback from convex hull creater with a newly created hull.
791 // Just add it to our collection of hulls for this shape.
792 private void HullReturn(ConvexResult result)
793 {
794 m_hulls.Add(result);
795 return;
796 }
797
798 // Compound shapes are always built from scratch.
799 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
800 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
801 {
802 // Remove reference to the old shape
803 // Don't need to do this as the shape is freed when the new root shape is created below.
804 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805
806 BulletShape cShape = new BulletShape(
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND);
808
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape);
814
815 prim.PhysShape = cShape;
816
817 return true;
818 }
819
820 // Create a hash of all the shape parameters to be used as a key
821 // for this particular shape.
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 {
824 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD;
826 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD;
828
829 // Mega prims usually get more detail because one can interact with shape approximations at this size.
830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD;
833
834 retLod = lod;
835 return pbs.GetMeshKey(size, lod);
836 }
837 // For those who don't want the LOD
838 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs)
839 {
840 float lod;
841 return ComputeShapeKey(size, pbs, out lod);
842 }
843
844 // The creation of a mesh or hull can fail if an underlying asset is not available.
845 // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
846 // and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
847 // The first case causes the asset to be fetched. The second case requires
848 // us to not loop forever.
849 // Called after creating a physical mesh or hull. If the physical shape was created,
850 // just return.
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 {
853 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero)
855 return newShape;
856
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
858 if (prim.BaseShape.SculptEntry && !prim.LastAssetBuildFailed && prim.BaseShape.SculptTexture != OMV.UUID.Zero)
859 {
860 prim.LastAssetBuildFailed = true;
861 BSPhysObject xprim = prim;
862 DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset,lID={1},lastFailed={2}",
863 LogHeader, prim.LocalID, prim.LastAssetBuildFailed);
864 Util.FireAndForget(delegate
865 {
866 RequestAssetDelegate assetProvider = PhysicsScene.RequestAssetMethod;
867 if (assetProvider != null)
868 {
869 BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
870 assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
871 {
872 if (!yprim.BaseShape.SculptEntry)
873 return;
874 if (yprim.BaseShape.SculptTexture.ToString() != asset.ID)
875 return;
876
877 yprim.BaseShape.SculptData = asset.Data;
878 // This will cause the prim to see that the filler shape is not the right
879 // one and try again to build the object.
880 // No race condition with the normal shape setting since the rebuild is at taint time.
881 yprim.ForceBodyShapeRebuild(false);
882
883 });
884 }
885 });
886 }
887 else
888 {
889 if (prim.LastAssetBuildFailed)
890 {
891 PhysicsScene.Logger.ErrorFormat("{0} Mesh failed to fetch asset. lID={1}, texture={2}",
892 LogHeader, prim.LocalID, prim.BaseShape.SculptTexture);
893 }
894 }
895
896 // While we figure out the real problem, stick a simple native shape on the object.
897 BulletShape fillinShape =
898 BuildPhysicalNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
899
900 return fillinShape;
901 }
902
903 // Create a body object in Bullet.
904 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created.
906 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape,
908 BodyDestructionCallback bodyCallback)
909 {
910 bool ret = false;
911
912 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero);
914
915 // If there is an existing body, verify it's of an acceptable type.
916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild)
918 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 {
923 // If the collisionObject is not the correct type for solidness, rebuild what's there
924 mustRebuild = true;
925 }
926 }
927
928 if (mustRebuild || forceRebuild)
929 {
930 // Free any old body
931 DereferenceBody(prim.PhysBody, true, bodyCallback);
932
933 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid)
936 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
938 prim.LocalID, prim.RawPosition, prim.RawOrientation);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 }
941 else
942 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
944 prim.LocalID, prim.RawPosition, prim.RawOrientation);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948
949 ReferenceBody(aBody, true);
950
951 prim.PhysBody = aBody;
952
953 ret = true;
954 }
955
956 return ret;
957 }
958
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc)
960 {
961 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values)
964 {
965 if (md.ptr == addr)
966 {
967 foundDesc = md;
968 ret = true;
969 break;
970 }
971
972 }
973 outDesc = foundDesc;
974 return ret;
975 }
976
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc)
978 {
979 bool ret = false;
980 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values)
982 {
983 if (hd.ptr == addr)
984 {
985 foundDesc = hd;
986 ret = true;
987 break;
988 }
989
990 }
991 outDesc = foundDesc;
992 return ret;
993 }
994
995 private void DetailLog(string msg, params Object[] args)
996 {
997 if (PhysicsScene.PhysicsLogging.Enabled)
998 PhysicsScene.DetailLog(msg, args);
999 }
1000}
1001}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
new file mode 100755
index 0000000..96cd55e
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -0,0 +1,208 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public abstract class BSShape
36{
37 public IntPtr ptr { get; set; }
38 public BSPhysicsShapeType type { get; set; }
39 public System.UInt64 key { get; set; }
40 public int referenceCount { get; set; }
41 public DateTime lastReferenced { get; set; }
42
43 public BSShape()
44 {
45 ptr = IntPtr.Zero;
46 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
47 key = 0;
48 referenceCount = 0;
49 lastReferenced = DateTime.Now;
50 }
51
52 // Get a reference to a physical shape. Create if it doesn't exist
53 public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
54 {
55 BSShape ret = null;
56
57 if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
58 {
59 // an avatar capsule is close to a native shape (it is not shared)
60 ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
61 FixedShapeKey.KEY_CAPSULE);
62 physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
63 }
64
65 // Compound shapes are handled special as they are rebuilt from scratch.
66 // This isn't too great a hardship since most of the child shapes will already been created.
67 if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
68 {
69 // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
70 ret = BSShapeCompound.GetReference(prim);
71 physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
72 }
73
74 if (ret == null)
75 ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
76
77 return ret;
78 }
79 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
80 {
81 return null;
82 }
83 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
84 {
85 return null;
86 }
87
88 // Release the use of a physical shape.
89 public abstract void Dereference(BSScene physicsScene);
90
91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference();
93
94 public override string ToString()
95 {
96 StringBuilder buff = new StringBuilder();
97 buff.Append("<p=");
98 buff.Append(ptr.ToString("X"));
99 buff.Append(",s=");
100 buff.Append(type.ToString());
101 buff.Append(",k=");
102 buff.Append(key.ToString("X"));
103 buff.Append(",c=");
104 buff.Append(referenceCount.ToString());
105 buff.Append(">");
106 return buff.ToString();
107 }
108}
109
110public class BSShapeNull : BSShape
111{
112 public BSShapeNull() : base()
113 {
114 }
115 public static BSShape GetReference() { return new BSShapeNull(); }
116 public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ }
117}
118
119public class BSShapeNative : BSShape
120{
121 private static string LogHeader = "[BULLETSIM SHAPE NATIVE]";
122 public BSShapeNative() : base()
123 {
124 }
125 public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim,
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 {
128 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
130 }
131
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
133 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
134 {
135 ShapeData nativeShapeData = new ShapeData();
136 nativeShapeData.Type = shapeType;
137 nativeShapeData.ID = prim.LocalID;
138 nativeShapeData.Scale = prim.Scale;
139 nativeShapeData.Size = prim.Scale;
140 nativeShapeData.MeshKey = (ulong)shapeKey;
141 nativeShapeData.HullKey = (ulong)shapeKey;
142
143
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 }
149 else
150 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData);
152 }
153 if (ptr == IntPtr.Zero)
154 {
155 physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
156 LogHeader, prim.LocalID, shapeType);
157 }
158 type = shapeType;
159 key = (UInt64)shapeKey;
160 }
161 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene)
163 {
164 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr);
167 ptr = IntPtr.Zero;
168 // Garbage collection will free up this instance.
169 }
170}
171
172public class BSShapeMesh : BSShape
173{
174 private static string LogHeader = "[BULLETSIM SHAPE MESH]";
175 private static Dictionary<System.UInt64, BSShapeMesh> Meshes = new Dictionary<System.UInt64, BSShapeMesh>();
176
177 public BSShapeMesh() : base()
178 {
179 }
180 public static BSShape GetReference() { return new BSShapeNull(); }
181 public override void Dereference(BSScene physicsScene) { }
182}
183
184public class BSShapeHull : BSShape
185{
186 private static string LogHeader = "[BULLETSIM SHAPE HULL]";
187 private static Dictionary<System.UInt64, BSShapeHull> Hulls = new Dictionary<System.UInt64, BSShapeHull>();
188
189 public BSShapeHull() : base()
190 {
191 }
192 public static BSShape GetReference() { return new BSShapeNull(); }
193 public override void Dereference(BSScene physicsScene) { }
194}
195
196public class BSShapeCompound : BSShape
197{
198 private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]";
199 public BSShapeCompound() : base()
200 {
201 }
202 public static BSShape GetReference(BSPhysObject prim)
203 {
204 return new BSShapeNull();
205 }
206 public override void Dereference(BSScene physicsScene) { }
207}
208}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
new file mode 100755
index 0000000..3ca756c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -0,0 +1,170 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainHeightmap : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46
47 BulletHeightMapInfo m_mapInfo = null;
48
49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
51 : base(physicsScene, regionBase, id)
52 {
53 Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE);
54 Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION);
55 int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y;
56 float[] initialMap = new float[totalHeights];
57 for (int ii = 0; ii < totalHeights; ii++)
58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase;
65 // Don't have to free any previous since we just got here.
66 BuildHeightmapTerrain();
67 }
68
69 // This minCoords and maxCoords passed in give the size of the terrain (min and max Z
70 // are the high and low points of the heightmap).
71 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id)
74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero);
76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z;
79 m_mapInfo.maxZ = maxCoords.Z;
80 m_mapInfo.terrainRegionBase = TerrainBase;
81
82 // Don't have to free any previous since we just got here.
83 BuildHeightmapTerrain();
84 }
85
86 public override void Dispose()
87 {
88 ReleaseHeightMapTerrain();
89 }
90
91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain()
93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
97
98 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
100 BSPhysicsShapeType.SHAPE_TERRAIN);
101
102 // The terrain object initial position is at the center of the object
103 Vector3 centerPos;
104 centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f);
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
107
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr,
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111
112 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
117
118 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
120
121 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
123
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr,
125 (uint)CollisionFilterGroups.TerrainFilter,
126 (uint)CollisionFilterGroups.TerrainMask);
127
128 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
130
131 return;
132 }
133
134 // If there is information in m_mapInfo pointing to physical structures, release same.
135 private void ReleaseHeightMapTerrain()
136 {
137 if (m_mapInfo != null)
138 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero)
140 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
142 // Frees both the body and the shape.
143 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr);
144 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
145 }
146 }
147 m_mapInfo = null;
148 }
149
150 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos)
152 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154
155 int mapIndex = (int)pos.Y * (int)m_mapInfo.sizeY + (int)pos.X;
156 try
157 {
158 ret = m_mapInfo.heightMap[mapIndex];
159 }
160 catch
161 {
162 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
163 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
164 LogHeader, m_mapInfo.terrainRegionBase, pos);
165 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
166 }
167 return ret;
168 }
169}
170}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
new file mode 100755
index 0000000..23fcfd3
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -0,0 +1,419 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43
44// The physical implementation of the terrain is wrapped in this class.
45public abstract class BSTerrainPhys : IDisposable
46{
47 public enum TerrainImplementation
48 {
49 Heightmap = 0,
50 Mesh = 1
51 }
52
53 public BSScene PhysicsScene { get; private set; }
54 // Base of the region in world coordinates. Coordinates inside the region are relative to this.
55 public Vector3 TerrainBase { get; private set; }
56 public uint ID { get; private set; }
57
58 public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id)
59 {
60 PhysicsScene = physicsScene;
61 TerrainBase = regionBase;
62 ID = id;
63 }
64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos);
66}
67
68// ==========================================================================================
69public sealed class BSTerrainManager
70{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72
73 // These height values are fractional so the odd values will be
74 // noticable when debugging.
75 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
78
79 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87
88 // The scene that I am part of
89 private BSScene PhysicsScene { get; set; }
90
91 // The ground plane created to keep thing from falling to infinity.
92 private BulletBody m_groundPlane;
93
94 // If doing mega-regions, if we're region zero we will be managing multiple
95 // region terrains since region zero does the physics for the whole mega-region.
96 private Dictionary<Vector3, BSTerrainPhys> m_terrains;
97
98 // Flags used to know when to recalculate the height.
99 private bool m_terrainModified = false;
100
101 // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount.
102 // This is incremented before assigning to new region so it is the last ID allocated.
103 private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1;
104 public uint HighestTerrainID { get {return m_terrainCount; } }
105
106 // If doing mega-regions, this holds our offset from region zero of
107 // the mega-regions. "parentScene" points to the PhysicsScene of region zero.
108 private Vector3 m_worldOffset;
109 // If the parent region (region 0), this is the extent of the combined regions
110 // relative to the origin of region zero
111 private Vector3 m_worldMax;
112 private PhysicsScene MegaRegionParentPhysicsScene { get; set; }
113
114 public BSTerrainManager(BSScene physicsScene)
115 {
116 PhysicsScene = physicsScene;
117 m_terrains = new Dictionary<Vector3,BSTerrainPhys>();
118
119 // Assume one region of default size
120 m_worldOffset = Vector3.Zero;
121 m_worldMax = new Vector3(DefaultRegionSize);
122 MegaRegionParentPhysicsScene = null;
123 }
124
125 // Create the initial instance of terrain and the underlying ground plane.
126 // This is called from the initialization routine so we presume it is
127 // safe to call Bullet in real time. We hope no one is moving prims around yet.
128 public void CreateInitialGroundPlaneAndTerrain()
129 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape(
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
136 Vector3.Zero, Quaternion.Identity));
137 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
138 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
139 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr,
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask);
144
145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
146 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
147 m_terrains.Add(Vector3.Zero, initialTerrain);
148 }
149
150 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain()
152 {
153 if (m_groundPlane.ptr != IntPtr.Zero)
154 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr))
156 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr);
158 }
159 m_groundPlane.ptr = IntPtr.Zero;
160 }
161
162 ReleaseTerrain();
163 }
164
165 // Release all the terrain we have allocated
166 public void ReleaseTerrain()
167 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
169 {
170 kvp.Value.Dispose();
171 }
172 m_terrains.Clear();
173 }
174
175 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
179 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 {
182 // If a child of a mega-region, we shouldn't have any terrain allocated for us
183 ReleaseGroundPlaneAndTerrain();
184 // If doing the mega-prim stuff and we are the child of the zero region,
185 // the terrain is added to our parent
186 if (MegaRegionParentPhysicsScene is BSScene)
187 {
188 DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}",
189 BSScene.DetailLogZero, m_worldOffset, m_worldMax);
190 ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.UpdateTerrain(
191 BSScene.CHILDTERRAIN_ID, localHeightMap,
192 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
193 }
194 }
195 else
196 {
197 // If not doing the mega-prim thing, just change the terrain
198 DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero);
199
200 UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap,
201 m_worldOffset, m_worldOffset + DefaultRegionSize, true);
202 }
203 });
204 }
205
206 // If called with no mapInfo for the terrain, this will create a new mapInfo and terrain
207 // based on the passed information. The 'id' should be either the terrain id or
208 // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used.
209 // The latter feature is for creating child terrains for mega-regions.
210 // If called with a mapInfo in m_heightMaps and there is an existing terrain body, a new
211 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.)
214 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 {
217 DetailLog("{0},BSTerrainManager.UpdateTerrain,call,minC={1},maxC={2},inTaintTime={3}",
218 BSScene.DetailLogZero, minCoords, maxCoords, inTaintTime);
219
220 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue;
225 float maxZ = float.MinValue;
226 foreach (float height in heightMap)
227 {
228 if (height < minZ) minZ = height;
229 if (height > maxZ) maxZ = height;
230 }
231 if (minZ == maxZ)
232 {
233 // If min and max are the same, reduce min a little bit so a good bounding box is created.
234 minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE;
235 }
236 minCoords.Z = minZ;
237 maxCoords.Z = maxZ;
238
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240
241 BSTerrainPhys terrainPhys;
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 {
244 // There is already a terrain in this spot. Free the old and build the new.
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 {
250 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using.
253 terrainPhys.Dispose();
254
255 if (MegaRegionParentPhysicsScene == null)
256 {
257 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
258 m_terrains.Add(terrainRegionBase, newTerrainPhys);
259
260 m_terrainModified = true;
261 }
262 else
263 {
264 // It's possible that Combine() was called after this code was queued.
265 // If we are a child of combined regions, we don't create any terrain for us.
266 DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero);
267
268 // Get rid of any terrain that may have been allocated for us.
269 ReleaseGroundPlaneAndTerrain();
270
271 // I hate doing this, but just bail
272 return;
273 }
274 });
275 }
276 else
277 {
278 // We don't know about this terrain so either we are creating a new terrain or
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
292
293 // Code that must happen at taint-time
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300
301 m_terrainModified = true;
302 });
303 }
304 }
305
306 // TODO: redo terrain implementation selection to allow other base types than heightMap.
307 private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords)
308 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
312 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation)
314 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
317 heightMap, minCoords, maxCoords);
318 break;
319 case (int)BSTerrainPhys.TerrainImplementation.Mesh:
320 newTerrainPhys = new BSTerrainMesh(PhysicsScene, terrainRegionBase, id,
321 heightMap, minCoords, maxCoords);
322 break;
323 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation,
327 PhysicsScene.Params.terrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase);
329 break;
330 }
331 return newTerrainPhys;
332 }
333
334
335 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region,
337 // the base of the region is calcuated assuming all regions are
338 // the same size and that is the default.
339 // Once the heightMapInfo is found, we have all the information to
340 // compute the offset into the array.
341 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc)
345 {
346 float tX = loc.X;
347 float tY = loc.Y;
348 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
351 return lastHeight;
352
353 lastHeightTX = tX;
354 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET;
356
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360
361 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
363 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 }
368 else
369 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY);
372 }
373 m_terrainModified = false;
374 lastHeight = ret;
375 return ret;
376 }
377
378 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining()
380 {
381 return true;
382 }
383
384 // This routine is called two ways:
385 // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum
386 // extent of the combined regions. This is to inform the parent of the size
387 // of the combined regions.
388 // and one with 'offset' as the offset of the child region to the base region,
389 // 'pScene' pointing to the parent and 'extents' of zero. This informs the
390 // child of its relative base and new parent.
391 public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents)
392 {
393 m_worldOffset = offset;
394 m_worldMax = extents;
395 MegaRegionParentPhysicsScene = pScene;
396 if (pScene != null)
397 {
398 // We are a child.
399 // We want m_worldMax to be the highest coordinate of our piece of terrain.
400 m_worldMax = offset + DefaultRegionSize;
401 }
402 DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}",
403 BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax);
404 }
405
406 // Unhook all the combining that I know about.
407 public void UnCombine(PhysicsScene pScene)
408 {
409 // Just like ODE, we don't do anything yet.
410 DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero);
411 }
412
413
414 private void DetailLog(string msg, params Object[] args)
415 {
416 PhysicsScene.PhysicsLogging.Write(msg, args);
417 }
418}
419}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
new file mode 100755
index 0000000..dca7150
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -0,0 +1,256 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Framework;
32using OpenSim.Region.Framework;
33using OpenSim.Region.CoreModules;
34using OpenSim.Region.Physics.Manager;
35
36using Nini.Config;
37using log4net;
38
39using OpenMetaverse;
40
41namespace OpenSim.Region.Physics.BulletSPlugin
42{
43public sealed class BSTerrainMesh : BSTerrainPhys
44{
45 static string LogHeader = "[BULLETSIM TERRAIN MESH]";
46
47 private float[] m_savedHeightMap;
48 int m_sizeX;
49 int m_sizeY;
50
51 BulletShape m_terrainShape;
52 BulletBody m_terrainBody;
53
54 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
55 : base(physicsScene, regionBase, id)
56 {
57 }
58
59 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */)
60 : base(physicsScene, regionBase, id)
61 {
62 }
63
64 // Create terrain mesh from a heightmap.
65 public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
66 Vector3 minCoords, Vector3 maxCoords)
67 : base(physicsScene, regionBase, id)
68 {
69 int indicesCount;
70 int[] indices;
71 int verticesCount;
72 float[] vertices;
73
74 m_savedHeightMap = initialMap;
75
76 m_sizeX = (int)(maxCoords.X - minCoords.X);
77 m_sizeY = (int)(maxCoords.Y - minCoords.Y);
78
79 if (!BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene, initialMap,
80 m_sizeX, m_sizeY,
81 (float)m_sizeX, (float)m_sizeY,
82 Vector3.Zero, 1.0f,
83 out indicesCount, out indices, out verticesCount, out vertices))
84 {
85 // DISASTER!!
86 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap", ID);
87 PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase);
88 // Something is very messed up and a crash is in our future.
89 return;
90 }
91
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
93 indicesCount, indices, verticesCount, vertices),
94 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero)
96 {
97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
99 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
100 // Something is very messed up and a crash is in our future.
101 return;
102 }
103
104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity;
106
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot));
108 if (m_terrainBody.ptr == IntPtr.Zero)
109 {
110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
112 // Something is very messed up and a crash is in our future.
113 return;
114 }
115
116 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
121
122 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
124
125 // Return the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
127
128 // redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
130
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
132 (uint)CollisionFilterGroups.TerrainFilter,
133 (uint)CollisionFilterGroups.TerrainMask);
134
135 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
137 }
138
139 public override void Dispose()
140 {
141 if (m_terrainBody.ptr != IntPtr.Zero)
142 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
144 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr);
146 }
147 }
148
149 public override float GetHeightAtXYZ(Vector3 pos)
150 {
151 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position.
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154
155 int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X;
156 try
157 {
158 ret = m_savedHeightMap[mapIndex];
159 }
160 catch
161 {
162 // Sometimes they give us wonky values of X and Y. Give a warning and return something.
163 PhysicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}",
164 LogHeader, TerrainBase, pos);
165 ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
166 }
167 return ret;
168 }
169
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh(
173 BSScene physicsScene,
174 float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap
175 float extentX, float extentY, // zero based range for output vertices
176 Vector3 extentBase, // base to be added to all vertices
177 float magnification, // number of vertices to create between heightMap coords
178 out int indicesCountO, out int[] indicesO,
179 out int verticesCountO, out float[] verticesO)
180 {
181 bool ret = false;
182
183 int indicesCount = 0;
184 int verticesCount = 0;
185 int[] indices = new int[0];
186 float[] vertices = new float[0];
187
188 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190
191 try
192 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge.
194 int totalVertices = (sizeX + 1) * (sizeY + 1);
195 vertices = new float[totalVertices * 3];
196 int totalIndices = sizeX * sizeY * 6;
197 indices = new int[totalIndices];
198
199 float magX = (float)sizeX / extentX;
200 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
203 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++)
205 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times
207 {
208 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column
210 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset];
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z;
216 verticesCount += 3;
217 }
218 }
219 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222
223 for (int yy = 0; yy < sizeY; yy++)
224 {
225 for (int xx = 0; xx < sizeX; xx++)
226 {
227 int offset = yy * sizeX + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1;
231 indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column
232 indices[indicesCount + 3] = offset + 1;
233 indices[indicesCount + 4] = offset + sizeX + 2;
234 indices[indicesCount + 5] = offset + sizeX + 1;
235 indicesCount += 6;
236 }
237 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
239 LogHeader, indicesCount); // DEBUG
240 ret = true;
241 }
242 catch (Exception e)
243 {
244 physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
245 LogHeader, physicsScene.RegionName, extentBase, e);
246 }
247
248 indicesCountO = indicesCount;
249 indicesO = indices;
250 verticesCountO = verticesCount;
251 verticesO = vertices;
252
253 return ret;
254 }
255}
256}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index 504bd3c..e60a760 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -33,52 +33,184 @@ using OpenMetaverse;
33namespace OpenSim.Region.Physics.BulletSPlugin { 33namespace OpenSim.Region.Physics.BulletSPlugin {
34 34
35// Classes to allow some type checking for the API 35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
36public struct BulletSim 39public struct BulletSim
37{ 40{
38 public BulletSim(uint id, BSScene bss, IntPtr xx) { ID = id; scene = bss; Ptr = xx; } 41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
39 public uint ID; 42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
40 // The scene is only in here so very low level routines have a handle to print debug/error messages 49 // The scene is only in here so very low level routines have a handle to print debug/error messages
41 public BSScene scene; 50 public BSScene physicsScene;
42 public IntPtr Ptr;
43} 51}
44 52
53// An allocated Bullet btRigidBody
45public struct BulletBody 54public struct BulletBody
46{ 55{
47 public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; } 56 public BulletBody(uint id, IntPtr xx)
48 public IntPtr Ptr; 57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
49 public uint ID; 64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
50} 120}
51 121
122 // Constraint type values as defined by Bullet
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
52public struct BulletConstraint 136public struct BulletConstraint
53{ 137{
54 public BulletConstraint(IntPtr xx) { Ptr = xx; } 138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
55 public IntPtr Ptr; 162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
56} 171}
57 172
58// =============================================================================== 173// ===============================================================================
59[StructLayout(LayoutKind.Sequential)] 174[StructLayout(LayoutKind.Sequential)]
60public struct ConvexHull 175public struct ConvexHull
61{ 176{
62 Vector3 Offset; 177 Vector3 Offset;
63 int VertexCount; 178 int VertexCount;
64 Vector3[] Vertices; 179 Vector3[] Vertices;
65} 180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
66[StructLayout(LayoutKind.Sequential)] 209[StructLayout(LayoutKind.Sequential)]
67public struct ShapeData 210public struct ShapeData
68{ 211{
69 public enum PhysicsShapeType
70 {
71 SHAPE_UNKNOWN = 0,
72 SHAPE_AVATAR = 1,
73 SHAPE_BOX = 2,
74 SHAPE_CONE = 3,
75 SHAPE_CYLINDER = 4,
76 SHAPE_SPHERE = 5,
77 SHAPE_MESH = 6,
78 SHAPE_HULL = 7
79 };
80 public uint ID; 212 public uint ID;
81 public PhysicsShapeType Type; 213 public BSPhysicsShapeType Type;
82 public Vector3 Position; 214 public Vector3 Position;
83 public Quaternion Rotation; 215 public Quaternion Rotation;
84 public Vector3 Velocity; 216 public Vector3 Velocity;
@@ -91,13 +223,15 @@ public struct ShapeData
91 public float Restitution; 223 public float Restitution;
92 public float Collidable; // true of things bump into this 224 public float Collidable; // true of things bump into this
93 public float Static; // true if a static object. Otherwise gravity, etc. 225 public float Static; // true if a static object. Otherwise gravity, etc.
226 public float Solid; // true if object cannot be passed through
227 public Vector3 Size;
94 228
95 // note that bools are passed as floats since bool size changes by language and architecture 229 // note that bools are passed as floats since bool size changes by language and architecture
96 public const float numericTrue = 1f; 230 public const float numericTrue = 1f;
97 public const float numericFalse = 0f; 231 public const float numericFalse = 0f;
98} 232}
99[StructLayout(LayoutKind.Sequential)] 233[StructLayout(LayoutKind.Sequential)]
100public struct SweepHit 234public struct SweepHit
101{ 235{
102 public uint ID; 236 public uint ID;
103 public float Fraction; 237 public float Fraction;
@@ -149,13 +283,16 @@ public struct ConfigurationParameters
149 public float ccdSweptSphereRadius; 283 public float ccdSweptSphereRadius;
150 public float contactProcessingThreshold; 284 public float contactProcessingThreshold;
151 285
286 public float terrainImplementation;
152 public float terrainFriction; 287 public float terrainFriction;
153 public float terrainHitFraction; 288 public float terrainHitFraction;
154 public float terrainRestitution; 289 public float terrainRestitution;
155 public float avatarFriction; 290 public float avatarFriction;
291 public float avatarStandingFriction;
156 public float avatarDensity; 292 public float avatarDensity;
157 public float avatarRestitution; 293 public float avatarRestitution;
158 public float avatarCapsuleRadius; 294 public float avatarCapsuleWidth;
295 public float avatarCapsuleDepth;
159 public float avatarCapsuleHeight; 296 public float avatarCapsuleHeight;
160 public float avatarContactProcessingThreshold; 297 public float avatarContactProcessingThreshold;
161 298
@@ -168,18 +305,45 @@ public struct ConfigurationParameters
168 public float shouldEnableFrictionCaching; 305 public float shouldEnableFrictionCaching;
169 public float numberOfSolverIterations; 306 public float numberOfSolverIterations;
170 307
308 public float linksetImplementation;
171 public float linkConstraintUseFrameOffset; 309 public float linkConstraintUseFrameOffset;
172 public float linkConstraintEnableTransMotor; 310 public float linkConstraintEnableTransMotor;
173 public float linkConstraintTransMotorMaxVel; 311 public float linkConstraintTransMotorMaxVel;
174 public float linkConstraintTransMotorMaxForce; 312 public float linkConstraintTransMotorMaxForce;
175 public float linkConstraintERP; 313 public float linkConstraintERP;
176 public float linkConstraintCFM; 314 public float linkConstraintCFM;
315 public float linkConstraintSolverIterations;
316
317 public float physicsLoggingFrames;
177 318
178 public const float numericTrue = 1f; 319 public const float numericTrue = 1f;
179 public const float numericFalse = 0f; 320 public const float numericFalse = 0f;
180} 321}
181 322
182// Values used by Bullet and BulletSim to control collisions 323
324// The states a bullet collision object can have
325public enum ActivationState : uint
326{
327 ACTIVE_TAG = 1,
328 ISLAND_SLEEPING,
329 WANTS_DEACTIVATION,
330 DISABLE_DEACTIVATION,
331 DISABLE_SIMULATION,
332}
333
334public enum CollisionObjectTypes : int
335{
336 CO_COLLISION_OBJECT = 1 << 0,
337 CO_RIGID_BODY = 1 << 1,
338 CO_GHOST_OBJECT = 1 << 2,
339 CO_SOFT_BODY = 1 << 3,
340 CO_HF_FLUID = 1 << 4,
341 CO_USER_TYPE = 1 << 5,
342}
343
344// Values used by Bullet and BulletSim to control object properties.
345// Bullet's "CollisionFlags" has more to do with operations on the
346// object (if collisions happen, if gravity effects it, ...).
183public enum CollisionFlags : uint 347public enum CollisionFlags : uint
184{ 348{
185 CF_STATIC_OBJECT = 1 << 0, 349 CF_STATIC_OBJECT = 1 << 0,
@@ -191,9 +355,54 @@ public enum CollisionFlags : uint
191 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
192 // Following used by BulletSim to control collisions 356 // Following used by BulletSim to control collisions
193 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, 357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
194 BS_VOLUME_DETECT_OBJECT = 1 << 11, 358 BS_FLOATS_ON_WATER = 1 << 11,
195 BS_PHANTOM_OBJECT = 1 << 12, 359 BS_NONE = 0,
196 BS_PHYSICAL_OBJECT = 1 << 13, 360 BS_ALL = 0xFFFFFFFF,
361
362 // These are the collision flags switched depending on physical state.
363 // The other flags are used for other things and should not be fooled with.
364 BS_ACTIVE = CF_STATIC_OBJECT
365 | CF_KINEMATIC_OBJECT
366 | CF_NO_CONTACT_RESPONSE
367};
368
369// Values for collisions groups and masks
370public enum CollisionFilterGroups : uint
371{
372 // Don't use the bit definitions!! Define the use in a
373 // filter/mask definition below. This way collision interactions
374 // are more easily debugged.
375 BNoneFilter = 0,
376 BDefaultFilter = 1 << 0,
377 BStaticFilter = 1 << 1,
378 BKinematicFilter = 1 << 2,
379 BDebrisFilter = 1 << 3,
380 BSensorTrigger = 1 << 4,
381 BCharacterFilter = 1 << 5,
382 BAllFilter = 0xFFFFFFFF,
383 // Filter groups defined by BulletSim
384 BGroundPlaneFilter = 1 << 10,
385 BTerrainFilter = 1 << 11,
386 BRaycastFilter = 1 << 12,
387 BSolidFilter = 1 << 13,
388 BLinksetFilter = 1 << 14,
389
390 // The collsion filters and masked are defined in one place -- don't want them scattered
391 AvatarFilter = BCharacterFilter,
392 AvatarMask = BAllFilter,
393 ObjectFilter = BSolidFilter,
394 ObjectMask = BAllFilter,
395 StaticObjectFilter = BStaticFilter,
396 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
397 LinksetFilter = BLinksetFilter,
398 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
399 VolumeDetectFilter = BSensorTrigger,
400 VolumeDetectMask = ~BSensorTrigger,
401 TerrainFilter = BTerrainFilter,
402 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
403 GroundPlaneFilter = BGroundPlaneFilter,
404 GroundPlaneMask = BAllFilter
405
197}; 406};
198 407
199// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
@@ -221,250 +430,285 @@ public enum ConstraintParamAxis : int
221// =============================================================================== 430// ===============================================================================
222static class BulletSimAPI { 431static class BulletSimAPI {
223 432
224[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 433// Link back to the managed code for outputting log messages
225[return: MarshalAs(UnmanagedType.LPStr)] 434[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
226public static extern string GetVersion(); 435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
227 436
437// ===============================================================================
438// Initialization and simulation
228[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
229public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, 440public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
230 int maxCollisions, IntPtr collisionArray, 441 int maxCollisions, IntPtr collisionArray,
231 int maxUpdates, IntPtr updateArray); 442 int maxUpdates, IntPtr updateArray,
443 DebugLogCallback logRoutine);
232 444
233[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
234public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); 446public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
235 447
236[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
237public static extern void Shutdown(uint worldID); 449public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
238 450
239[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
240public static extern bool UpdateParameter(uint worldID, uint localID, 452public static extern void Shutdown2(IntPtr sim);
241 [MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
242 453
243// ===============================================================================
244[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
245public static extern int PhysicsStep(uint worldID, float timeStep, int maxSubSteps, float fixedTimeStep, 455public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
246 out int updatedEntityCount, 456 out int updatedEntityCount,
247 out IntPtr updatedEntitiesPtr, 457 out IntPtr updatedEntitiesPtr,
248 out int collidersCount, 458 out int collidersCount,
249 out IntPtr collidersPtr); 459 out IntPtr collidersPtr);
250 460
251[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
252public static extern bool CreateHull(uint worldID, System.UInt64 meshKey, 462public static extern bool PushUpdate2(IntPtr obj);
253 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls
254 );
255 463
464// =====================================================================================
465// Mesh, hull, shape and body creation helper routines
256[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
257public static extern bool CreateMesh(uint worldID, System.UInt64 meshKey, 467public static extern IntPtr CreateMeshShape2(IntPtr world,
258 int indexCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, 468 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
259 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices 469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
260 );
261 470
262[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
263public static extern bool DestroyHull(uint worldID, System.UInt64 meshKey); 472public static extern IntPtr CreateHullShape2(IntPtr world,
473 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
264 474
265[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
266public static extern bool DestroyMesh(uint worldID, System.UInt64 meshKey); 476public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
267 477
268[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
269public static extern bool CreateObject(uint worldID, ShapeData shapeData); 479public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
270 480
271/* Remove old functionality
272[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
273public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas); 482public static extern bool IsNativeShape2(IntPtr shape);
274 483
275[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
276public static extern void AddConstraint(uint worldID, uint id1, uint id2, 485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
277 Vector3 frame1, Quaternion frame1rot,
278 Vector3 frame2, Quaternion frame2rot,
279 Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
280 486
281[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
282public static extern bool RemoveConstraintByID(uint worldID, uint id1); 488public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
283 489
284[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
285public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); 491public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
286 */
287 492
288[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
289public static extern Vector3 GetObjectPosition(uint WorldID, uint id); 494public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
290 495
291[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
292public static extern Quaternion GetObjectOrientation(uint WorldID, uint id); 497public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
293 498
294[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
295public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); 500public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
296 501
297[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
298public static extern bool SetObjectVelocity(uint worldID, uint id, Vector3 velocity); 503public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
299 504
300[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
301public static extern bool SetObjectAngularVelocity(uint worldID, uint id, Vector3 angularVelocity); 506public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
302 507
303[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
304public static extern bool SetObjectForce(uint worldID, uint id, Vector3 force); 509public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
305 510
306[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
307public static extern bool SetObjectScaleMass(uint worldID, uint id, Vector3 scale, float mass, bool isDynamic); 512public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
308 513
309[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
310public static extern bool SetObjectCollidable(uint worldID, uint id, bool phantom); 515public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
311 516
312[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
313public static extern bool SetObjectDynamic(uint worldID, uint id, bool isDynamic, float mass); 518public static extern int GetBodyType2(IntPtr obj);
314 519
315[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
316public static extern bool SetObjectGhost(uint worldID, uint id, bool ghostly); 521public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
317 522
318[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
319public static extern bool SetObjectProperties(uint worldID, uint id, bool isStatic, bool isSolid, bool genCollisions, float mass); 524public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
320 525
321[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
322public static extern bool SetObjectBuoyancy(uint worldID, uint id, float buoyancy); 527public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
323 528
324[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
325public static extern bool HasObject(uint worldID, uint id); 530public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
326 531
327[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
328public static extern bool DestroyObject(uint worldID, uint id); 533public static extern void ReleaseBodyInfo2(IntPtr obj);
329 534
330// ===============================================================================
331[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
332public static extern SweepHit ConvexSweepTest(uint worldID, uint id, Vector3 to, float extraMargin); 536public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
333 537
538// =====================================================================================
539// Terrain creation and helper routines
334[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
335public static extern RaycastHit RayTest(uint worldID, uint id, Vector3 from, Vector3 to); 541public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
542 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
336 543
337[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
338public static extern Vector3 RecoverFromPenetration(uint worldID, uint id); 545public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
546 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
339 547
340// ===============================================================================
341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
342public static extern void DumpBulletStatistics(); 549public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
343 550
344// Log a debug message
345[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
346public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
348public static extern void SetDebugLogCallback(DebugLogCallback callback); 552public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
349 553
350// =============================================================================== 554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
351// =============================================================================== 555public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
352// ===============================================================================
353// A new version of the API that enables moving all the logic out of the C++ code and into
354// the C# code. This will make modifications easier for the next person.
355// This interface passes the actual pointers to the objects in the unmanaged
356// address space. All the management (calls for creation/destruction/lookup)
357// is done in the C# code.
358// The names have a "2" tacked on. This will be removed as the C# code gets rebuilt
359// and the old code is removed.
360 556
557// =====================================================================================
558// Constraint creation and helper routines
361[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 559[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
362public static extern IntPtr GetSimHandle2(uint worldID); 560public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
561 Vector3 frame1loc, Quaternion frame1rot,
562 Vector3 frame2loc, Quaternion frame2rot,
563 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
363 564
364[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
365public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id); 566public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
567 Vector3 joinPoint,
568 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
366 569
367[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
368public static extern IntPtr GetBodyHandle2(IntPtr world, uint id); 571public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
572 Vector3 pivotinA, Vector3 pivotinB,
573 Vector3 axisInA, Vector3 axisInB,
574 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
369 575
370// ===============================================================================
371[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
372public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, 577public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
373 int maxCollisions, IntPtr collisionArray,
374 int maxUpdates, IntPtr updateArray);
375 578
376[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 579[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
377public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); 580public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
378 581
379[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 582[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
380public static extern void SetHeightmap2(IntPtr world, float[] heightmap); 583public static extern bool SetFrames2(IntPtr constrain,
584 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
381 585
382[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
383public static extern void Shutdown2(IntPtr sim); 587public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
384 588
385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
386public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, 590public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
387 out int updatedEntityCount,
388 out IntPtr updatedEntitiesPtr,
389 out int collidersCount,
390 out IntPtr collidersPtr);
391 591
392[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
393public static extern bool PushUpdate2(IntPtr obj); 593public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
394 594
395/*
396[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
397public static extern IntPtr CreateMesh2(IntPtr world, int indicesCount, int* indices, int verticesCount, float* vertices ); 596public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
398 597
399[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 598[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
400public static extern bool BuildHull2(IntPtr world, IntPtr mesh); 599public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
401 600
402[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
403public static extern bool ReleaseHull2(IntPtr world, IntPtr mesh); 602public static extern bool CalculateTransforms2(IntPtr constrain);
404 603
405[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
406public static extern bool DestroyMesh2(IntPtr world, IntPtr mesh); 605public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
407 606
408[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
409public static extern IntPtr CreateObject2(IntPtr world, ShapeData shapeData); 608public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
410*/
411 609
610// =====================================================================================
611// btCollisionWorld entries
412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
413public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 613public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
414 Vector3 frame1loc, Quaternion frame1rot,
415 Vector3 frame2loc, Quaternion frame2rot,
416 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
417 614
418[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
419public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, 616public static extern void UpdateAabbs2(IntPtr world);
420 Vector3 joinPoint,
421 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
422 617
423[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
424public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, 619public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
425 Vector3 pivotinA, Vector3 pivotinB,
426 Vector3 axisInA, Vector3 axisInB,
427 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
428 620
429[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
430public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); 622public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
431 623
624// =====================================================================================
625// btDynamicsWorld entries
432[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
433public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); 627public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
434 628
435[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
436public static extern bool SetFrames2(IntPtr constrain, 630public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
437 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
438 631
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
440public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); 633public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
441 634
442[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
443public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); 636public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
637// =====================================================================================
638// btCollisionObject entries
639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
640public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
444 641
445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
446public static extern bool UseFrameOffset2(IntPtr constrain, float enable); 643public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
447 644
448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
449public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); 646public static extern bool HasAnisotripicFriction2(IntPtr constrain);
450 647
451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 648[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
452public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); 649public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
453 650
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern bool CalculateTransforms2(IntPtr constrain); 652public static extern float GetContactProcessingThreshold2(IntPtr obj);
456 653
457[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 654[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
458public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); 655public static extern bool IsStaticObject2(IntPtr obj);
459 656
460[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 657[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
461public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); 658public static extern bool IsKinematicObject2(IntPtr obj);
659
660[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
661public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
662
663[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
664public static extern bool HasContactResponse2(IntPtr obj);
665
666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
667public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
462 668
463[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
464public static extern Vector3 AddObjectToWorld2(IntPtr world, IntPtr obj); 670public static extern IntPtr GetCollisionShape2(IntPtr obj);
465 671
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 672[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern Vector3 RemoveObjectFromWorld2(IntPtr world, IntPtr obj); 673public static extern int GetActivationState2(IntPtr obj);
674
675[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
676public static extern void SetActivationState2(IntPtr obj, int state);
677
678[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
679public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
680
681[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
682public static extern float GetDeactivationTime2(IntPtr obj);
683
684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
685public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
686
687[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
688public static extern void Activate2(IntPtr obj, bool forceActivation);
689
690[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
691public static extern bool IsActive2(IntPtr obj);
692
693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
694public static extern void SetRestitution2(IntPtr obj, float val);
695
696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
697public static extern float GetRestitution2(IntPtr obj);
698
699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
700public static extern void SetFriction2(IntPtr obj, float val);
701
702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
703public static extern float GetFriction2(IntPtr obj);
704
705 /* Haven't defined the type 'Transform'
706[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
707public static extern Transform GetWorldTransform2(IntPtr obj);
708
709[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
710public static extern void setWorldTransform2(IntPtr obj, Transform trans);
711 */
468 712
469[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 713[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
470public static extern Vector3 GetPosition2(IntPtr obj); 714public static extern Vector3 GetPosition2(IntPtr obj);
@@ -473,85 +717,296 @@ public static extern Vector3 GetPosition2(IntPtr obj);
473public static extern Quaternion GetOrientation2(IntPtr obj); 717public static extern Quaternion GetOrientation2(IntPtr obj);
474 718
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern bool SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); 720public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
477 721
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern bool SetVelocity2(IntPtr obj, Vector3 velocity); 723public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
480 724
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); 726public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
483 727
728 /*
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern bool SetObjectForce2(IntPtr obj, Vector3 force); 730public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
486 731
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern bool AddObjectForce2(IntPtr obj, Vector3 force); 733public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
734 */
489 735
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern bool SetCcdMotionThreshold2(IntPtr obj, float val); 737public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
492 738
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern bool SetCcdSweepSphereRadius2(IntPtr obj, float val); 740public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
495 741
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern bool SetDamping2(IntPtr obj, float lin_damping, float ang_damping); 743public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
498 744
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 745[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern bool SetDeactivationTime2(IntPtr obj, float val); 746public static extern float GetHitFraction2(IntPtr obj);
501 747
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 748[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern bool SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); 749public static extern void SetHitFraction2(IntPtr obj, float val);
504 750
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 751[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern bool SetContactProcessingThreshold2(IntPtr obj, float val); 752public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
507 753
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 754[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern bool SetFriction2(IntPtr obj, float val); 755public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
510 756
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 757[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern bool SetRestitution2(IntPtr obj, float val); 758public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
513 759
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 760[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool SetLinearVelocity2(IntPtr obj, Vector3 val); 761public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
516 762
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 763[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern bool SetInterpolation2(IntPtr obj, Vector3 lin, Vector3 ang); 764public static extern float GetCcdMotionThreshold2(IntPtr obj);
519 765
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 766[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); 767public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
768
769[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
770public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
771
772[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
773public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
774
775[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
776public static extern IntPtr GetUserPointer2(IntPtr obj);
777
778[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
779public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
780
781// =====================================================================================
782// btRigidBody entries
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern void ApplyGravity2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern void SetGravity2(IntPtr obj, Vector3 val);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern Vector3 GetGravity2(IntPtr obj);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern float GetLinearDamping2(IntPtr obj);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern float GetAngularDamping2(IntPtr obj);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetLinearSleepingThreshold2(IntPtr obj);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern float GetAngularSleepingThreshold2(IntPtr obj);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void ApplyDamping2(IntPtr obj, float timeStep);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
818
819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
820public static extern Vector3 GetLinearFactor2(IntPtr obj);
821
822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
823public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
824
825 /*
826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
827public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
828 */
829
830[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
831public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
832
833// Add a force to the object as if its mass is one.
834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
835public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
836
837// Set the force being applied to the object as if its mass is one.
838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
839public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
840
841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
842public static extern Vector3 GetTotalForce2(IntPtr obj);
843
844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
845public static extern Vector3 GetTotalTorque2(IntPtr obj);
846
847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
848public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
849
850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
851public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
852
853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
854public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
855
856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
857public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
858
859// Apply force at the given point. Will add torque to the object.
860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
861public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
862
863// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
865public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
866
867// Apply impulse to the object's torque. Force is scaled by object's mass.
868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
869public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
870
871// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
873public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
874
875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
876public static extern void ClearForces2(IntPtr obj);
877
878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
879public static extern void ClearAllForces2(IntPtr obj);
880
881[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
882public static extern void UpdateInertiaTensor2(IntPtr obj);
883
884[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
885public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
886
887 /*
888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
889public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
890 */
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern Vector3 GetLinearVelocity2(IntPtr obj);
894
895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
896public static extern Vector3 GetAngularVelocity2(IntPtr obj);
897
898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
899public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
900
901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
902public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
903
904[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
905public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
906
907[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
908public static extern void Translate2(IntPtr obj, Vector3 trans);
909
910[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
911public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
912
913[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
914public static extern bool WantsSleeping2(IntPtr obj);
915
916[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
917public static extern void SetAngularFactor2(IntPtr obj, float factor);
918
919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
920public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
921
922[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
923public static extern Vector3 GetAngularFactor2(IntPtr obj);
924
925[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
926public static extern bool IsInWorld2(IntPtr obj);
927
928[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
929public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
930
931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
932public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
933
934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
935public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
936
937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
938public static extern int GetNumConstraintRefs2(IntPtr obj);
939
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
942
943// =====================================================================================
944// btCollisionShape entries
945
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern float GetAngularMotionDisc2(IntPtr shape);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern bool IsPolyhedral2(IntPtr shape);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern bool IsConvex2d2(IntPtr shape);
957
958[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
959public static extern bool IsConvex2(IntPtr shape);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern bool IsNonMoving2(IntPtr shape);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern bool IsConcave2(IntPtr shape);
966
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern bool IsCompound2(IntPtr shape);
969
970[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
971public static extern bool IsSoftBody2(IntPtr shape);
972
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern bool IsInfinite2(IntPtr shape);
522 975
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr SetCollisionFlags2(IntPtr obj, CollisionFlags flags); 977public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
525 978
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 979[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); 980public static extern Vector3 GetLocalScaling2(IntPtr shape);
528 981
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 982[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); 983public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
531 984
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern bool SetMassProps2(IntPtr obj, float mass, Vector3 inertia); 986public static extern int GetShapeType2(IntPtr shape);
534 987
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern bool UpdateInertiaTensor2(IntPtr obj); 989public static extern void SetMargin2(IntPtr shape, float val);
537 990
538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
539public static extern bool SetGravity2(IntPtr obj, Vector3 val); 992public static extern float GetMargin2(IntPtr shape);
540 993
994// =====================================================================================
995// Debugging
541[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
542public static extern IntPtr ClearForces2(IntPtr obj); 997public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
543 998
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 999[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr ClearAllForces2(IntPtr obj); 1000public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
546 1001
547[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
548public static extern bool SetMargin2(IntPtr obj, float val); 1003public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
549 1004
550[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
551public static extern bool UpdateSingleAabb2(IntPtr world, IntPtr obj); 1006public static extern void DumpAllInfo2(IntPtr sim);
552 1007
553[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
554public static extern bool DestroyObject2(IntPtr world, uint id); 1009public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
555 1010
556[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] 1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
557public static extern void DumpPhysicsStatistics2(IntPtr sim); 1012public static extern void DumpPhysicsStatistics2(IntPtr sim);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..0d1db3b
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Region.Physics.BulletSPlugin")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("520ea11b-20cb-449d-ba05-c01015fed841")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]