diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 614 |
1 files changed, 317 insertions, 297 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 130f1ca..a4ab702 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -42,6 +42,8 @@ public sealed class BSPrim : PhysicsActor | |||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 43 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
44 | 44 | ||
45 | private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); } | ||
46 | |||
45 | private IMesh _mesh; | 47 | private IMesh _mesh; |
46 | private PrimitiveBaseShape _pbs; | 48 | private PrimitiveBaseShape _pbs; |
47 | private ShapeData.PhysicsShapeType _shapeType; | 49 | private ShapeData.PhysicsShapeType _shapeType; |
@@ -50,6 +52,7 @@ public sealed class BSPrim : PhysicsActor | |||
50 | private List<ConvexResult> _hulls; | 52 | private List<ConvexResult> _hulls; |
51 | 53 | ||
52 | private BSScene _scene; | 54 | private BSScene _scene; |
55 | public BSScene Scene { get { return _scene; } } | ||
53 | private String _avName; | 56 | private String _avName; |
54 | private uint _localID = 0; | 57 | private uint _localID = 0; |
55 | 58 | ||
@@ -63,7 +66,7 @@ public sealed class BSPrim : PhysicsActor | |||
63 | private bool _isSelected; | 66 | private bool _isSelected; |
64 | private bool _isVolumeDetect; | 67 | private bool _isVolumeDetect; |
65 | private OMV.Vector3 _position; | 68 | private OMV.Vector3 _position; |
66 | private float _mass; | 69 | private float _mass; // the mass of this object |
67 | private float _density; | 70 | private float _density; |
68 | private OMV.Vector3 _force; | 71 | private OMV.Vector3 _force; |
69 | private OMV.Vector3 _velocity; | 72 | private OMV.Vector3 _velocity; |
@@ -86,14 +89,25 @@ public sealed class BSPrim : PhysicsActor | |||
86 | private bool _kinematic; | 89 | private bool _kinematic; |
87 | private float _buoyancy; | 90 | private float _buoyancy; |
88 | 91 | ||
89 | private List<BSPrim> _childrenPrims; | 92 | // Membership in a linkset is controlled by this class. |
90 | private BSPrim _parentPrim; | 93 | private BSLinkset _linkset; |
94 | public BSLinkset Linkset | ||
95 | { | ||
96 | get { return _linkset; } | ||
97 | set { _linkset = value; } | ||
98 | } | ||
91 | 99 | ||
92 | private int _subscribedEventsMs = 0; | 100 | private int _subscribedEventsMs = 0; |
93 | private int _nextCollisionOkTime = 0; | 101 | private int _nextCollisionOkTime = 0; |
94 | long _collidingStep; | 102 | long _collidingStep; |
95 | long _collidingGroundStep; | 103 | long _collidingGroundStep; |
96 | 104 | ||
105 | private BulletBody m_body; | ||
106 | public BulletBody Body { | ||
107 | get { return m_body; } | ||
108 | set { m_body = value; } | ||
109 | } | ||
110 | |||
97 | private BSDynamics _vehicle; | 111 | private BSDynamics _vehicle; |
98 | 112 | ||
99 | private OMV.Vector3 _PIDTarget; | 113 | private OMV.Vector3 _PIDTarget; |
@@ -127,17 +141,18 @@ public sealed class BSPrim : PhysicsActor | |||
127 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material | 141 | _friction = _scene.Params.defaultFriction; // TODO: compute based on object material |
128 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material | 142 | _density = _scene.Params.defaultDensity; // TODO: compute based on object material |
129 | _restitution = _scene.Params.defaultRestitution; | 143 | _restitution = _scene.Params.defaultRestitution; |
130 | _parentPrim = null; // not a child or a parent | 144 | _linkset = new BSLinkset(_scene, this); // a linkset of one |
131 | _vehicle = new BSDynamics(this); // add vehicleness | 145 | _vehicle = new BSDynamics(this); // add vehicleness |
132 | _childrenPrims = new List<BSPrim>(); | 146 | _mass = CalculateMass(); |
133 | if (_isPhysical) | ||
134 | _mass = CalculateMass(); | ||
135 | else | ||
136 | _mass = 0f; | ||
137 | // do the actual object creation at taint time | 147 | // do the actual object creation at taint time |
138 | _scene.TaintedObject(delegate() | 148 | _scene.TaintedObject(delegate() |
139 | { | 149 | { |
140 | RecreateGeomAndObject(); | 150 | RecreateGeomAndObject(); |
151 | |||
152 | // Get the pointer to the physical body for this object. | ||
153 | // At the moment, we're still letting BulletSim manage the creation and destruction | ||
154 | // of the object. Someday we'll move that into the C# code. | ||
155 | m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID)); | ||
141 | }); | 156 | }); |
142 | } | 157 | } |
143 | 158 | ||
@@ -145,13 +160,19 @@ public sealed class BSPrim : PhysicsActor | |||
145 | public void Destroy() | 160 | public void Destroy() |
146 | { | 161 | { |
147 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 162 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
163 | // DetailLog("{0},Destroy", LocalID); | ||
164 | |||
148 | // Undo any vehicle properties | 165 | // Undo any vehicle properties |
149 | _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); | 166 | _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); |
150 | _scene.RemoveVehiclePrim(this); // just to make sure | 167 | _scene.RemoveVehiclePrim(this); // just to make sure |
168 | |||
151 | _scene.TaintedObject(delegate() | 169 | _scene.TaintedObject(delegate() |
152 | { | 170 | { |
171 | // Undo any links between me and any other object | ||
172 | _linkset = _linkset.RemoveMeFromLinkset(this); | ||
173 | |||
153 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. | 174 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. |
154 | BulletSimAPI.DestroyObject(_scene.WorldID, _localID); | 175 | BulletSimAPI.DestroyObject(_scene.WorldID, LocalID); |
155 | }); | 176 | }); |
156 | } | 177 | } |
157 | 178 | ||
@@ -164,8 +185,9 @@ public sealed class BSPrim : PhysicsActor | |||
164 | _size = value; | 185 | _size = value; |
165 | _scene.TaintedObject(delegate() | 186 | _scene.TaintedObject(delegate() |
166 | { | 187 | { |
167 | if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass | 188 | _mass = CalculateMass(); // changing size changes the mass |
168 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical); | 189 | BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical); |
190 | DetailLog("{0}: setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical); | ||
169 | RecreateGeomAndObject(); | 191 | RecreateGeomAndObject(); |
170 | }); | 192 | }); |
171 | } | 193 | } |
@@ -175,7 +197,7 @@ public sealed class BSPrim : PhysicsActor | |||
175 | _pbs = value; | 197 | _pbs = value; |
176 | _scene.TaintedObject(delegate() | 198 | _scene.TaintedObject(delegate() |
177 | { | 199 | { |
178 | if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass | 200 | _mass = CalculateMass(); // changing the shape changes the mass |
179 | RecreateGeomAndObject(); | 201 | RecreateGeomAndObject(); |
180 | }); | 202 | }); |
181 | } | 203 | } |
@@ -202,33 +224,10 @@ public sealed class BSPrim : PhysicsActor | |||
202 | // link me to the specified parent | 224 | // link me to the specified parent |
203 | public override void link(PhysicsActor obj) { | 225 | public override void link(PhysicsActor obj) { |
204 | BSPrim parent = obj as BSPrim; | 226 | BSPrim parent = obj as BSPrim; |
205 | // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); | 227 | DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); |
206 | // TODO: decide if this parent checking needs to happen at taint time | 228 | DetailLog("{0},link,parent={1}", LocalID, obj.LocalID); |
207 | if (_parentPrim == null) | 229 | |
208 | { | 230 | _linkset = _linkset.AddMeToLinkset(this, parent); |
209 | if (parent != null) | ||
210 | { | ||
211 | // I don't have a parent so I am joining a linkset | ||
212 | parent.AddChildToLinkset(this); | ||
213 | } | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | // I already have a parent, is parenting changing? | ||
218 | if (parent != _parentPrim) | ||
219 | { | ||
220 | if (parent == null) | ||
221 | { | ||
222 | // we are being removed from a linkset | ||
223 | _parentPrim.RemoveChildFromLinkset(this); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | // asking to reparent a prim should not happen | ||
228 | m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader); | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | return; | 231 | return; |
233 | } | 232 | } |
234 | 233 | ||
@@ -236,101 +235,92 @@ public sealed class BSPrim : PhysicsActor | |||
236 | public override void delink() { | 235 | public override void delink() { |
237 | // TODO: decide if this parent checking needs to happen at taint time | 236 | // TODO: decide if this parent checking needs to happen at taint time |
238 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | 237 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen |
239 | // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID); | 238 | DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, |
240 | if (_parentPrim != null) | 239 | _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString()); |
241 | { | 240 | DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString()); |
242 | _parentPrim.RemoveChildFromLinkset(this); | ||
243 | } | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | // I am the root of a linkset and a new child is being added | ||
248 | public void AddChildToLinkset(BSPrim pchild) | ||
249 | { | ||
250 | BSPrim child = pchild; | ||
251 | _scene.TaintedObject(delegate() | ||
252 | { | ||
253 | if (!_childrenPrims.Contains(child)) | ||
254 | { | ||
255 | _childrenPrims.Add(child); | ||
256 | child.ParentPrim = this; // the child has gained a parent | ||
257 | RecreateGeomAndObject(); // rebuild my shape with the new child added | ||
258 | } | ||
259 | }); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | // I am the root of a linkset and one of my children is being removed. | ||
264 | // Safe to call even if the child is not really in my linkset. | ||
265 | public void RemoveChildFromLinkset(BSPrim pchild) | ||
266 | { | ||
267 | BSPrim child = pchild; | ||
268 | _scene.TaintedObject(delegate() | ||
269 | { | ||
270 | if (_childrenPrims.Contains(child)) | ||
271 | { | ||
272 | BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID); | ||
273 | _childrenPrims.Remove(child); | ||
274 | child.ParentPrim = null; // the child has lost its parent | ||
275 | RecreateGeomAndObject(); // rebuild my shape with the child removed | ||
276 | } | ||
277 | else | ||
278 | { | ||
279 | m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset"); | ||
280 | } | ||
281 | }); | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | public BSPrim ParentPrim | ||
286 | { | ||
287 | set { _parentPrim = value; } | ||
288 | } | ||
289 | 241 | ||
290 | // return true if we are the root of a linkset (there are children to manage) | 242 | _linkset.RemoveMeFromLinkset(this); |
291 | public bool IsRootOfLinkset | 243 | return; |
292 | { | ||
293 | get { return (_parentPrim == null && _childrenPrims.Count != 0); } | ||
294 | } | 244 | } |
295 | 245 | ||
296 | // Set motion values to zero. | 246 | // Set motion values to zero. |
297 | // Do it to the properties so the values get set in the physics engine. | 247 | // Do it to the properties so the values get set in the physics engine. |
298 | // Push the setting of the values to the viewer. | 248 | // Push the setting of the values to the viewer. |
299 | private void ZeroMotion() | 249 | // Called at taint time! |
250 | public void ZeroMotion() | ||
300 | { | 251 | { |
301 | Velocity = OMV.Vector3.Zero; | 252 | _velocity = OMV.Vector3.Zero; |
302 | _acceleration = OMV.Vector3.Zero; | 253 | _acceleration = OMV.Vector3.Zero; |
303 | RotationalVelocity = OMV.Vector3.Zero; | 254 | _rotationalVelocity = OMV.Vector3.Zero; |
304 | base.RequestPhysicsterseUpdate(); | 255 | |
256 | // Zero some other properties directly into the physics engine | ||
257 | BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero); | ||
258 | BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero); | ||
259 | BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
260 | BulletSimAPI.ClearForces2(Body.Ptr); | ||
305 | } | 261 | } |
306 | 262 | ||
307 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 263 | public override void LockAngularMotion(OMV.Vector3 axis) |
264 | { | ||
265 | DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis); | ||
266 | return; | ||
267 | } | ||
308 | 268 | ||
309 | public override OMV.Vector3 Position { | 269 | public override OMV.Vector3 Position { |
310 | get { | 270 | get { |
311 | // don't do the following GetObjectPosition because this function is called a zillion times | 271 | if (!_linkset.IsRoot(this)) |
272 | // child prims move around based on their parent. Need to get the latest location | ||
273 | _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
274 | |||
275 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | ||
312 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 276 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
313 | return _position; | 277 | return _position; |
314 | } | 278 | } |
315 | set { | 279 | set { |
316 | _position = value; | 280 | _position = value; |
281 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
317 | _scene.TaintedObject(delegate() | 282 | _scene.TaintedObject(delegate() |
318 | { | 283 | { |
284 | DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
319 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 285 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
320 | // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position); | ||
321 | }); | 286 | }); |
322 | } | 287 | } |
323 | } | 288 | } |
324 | public override float Mass { | 289 | |
325 | get { return _mass; } | 290 | // Return the effective mass of the object. |
291 | // If there are multiple items in the linkset, add them together for the root | ||
292 | public override float Mass | ||
293 | { | ||
294 | get | ||
295 | { | ||
296 | return _linkset.LinksetMass; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | // used when we only want this prim's mass and not the linkset thing | ||
301 | public float MassRaw { get { return _mass; } } | ||
302 | |||
303 | // Is this used? | ||
304 | public override OMV.Vector3 CenterOfMass | ||
305 | { | ||
306 | get { return _linkset.CenterOfMass; } | ||
307 | } | ||
308 | |||
309 | // Is this used? | ||
310 | public override OMV.Vector3 GeometricCenter | ||
311 | { | ||
312 | get { return _linkset.GeometricCenter; } | ||
326 | } | 313 | } |
314 | |||
327 | public override OMV.Vector3 Force { | 315 | public override OMV.Vector3 Force { |
328 | get { return _force; } | 316 | get { return _force; } |
329 | set { | 317 | set { |
330 | _force = value; | 318 | _force = value; |
331 | _scene.TaintedObject(delegate() | 319 | _scene.TaintedObject(delegate() |
332 | { | 320 | { |
333 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | 321 | DetailLog("{0},SetForce,taint,force={1}", LocalID, _force); |
322 | // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | ||
323 | BulletSimAPI.SetObjectForce2(Body.Ptr, _force); | ||
334 | }); | 324 | }); |
335 | } | 325 | } |
336 | } | 326 | } |
@@ -341,15 +331,22 @@ public sealed class BSPrim : PhysicsActor | |||
341 | } | 331 | } |
342 | set { | 332 | set { |
343 | Vehicle type = (Vehicle)value; | 333 | Vehicle type = (Vehicle)value; |
344 | _vehicle.ProcessTypeChange(type); | ||
345 | _scene.TaintedObject(delegate() | 334 | _scene.TaintedObject(delegate() |
346 | { | 335 | { |
336 | DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type); | ||
337 | _vehicle.ProcessTypeChange(type); | ||
347 | if (type == Vehicle.TYPE_NONE) | 338 | if (type == Vehicle.TYPE_NONE) |
348 | { | 339 | { |
349 | _scene.RemoveVehiclePrim(this); | 340 | _scene.RemoveVehiclePrim(this); |
350 | } | 341 | } |
351 | else | 342 | else |
352 | { | 343 | { |
344 | _scene.TaintedObject(delegate() | ||
345 | { | ||
346 | // Tell the physics engine to clear state | ||
347 | BulletSimAPI.ClearForces2(this.Body.Ptr); | ||
348 | }); | ||
349 | |||
353 | // make it so the scene will call us each tick to do vehicle things | 350 | // make it so the scene will call us each tick to do vehicle things |
354 | _scene.AddVehiclePrim(this); | 351 | _scene.AddVehiclePrim(this); |
355 | } | 352 | } |
@@ -359,47 +356,59 @@ public sealed class BSPrim : PhysicsActor | |||
359 | } | 356 | } |
360 | public override void VehicleFloatParam(int param, float value) | 357 | public override void VehicleFloatParam(int param, float value) |
361 | { | 358 | { |
362 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 359 | _scene.TaintedObject(delegate() |
360 | { | ||
361 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | ||
362 | }); | ||
363 | } | 363 | } |
364 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 364 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
365 | { | 365 | { |
366 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 366 | _scene.TaintedObject(delegate() |
367 | { | ||
368 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | ||
369 | }); | ||
367 | } | 370 | } |
368 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 371 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
369 | { | 372 | { |
370 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 373 | _scene.TaintedObject(delegate() |
374 | { | ||
375 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
376 | }); | ||
371 | } | 377 | } |
372 | public override void VehicleFlags(int param, bool remove) | 378 | public override void VehicleFlags(int param, bool remove) |
373 | { | 379 | { |
374 | _vehicle.ProcessVehicleFlags(param, remove); | 380 | _scene.TaintedObject(delegate() |
381 | { | ||
382 | _vehicle.ProcessVehicleFlags(param, remove); | ||
383 | }); | ||
375 | } | 384 | } |
376 | // Called each simulation step to advance vehicle characteristics | 385 | |
386 | // Called each simulation step to advance vehicle characteristics. | ||
387 | // Called from Scene when doing simulation step so we're in taint processing time. | ||
377 | public void StepVehicle(float timeStep) | 388 | public void StepVehicle(float timeStep) |
378 | { | 389 | { |
379 | _vehicle.Step(timeStep, _scene); | 390 | if (IsPhysical) |
391 | _vehicle.Step(timeStep); | ||
380 | } | 392 | } |
381 | 393 | ||
382 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 394 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
383 | public override void SetVolumeDetect(int param) { | 395 | public override void SetVolumeDetect(int param) { |
384 | bool newValue = (param != 0); | 396 | bool newValue = (param != 0); |
385 | if (_isVolumeDetect != newValue) | 397 | _isVolumeDetect = newValue; |
398 | _scene.TaintedObject(delegate() | ||
386 | { | 399 | { |
387 | _isVolumeDetect = newValue; | 400 | SetObjectDynamic(); |
388 | _scene.TaintedObject(delegate() | 401 | }); |
389 | { | ||
390 | SetObjectDynamic(); | ||
391 | }); | ||
392 | } | ||
393 | return; | 402 | return; |
394 | } | 403 | } |
395 | 404 | ||
396 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
397 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
398 | public override OMV.Vector3 Velocity { | 405 | public override OMV.Vector3 Velocity { |
399 | get { return _velocity; } | 406 | get { return _velocity; } |
400 | set { _velocity = value; | 407 | set { |
408 | _velocity = value; | ||
401 | _scene.TaintedObject(delegate() | 409 | _scene.TaintedObject(delegate() |
402 | { | 410 | { |
411 | DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity); | ||
403 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); | 412 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); |
404 | }); | 413 | }); |
405 | } | 414 | } |
@@ -407,6 +416,7 @@ public sealed class BSPrim : PhysicsActor | |||
407 | public override OMV.Vector3 Torque { | 416 | public override OMV.Vector3 Torque { |
408 | get { return _torque; } | 417 | get { return _torque; } |
409 | set { _torque = value; | 418 | set { _torque = value; |
419 | DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque); | ||
410 | } | 420 | } |
411 | } | 421 | } |
412 | public override float CollisionScore { | 422 | public override float CollisionScore { |
@@ -419,13 +429,21 @@ public sealed class BSPrim : PhysicsActor | |||
419 | set { _acceleration = value; } | 429 | set { _acceleration = value; } |
420 | } | 430 | } |
421 | public override OMV.Quaternion Orientation { | 431 | public override OMV.Quaternion Orientation { |
422 | get { return _orientation; } | 432 | get { |
433 | if (!_linkset.IsRoot(this)) | ||
434 | { | ||
435 | // Children move around because tied to parent. Get a fresh value. | ||
436 | _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); | ||
437 | } | ||
438 | return _orientation; | ||
439 | } | ||
423 | set { | 440 | set { |
424 | _orientation = value; | 441 | _orientation = value; |
425 | // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); | 442 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
426 | _scene.TaintedObject(delegate() | 443 | _scene.TaintedObject(delegate() |
427 | { | 444 | { |
428 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 445 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
446 | DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
429 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 447 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
430 | }); | 448 | }); |
431 | } | 449 | } |
@@ -458,25 +476,24 @@ public sealed class BSPrim : PhysicsActor | |||
458 | get { return !IsPhantom && !_isVolumeDetect; } | 476 | get { return !IsPhantom && !_isVolumeDetect; } |
459 | } | 477 | } |
460 | 478 | ||
461 | // make gravity work if the object is physical and not selected | 479 | // Make gravity work if the object is physical and not selected |
462 | // no locking here because only called when it is safe | 480 | // No locking here because only called when it is safe |
481 | // Only called at taint time so it is save to call into Bullet. | ||
463 | private void SetObjectDynamic() | 482 | private void SetObjectDynamic() |
464 | { | 483 | { |
465 | // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); | 484 | // RA: remove this for the moment. |
466 | // non-physical things work best with a mass of zero | 485 | // The problem is that dynamic objects are hulls so if we are becoming physical |
467 | if (IsStatic) | 486 | // the shape has to be checked and possibly built. |
468 | { | 487 | // Maybe a VerifyCorrectPhysicalShape() routine? |
469 | _mass = 0f; | 488 | // RecreateGeomAndObject(); |
470 | } | ||
471 | else | ||
472 | { | ||
473 | _mass = CalculateMass(); | ||
474 | // If it's dynamic, make sure the hull has been created for it | ||
475 | // This shouldn't do much work if the object had previously been built | ||
476 | RecreateGeomAndObject(); | ||
477 | 489 | ||
478 | } | 490 | float mass = _mass; |
479 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); | 491 | // Bullet wants static objects have a mass of zero |
492 | if (IsStatic) | ||
493 | mass = 0f; | ||
494 | |||
495 | DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass); | ||
496 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass); | ||
480 | } | 497 | } |
481 | 498 | ||
482 | // prims don't fly | 499 | // prims don't fly |
@@ -516,11 +533,24 @@ public sealed class BSPrim : PhysicsActor | |||
516 | set { _floatOnWater = value; } | 533 | set { _floatOnWater = value; } |
517 | } | 534 | } |
518 | public override OMV.Vector3 RotationalVelocity { | 535 | public override OMV.Vector3 RotationalVelocity { |
519 | get { return _rotationalVelocity; } | 536 | get { |
520 | set { _rotationalVelocity = value; | 537 | /* |
538 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
539 | // if close to zero, report zero | ||
540 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
541 | // zero the property in the physics engine. | ||
542 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
543 | return pv; | ||
544 | */ | ||
545 | |||
546 | return _rotationalVelocity; | ||
547 | } | ||
548 | set { | ||
549 | _rotationalVelocity = value; | ||
521 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 550 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
522 | _scene.TaintedObject(delegate() | 551 | _scene.TaintedObject(delegate() |
523 | { | 552 | { |
553 | DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
524 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); | 554 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); |
525 | }); | 555 | }); |
526 | } | 556 | } |
@@ -533,11 +563,13 @@ public sealed class BSPrim : PhysicsActor | |||
533 | } | 563 | } |
534 | public override float Buoyancy { | 564 | public override float Buoyancy { |
535 | get { return _buoyancy; } | 565 | get { return _buoyancy; } |
536 | set { _buoyancy = value; | 566 | set { |
537 | _scene.TaintedObject(delegate() | 567 | _buoyancy = value; |
538 | { | 568 | _scene.TaintedObject(delegate() |
539 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | 569 | { |
540 | }); | 570 | DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
571 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
572 | }); | ||
541 | } | 573 | } |
542 | } | 574 | } |
543 | 575 | ||
@@ -573,27 +605,45 @@ public sealed class BSPrim : PhysicsActor | |||
573 | public override float APIDStrength { set { return; } } | 605 | public override float APIDStrength { set { return; } } |
574 | public override float APIDDamping { set { return; } } | 606 | public override float APIDDamping { set { return; } } |
575 | 607 | ||
608 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | ||
576 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 609 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
577 | if (force.IsFinite()) | 610 | if (force.IsFinite()) |
578 | { | 611 | { |
579 | _force.X += force.X; | 612 | // _force += force; |
580 | _force.Y += force.Y; | 613 | lock (m_accumulatedForces) |
581 | _force.Z += force.Z; | 614 | m_accumulatedForces.Add(new OMV.Vector3(force)); |
582 | } | 615 | } |
583 | else | 616 | else |
584 | { | 617 | { |
585 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); | 618 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); |
619 | return; | ||
586 | } | 620 | } |
587 | _scene.TaintedObject(delegate() | 621 | _scene.TaintedObject(delegate() |
588 | { | 622 | { |
589 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | 623 | lock (m_accumulatedForces) |
624 | { | ||
625 | if (m_accumulatedForces.Count > 0) | ||
626 | { | ||
627 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
628 | foreach (OMV.Vector3 v in m_accumulatedForces) | ||
629 | { | ||
630 | fSum += v; | ||
631 | } | ||
632 | m_accumulatedForces.Clear(); | ||
633 | |||
634 | DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum); | ||
635 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum); | ||
636 | } | ||
637 | } | ||
590 | }); | 638 | }); |
591 | } | 639 | } |
592 | 640 | ||
593 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 641 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
642 | DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); | ||
594 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | 643 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); |
595 | } | 644 | } |
596 | public override void SetMomentum(OMV.Vector3 momentum) { | 645 | public override void SetMomentum(OMV.Vector3 momentum) { |
646 | DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum); | ||
597 | } | 647 | } |
598 | public override void SubscribeEvents(int ms) { | 648 | public override void SubscribeEvents(int ms) { |
599 | _subscribedEventsMs = ms; | 649 | _subscribedEventsMs = ms; |
@@ -885,6 +935,9 @@ public sealed class BSPrim : PhysicsActor | |||
885 | 935 | ||
886 | returnMass = _density * volume; | 936 | returnMass = _density * volume; |
887 | 937 | ||
938 | /* | ||
939 | * This change means each object keeps its own mass and the Mass property | ||
940 | * will return the sum if we're part of a linkset. | ||
888 | if (IsRootOfLinkset) | 941 | if (IsRootOfLinkset) |
889 | { | 942 | { |
890 | foreach (BSPrim prim in _childrenPrims) | 943 | foreach (BSPrim prim in _childrenPrims) |
@@ -892,6 +945,7 @@ public sealed class BSPrim : PhysicsActor | |||
892 | returnMass += prim.CalculateMass(); | 945 | returnMass += prim.CalculateMass(); |
893 | } | 946 | } |
894 | } | 947 | } |
948 | */ | ||
895 | 949 | ||
896 | if (returnMass <= 0) | 950 | if (returnMass <= 0) |
897 | returnMass = 0.0001f; | 951 | returnMass = 0.0001f; |
@@ -907,9 +961,11 @@ public sealed class BSPrim : PhysicsActor | |||
907 | // The objects needs a hull if it's physical otherwise a mesh is enough | 961 | // The objects needs a hull if it's physical otherwise a mesh is enough |
908 | // No locking here because this is done when we know physics is not simulating | 962 | // No locking here because this is done when we know physics is not simulating |
909 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used | 963 | // if 'forceRebuild' is true, the geometry is rebuilt. Otherwise a previously built version is used |
910 | private void CreateGeom(bool forceRebuild) | 964 | // Returns 'true' if the geometry was rebuilt |
965 | private bool CreateGeom(bool forceRebuild) | ||
911 | { | 966 | { |
912 | // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. | 967 | // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. |
968 | bool ret = false; | ||
913 | if (!_scene.NeedsMeshing(_pbs)) | 969 | if (!_scene.NeedsMeshing(_pbs)) |
914 | { | 970 | { |
915 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) | 971 | if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1) |
@@ -917,16 +973,28 @@ public sealed class BSPrim : PhysicsActor | |||
917 | if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) | 973 | if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z) |
918 | { | 974 | { |
919 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); | 975 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); |
920 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | 976 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE)) |
921 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 977 | { |
922 | _scale = _size; | 978 | DetailLog("{0},CreateGeom,sphere", LocalID); |
979 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | ||
980 | // Bullet native objects are scaled by the Bullet engine so pass the size in | ||
981 | _scale = _size; | ||
982 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
983 | ret = true; | ||
984 | } | ||
923 | } | 985 | } |
924 | } | 986 | } |
925 | else | 987 | else |
926 | { | 988 | { |
927 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); | 989 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, type={2}, size={3}", LogHeader, LocalID, _shapeType, _size); |
928 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | 990 | if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_BOX)) |
929 | _scale = _size; | 991 | { |
992 | DetailLog("{0},CreateGeom,box", LocalID); | ||
993 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | ||
994 | _scale = _size; | ||
995 | // TODO: do we need to check for and destroy a mesh or hull that might have been left from before? | ||
996 | ret = true; | ||
997 | } | ||
930 | } | 998 | } |
931 | } | 999 | } |
932 | else | 1000 | else |
@@ -938,6 +1006,7 @@ public sealed class BSPrim : PhysicsActor | |||
938 | // physical objects require a hull for interaction. | 1006 | // physical objects require a hull for interaction. |
939 | // This will create the mesh if it doesn't already exist | 1007 | // This will create the mesh if it doesn't already exist |
940 | CreateGeomHull(); | 1008 | CreateGeomHull(); |
1009 | ret = true; | ||
941 | } | 1010 | } |
942 | } | 1011 | } |
943 | else | 1012 | else |
@@ -946,9 +1015,11 @@ public sealed class BSPrim : PhysicsActor | |||
946 | { | 1015 | { |
947 | // Static (non-physical) objects only need a mesh for bumping into | 1016 | // Static (non-physical) objects only need a mesh for bumping into |
948 | CreateGeomMesh(); | 1017 | CreateGeomMesh(); |
1018 | ret = true; | ||
949 | } | 1019 | } |
950 | } | 1020 | } |
951 | } | 1021 | } |
1022 | return ret; | ||
952 | } | 1023 | } |
953 | 1024 | ||
954 | // No locking here because this is done when we know physics is not simulating | 1025 | // No locking here because this is done when we know physics is not simulating |
@@ -961,10 +1032,12 @@ public sealed class BSPrim : PhysicsActor | |||
961 | // if this new shape is the same as last time, don't recreate the mesh | 1032 | // if this new shape is the same as last time, don't recreate the mesh |
962 | if (_meshKey == newMeshKey) return; | 1033 | if (_meshKey == newMeshKey) return; |
963 | 1034 | ||
1035 | DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey); | ||
964 | // Since we're recreating new, get rid of any previously generated shape | 1036 | // Since we're recreating new, get rid of any previously generated shape |
965 | if (_meshKey != 0) | 1037 | if (_meshKey != 0) |
966 | { | 1038 | { |
967 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | 1039 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); |
1040 | DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); | ||
968 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | 1041 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); |
969 | _mesh = null; | 1042 | _mesh = null; |
970 | _meshKey = 0; | 1043 | _meshKey = 0; |
@@ -981,7 +1054,6 @@ public sealed class BSPrim : PhysicsActor | |||
981 | int vi = 0; | 1054 | int vi = 0; |
982 | foreach (OMV.Vector3 vv in vertices) | 1055 | foreach (OMV.Vector3 vv in vertices) |
983 | { | 1056 | { |
984 | // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z); | ||
985 | verticesAsFloats[vi++] = vv.X; | 1057 | verticesAsFloats[vi++] = vv.X; |
986 | verticesAsFloats[vi++] = vv.Y; | 1058 | verticesAsFloats[vi++] = vv.Y; |
987 | verticesAsFloats[vi++] = vv.Z; | 1059 | verticesAsFloats[vi++] = vv.Z; |
@@ -995,6 +1067,7 @@ public sealed class BSPrim : PhysicsActor | |||
995 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | 1067 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; |
996 | // meshes are already scaled by the meshmerizer | 1068 | // meshes are already scaled by the meshmerizer |
997 | _scale = new OMV.Vector3(1f, 1f, 1f); | 1069 | _scale = new OMV.Vector3(1f, 1f, 1f); |
1070 | DetailLog("{0},CreateGeomMesh,done", LocalID); | ||
998 | return; | 1071 | return; |
999 | } | 1072 | } |
1000 | 1073 | ||
@@ -1008,13 +1081,17 @@ public sealed class BSPrim : PhysicsActor | |||
1008 | // if the hull hasn't changed, don't rebuild it | 1081 | // if the hull hasn't changed, don't rebuild it |
1009 | if (newHullKey == _hullKey) return; | 1082 | if (newHullKey == _hullKey) return; |
1010 | 1083 | ||
1084 | DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey); | ||
1085 | |||
1011 | // Since we're recreating new, get rid of any previously generated shape | 1086 | // Since we're recreating new, get rid of any previously generated shape |
1012 | if (_hullKey != 0) | 1087 | if (_hullKey != 0) |
1013 | { | 1088 | { |
1014 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); | 1089 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); |
1090 | DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey); | ||
1015 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | 1091 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); |
1016 | _hullKey = 0; | 1092 | _hullKey = 0; |
1017 | _hulls.Clear(); | 1093 | _hulls.Clear(); |
1094 | DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey); | ||
1018 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | 1095 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); |
1019 | _mesh = null; // the mesh cannot match either | 1096 | _mesh = null; // the mesh cannot match either |
1020 | _meshKey = 0; | 1097 | _meshKey = 0; |
@@ -1111,6 +1188,7 @@ public sealed class BSPrim : PhysicsActor | |||
1111 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | 1188 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; |
1112 | // meshes are already scaled by the meshmerizer | 1189 | // meshes are already scaled by the meshmerizer |
1113 | _scale = new OMV.Vector3(1f, 1f, 1f); | 1190 | _scale = new OMV.Vector3(1f, 1f, 1f); |
1191 | DetailLog("{0},CreateGeomHull,done", LocalID); | ||
1114 | return; | 1192 | return; |
1115 | } | 1193 | } |
1116 | 1194 | ||
@@ -1124,47 +1202,21 @@ public sealed class BSPrim : PhysicsActor | |||
1124 | 1202 | ||
1125 | // Create an object in Bullet if it has not already been created | 1203 | // Create an object in Bullet if it has not already been created |
1126 | // No locking here because this is done when the physics engine is not simulating | 1204 | // No locking here because this is done when the physics engine is not simulating |
1127 | private void CreateObject() | 1205 | // Returns 'true' if an object was actually created. |
1206 | private bool CreateObject() | ||
1128 | { | 1207 | { |
1129 | if (IsRootOfLinkset) | 1208 | // this routine is called when objects are rebuilt. |
1130 | { | ||
1131 | // Create a linkset around this object | ||
1132 | // CreateLinksetWithCompoundHull(); | ||
1133 | CreateLinksetWithConstraints(); | ||
1134 | } | ||
1135 | else | ||
1136 | { | ||
1137 | // simple object | ||
1138 | // the mesh or hull must have already been created in Bullet | ||
1139 | ShapeData shape; | ||
1140 | FillShapeInfo(out shape); | ||
1141 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); | ||
1142 | BulletSimAPI.CreateObject(_scene.WorldID, shape); | ||
1143 | } | ||
1144 | } | ||
1145 | 1209 | ||
1146 | // Create a linkset by creating a compound hull at the root prim that consists of all | 1210 | // the mesh or hull must have already been created in Bullet |
1147 | // the children. | 1211 | ShapeData shape; |
1148 | // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution | 1212 | FillShapeInfo(out shape); |
1149 | void CreateLinksetWithCompoundHull() | 1213 | // m_log.DebugFormat("{0}: CreateObject: lID={1}, shape={2}", LogHeader, _localID, shape.Type); |
1150 | { | 1214 | bool ret = BulletSimAPI.CreateObject(_scene.WorldID, shape); |
1151 | // If I am the root prim of a linkset, replace my physical shape with all the | 1215 | |
1152 | // pieces of the children. | 1216 | // the CreateObject() may have recreated the rigid body. Make sure we have the latest. |
1153 | // All of the children should have called CreateGeom so they have a hull | 1217 | m_body.Ptr = BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID); |
1154 | // in the physics engine already. Here we pull together all of those hulls | 1218 | |
1155 | // into one shape. | 1219 | return ret; |
1156 | int totalPrimsInLinkset = _childrenPrims.Count + 1; | ||
1157 | // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset); | ||
1158 | ShapeData[] shapes = new ShapeData[totalPrimsInLinkset]; | ||
1159 | FillShapeInfo(out shapes[0]); | ||
1160 | int ii = 1; | ||
1161 | foreach (BSPrim prim in _childrenPrims) | ||
1162 | { | ||
1163 | // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID); | ||
1164 | prim.FillShapeInfo(out shapes[ii]); | ||
1165 | ii++; | ||
1166 | } | ||
1167 | BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes); | ||
1168 | } | 1220 | } |
1169 | 1221 | ||
1170 | // Copy prim's info into the BulletSim shape description structure | 1222 | // Copy prim's info into the BulletSim shape description structure |
@@ -1186,44 +1238,6 @@ public sealed class BSPrim : PhysicsActor | |||
1186 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; | 1238 | shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; |
1187 | } | 1239 | } |
1188 | 1240 | ||
1189 | // Create the linkset by putting constraints between the objects of the set so they cannot move | ||
1190 | // relative to each other. | ||
1191 | // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added | ||
1192 | void CreateLinksetWithConstraints() | ||
1193 | { | ||
1194 | // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); | ||
1195 | |||
1196 | // remove any constraints that might be in place | ||
1197 | foreach (BSPrim prim in _childrenPrims) | ||
1198 | { | ||
1199 | // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1200 | BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); | ||
1201 | } | ||
1202 | // create constraints between the root prim and each of the children | ||
1203 | foreach (BSPrim prim in _childrenPrims) | ||
1204 | { | ||
1205 | // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1206 | |||
1207 | // Zero motion for children so they don't interpolate | ||
1208 | prim.ZeroMotion(); | ||
1209 | |||
1210 | // relative position normalized to the root prim | ||
1211 | OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); | ||
1212 | |||
1213 | // relative rotation of the child to the parent | ||
1214 | OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; | ||
1215 | |||
1216 | // this is a constraint that allows no freedom of movement between the two objects | ||
1217 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
1218 | BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, | ||
1219 | childRelativePosition, | ||
1220 | relativeRotation, | ||
1221 | OMV.Vector3.Zero, | ||
1222 | OMV.Quaternion.Identity, | ||
1223 | OMV.Vector3.Zero, OMV.Vector3.Zero, | ||
1224 | OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
1225 | } | ||
1226 | } | ||
1227 | 1241 | ||
1228 | // Rebuild the geometry and object. | 1242 | // Rebuild the geometry and object. |
1229 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1243 | // This is called when the shape changes so we need to recreate the mesh/hull. |
@@ -1231,8 +1245,8 @@ public sealed class BSPrim : PhysicsActor | |||
1231 | private void RecreateGeomAndObject() | 1245 | private void RecreateGeomAndObject() |
1232 | { | 1246 | { |
1233 | // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); | 1247 | // m_log.DebugFormat("{0}: RecreateGeomAndObject. lID={1}", LogHeader, _localID); |
1234 | CreateGeom(true); | 1248 | if (CreateGeom(true)) |
1235 | CreateObject(); | 1249 | CreateObject(); |
1236 | return; | 1250 | return; |
1237 | } | 1251 | } |
1238 | 1252 | ||
@@ -1252,78 +1266,78 @@ public sealed class BSPrim : PhysicsActor | |||
1252 | const float POSITION_TOLERANCE = 0.05f; | 1266 | const float POSITION_TOLERANCE = 0.05f; |
1253 | const float ACCELERATION_TOLERANCE = 0.01f; | 1267 | const float ACCELERATION_TOLERANCE = 0.01f; |
1254 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | 1268 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; |
1255 | const bool SHOULD_DAMP_UPDATES = false; | ||
1256 | 1269 | ||
1257 | public void UpdateProperties(EntityProperties entprop) | 1270 | public void UpdateProperties(EntityProperties entprop) |
1258 | { | 1271 | { |
1272 | /* | ||
1259 | UpdatedProperties changed = 0; | 1273 | UpdatedProperties changed = 0; |
1260 | if (SHOULD_DAMP_UPDATES) | 1274 | // assign to the local variables so the normal set action does not happen |
1275 | // if (_position != entprop.Position) | ||
1276 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1261 | { | 1277 | { |
1262 | // assign to the local variables so the normal set action does not happen | 1278 | _position = entprop.Position; |
1263 | // if (_position != entprop.Position) | 1279 | changed |= UpdatedProperties.Position; |
1264 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1265 | { | ||
1266 | _position = entprop.Position; | ||
1267 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position); | ||
1268 | changed |= UpdatedProperties.Position; | ||
1269 | } | ||
1270 | // if (_orientation != entprop.Rotation) | ||
1271 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1272 | { | ||
1273 | _orientation = entprop.Rotation; | ||
1274 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation); | ||
1275 | changed |= UpdatedProperties.Rotation; | ||
1276 | } | ||
1277 | // if (_velocity != entprop.Velocity) | ||
1278 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1279 | { | ||
1280 | _velocity = entprop.Velocity; | ||
1281 | // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); | ||
1282 | changed |= UpdatedProperties.Velocity; | ||
1283 | } | ||
1284 | // if (_acceleration != entprop.Acceleration) | ||
1285 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1286 | { | ||
1287 | _acceleration = entprop.Acceleration; | ||
1288 | // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); | ||
1289 | changed |= UpdatedProperties.Acceleration; | ||
1290 | } | ||
1291 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1292 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1293 | { | ||
1294 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1295 | // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); | ||
1296 | changed |= UpdatedProperties.RotationalVel; | ||
1297 | } | ||
1298 | if (changed != 0) | ||
1299 | { | ||
1300 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1301 | // Only update the position of single objects and linkset roots | ||
1302 | if (this._parentPrim == null) | ||
1303 | { | ||
1304 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1305 | base.RequestPhysicsterseUpdate(); | ||
1306 | } | ||
1307 | } | ||
1308 | } | 1280 | } |
1309 | else | 1281 | // if (_orientation != entprop.Rotation) |
1282 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1310 | { | 1283 | { |
1311 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | 1284 | _orientation = entprop.Rotation; |
1312 | 1285 | changed |= UpdatedProperties.Rotation; | |
1313 | // Only updates only for individual prims and for the root object of a linkset. | 1286 | } |
1287 | // if (_velocity != entprop.Velocity) | ||
1288 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1289 | { | ||
1290 | _velocity = entprop.Velocity; | ||
1291 | changed |= UpdatedProperties.Velocity; | ||
1292 | } | ||
1293 | // if (_acceleration != entprop.Acceleration) | ||
1294 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1295 | { | ||
1296 | _acceleration = entprop.Acceleration; | ||
1297 | changed |= UpdatedProperties.Acceleration; | ||
1298 | } | ||
1299 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1300 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1301 | { | ||
1302 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1303 | changed |= UpdatedProperties.RotationalVel; | ||
1304 | } | ||
1305 | if (changed != 0) | ||
1306 | { | ||
1307 | // Only update the position of single objects and linkset roots | ||
1314 | if (this._parentPrim == null) | 1308 | if (this._parentPrim == null) |
1315 | { | 1309 | { |
1316 | // Assign to the local variables so the normal set action does not happen | ||
1317 | _position = entprop.Position; | ||
1318 | _orientation = entprop.Rotation; | ||
1319 | _velocity = entprop.Velocity; | ||
1320 | _acceleration = entprop.Acceleration; | ||
1321 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1322 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", | ||
1323 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1324 | base.RequestPhysicsterseUpdate(); | 1310 | base.RequestPhysicsterseUpdate(); |
1325 | } | 1311 | } |
1326 | } | 1312 | } |
1313 | */ | ||
1314 | |||
1315 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1316 | |||
1317 | // Updates only for individual prims and for the root object of a linkset. | ||
1318 | if (_linkset.IsRoot(this)) | ||
1319 | { | ||
1320 | // Assign to the local variables so the normal set action does not happen | ||
1321 | _position = entprop.Position; | ||
1322 | _orientation = entprop.Rotation; | ||
1323 | _velocity = entprop.Velocity; | ||
1324 | _acceleration = entprop.Acceleration; | ||
1325 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1326 | |||
1327 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", | ||
1328 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1329 | DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1330 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1331 | |||
1332 | base.RequestPhysicsterseUpdate(); | ||
1333 | } | ||
1334 | else | ||
1335 | { | ||
1336 | // For debugging, we can also report the movement of children | ||
1337 | DetailLog("{0},UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1338 | LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, | ||
1339 | entprop.Acceleration, entprop.RotationalVelocity); | ||
1340 | } | ||
1327 | } | 1341 | } |
1328 | 1342 | ||
1329 | // I've collided with something | 1343 | // I've collided with something |
@@ -1362,5 +1376,11 @@ public sealed class BSPrim : PhysicsActor | |||
1362 | collisionCollection.Clear(); | 1376 | collisionCollection.Clear(); |
1363 | } | 1377 | } |
1364 | } | 1378 | } |
1379 | |||
1380 | // Invoke the detailed logger and output something if it's enabled. | ||
1381 | private void DetailLog(string msg, params Object[] args) | ||
1382 | { | ||
1383 | Scene.PhysicsLogging.Write(msg, args); | ||
1384 | } | ||
1365 | } | 1385 | } |
1366 | } | 1386 | } |