aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs292
1 files changed, 280 insertions, 12 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..a113530 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 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. 46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */ 47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
48public abstract class BSPhysObject : PhysicsActor 68public abstract class BSPhysObject : PhysicsActor
49{ 69{
50 protected BSPhysObject() 70 protected BSPhysObject()
@@ -57,13 +77,34 @@ public abstract class BSPhysObject : PhysicsActor
57 PhysObjectName = name; 77 PhysObjectName = name;
58 TypeName = typeName; 78 TypeName = typeName;
59 79
80 // We don't have any physical representation yet.
81 PhysBody = new BulletBody(localID);
82 PhysShape = new BulletShape();
83
84 // A linkset of just me
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 85 Linkset = BSLinkset.Factory(PhysicsScene, this);
86 PositionDisplacement = OMV.Vector3.Zero;
87
61 LastAssetBuildFailed = false; 88 LastAssetBuildFailed = false;
62 89
90 // Default material type
91 Material = MaterialAttributes.Material.Wood;
92
63 CollisionCollection = new CollisionEventUpdate(); 93 CollisionCollection = new CollisionEventUpdate();
94 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 95 SubscribedEventsMs = 0;
65 CollidingStep = 0; 96 CollidingStep = 0;
66 CollidingGroundStep = 0; 97 CollidingGroundStep = 0;
98 CollisionAccumulation = 0;
99 ColliderIsMoving = false;
100 CollisionScore = 0;
101 }
102
103 // Tell the object to clean up.
104 public virtual void Destroy()
105 {
106 UnRegisterAllPreStepActions();
107 UnRegisterAllPostStepActions();
67 } 108 }
68 109
69 public BSScene PhysicsScene { get; protected set; } 110 public BSScene PhysicsScene { get; protected set; }
@@ -72,11 +113,13 @@ public abstract class BSPhysObject : PhysicsActor
72 public string TypeName { get; protected set; } 113 public string TypeName { get; protected set; }
73 114
74 public BSLinkset Linkset { get; set; } 115 public BSLinkset Linkset { get; set; }
116 public BSLinksetInfo LinksetInfo { get; set; }
75 117
76 // Return the object mass without calculating it or having side effects 118 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 119 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 120 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 121 // 'inWorld' true if the object has already been added to the dynamic world.
122 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 123
81 // The last value calculated for the prim's inertia 124 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 125 public OMV.Vector3 Inertia { get; set; }
@@ -105,9 +148,22 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 148 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 149 public EntityProperties LastEntityProperties { get; set; }
107 150
108 public abstract OMV.Vector3 Scale { get; set; } 151 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 152 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 153 public abstract bool IsStatic { get; }
154 public abstract bool IsSelected { get; }
155
156 // It can be confusing for an actor to know if it should move or update an object
157 // depeneding on the setting of 'selected', 'physical, ...
158 // This flag is the true test -- if true, the object is being acted on in the physical world
159 public abstract bool IsPhysicallyActive { get; }
160
161 // Materialness
162 public MaterialAttributes.Material Material { get; private set; }
163 public override void SetMaterial(int material)
164 {
165 Material = (MaterialAttributes.Material)material;
166 }
111 167
112 // Stop all physical motion. 168 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 169 public abstract void ZeroMotion(bool inTaintTime);
@@ -119,15 +175,42 @@ public abstract class BSPhysObject : PhysicsActor
119 // Update the physical location and motion of the object. Called with data from Bullet. 175 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 176 public abstract void UpdateProperties(EntityProperties entprop);
121 177
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 178 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 179 public abstract OMV.Vector3 ForcePosition { get; set; }
127 180
181 // 'Position' and 'Orientation' is what the simulator thinks the positions of the prim is.
182 // Because Bullet needs the zero coordinate to be the center of mass of the linkset,
183 // sometimes it is necessary to displace the position the physics engine thinks
184 // the position is. PositionDisplacement must be added and removed from the
185 // position as the simulator position is stored and fetched from the physics
186 // engine. Similar to OrientationDisplacement.
187 public virtual OMV.Vector3 PositionDisplacement { get; set; }
188 public virtual OMV.Quaternion OrientationDisplacement { get; set; }
189
128 public abstract OMV.Quaternion RawOrientation { get; set; } 190 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 191 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 192
193 // The system is telling us the velocity it wants to move at.
194 // Velocity in world coordinates.
195 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
196 public override OMV.Vector3 TargetVelocity
197 {
198 get { return m_targetVelocity; }
199 set
200 {
201 m_targetVelocity = value;
202 Velocity = value;
203 }
204 }
205 public virtual float TargetSpeed
206 {
207 get
208 {
209 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
210 return characterOrientedVelocity.X;
211 }
212 }
213 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 214 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 215
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 216 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +219,15 @@ public abstract class BSPhysObject : PhysicsActor
136 219
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 220 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 221
222 public virtual float ForwardSpeed
223 {
224 get
225 {
226 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
227 return characterOrientedVelocity.X;
228 }
229 }
230
139 #region Collisions 231 #region Collisions
140 232
141 // Requested number of milliseconds between collision events. Zero means disabled. 233 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,26 +238,71 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 238 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 239 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 240 protected long CollidingGroundStep { get; set; }
241 // The simulation step that last collided with an object
242 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 243 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 244 protected CollisionFlags CurrentCollisionFlags { get; set; }
245 // On a collision, check the collider and remember if the last collider was moving
246 // Used to modify the standing of avatars (avatars on stationary things stand still)
247 protected bool ColliderIsMoving;
248
249 // Count of collisions for this object
250 protected long CollisionAccumulation { get; set; }
251
252 public override bool IsColliding {
253 get { return (CollidingStep == PhysicsScene.SimulationStep); }
254 set {
255 if (value)
256 CollidingStep = PhysicsScene.SimulationStep;
257 else
258 CollidingStep = 0;
259 }
260 }
261 public override bool CollidingGround {
262 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
263 set
264 {
265 if (value)
266 CollidingGroundStep = PhysicsScene.SimulationStep;
267 else
268 CollidingGroundStep = 0;
269 }
270 }
271 public override bool CollidingObj {
272 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
273 set {
274 if (value)
275 CollidingObjectStep = PhysicsScene.SimulationStep;
276 else
277 CollidingObjectStep = 0;
278 }
279 }
151 280
152 // The collisions that have been collected this tick 281 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 282 protected CollisionEventUpdate CollisionCollection;
283 // Remember collisions from last tick for fancy collision based actions
284 // (like a BSCharacter walking up stairs).
285 protected CollisionEventUpdate CollisionsLastTick;
154 286
155 // The simulation step is telling this object about a collision. 287 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 288 // Return 'true' if a collision was processed and should be sent up.
289 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
157 // Called at taint time from within the Step() function 290 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 291 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 292 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 293 {
161 bool ret = false; 294 bool ret = false;
162 295
163 // The following lines make IsColliding() and IsCollidingGround() work 296 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 297 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 298 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 299 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 300 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 301 }
302 else
303 {
304 CollidingObjectStep = PhysicsScene.SimulationStep;
305 }
169 306
170 // prims in the same linkset cannot collide with each other 307 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) 308 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
@@ -173,7 +310,12 @@ public abstract class BSPhysObject : PhysicsActor
173 return ret; 310 return ret;
174 } 311 }
175 312
176 // if someone has subscribed for collision events.... 313 CollisionAccumulation++;
314
315 // For movement tests, remember if we are colliding with an object that is moving.
316 ColliderIsMoving = collidee != null ? collidee.RawVelocity != OMV.Vector3.Zero : false;
317
318 // If someone has subscribed for collision events log the collision so it will be reported up
177 if (SubscribedEvents()) { 319 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 320 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 321 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
@@ -191,8 +333,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 333 public virtual bool SendCollisions()
192 { 334 {
193 bool ret = true; 335 bool ret = true;
336
194 // If the 'no collision' call, force it to happen right now so quick collision_end 337 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 338 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 339
197 // throttle the collisions to the number of milliseconds specified in the subscription 340 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 341 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +350,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 350 ret = false;
208 } 351 }
209 352
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 353 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 354 base.SendCollisionUpdate(CollisionCollection);
212 355
213 // The collisionCollection structure is passed around in the simulator. 356 // Remember the collisions from this tick for some collision specific processing.
357 CollisionsLastTick = CollisionCollection;
358
359 // The CollisionCollection instance 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. 360 // Make sure we don't have a handle to that one and that a new one is used for next time.
361 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
362 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 363 CollisionCollection = new CollisionEventUpdate();
216 } 364 }
217 return ret; 365 return ret;
@@ -229,7 +377,8 @@ public abstract class BSPhysObject : PhysicsActor
229 377
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 378 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 379 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 380 if (PhysBody.HasPhysicalBody)
381 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 382 });
234 } 383 }
235 else 384 else
@@ -243,21 +392,140 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 392 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 393 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 394 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 395 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
396 if (PhysBody.HasPhysicalBody)
397 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 398 });
248 } 399 }
249 // Return 'true' if the simulator wants collision events 400 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() { 401 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0); 402 return (SubscribedEventsMs > 0);
252 } 403 }
404 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
405 // each time called. So this is built to be light weight for each collision and to do
406 // all the processing when the user asks for the info.
407 public void ComputeCollisionScore()
408 {
409 // Scale the collision count by the time since the last collision.
410 // The "+1" prevents dividing by zero.
411 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1;
412 CollisionScore = CollisionAccumulation / timeAgo;
413 }
414 public override float CollisionScore { get; set; }
253 415
254 #endregion // Collisions 416 #endregion // Collisions
255 417
418 #region Per Simulation Step actions
419 // There are some actions that must be performed for a physical object before each simulation step.
420 // These actions are optional so, rather than scanning all the physical objects and asking them
421 // if they have anything to do, a physical object registers for an event call before the step is performed.
422 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
423 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
424 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
425 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
426 {
427 string identifier = op + "-" + id.ToString();
428
429 lock (RegisteredPrestepActions)
430 {
431 // Clean out any existing action
432 UnRegisterPreStepAction(op, id);
433
434 RegisteredPrestepActions[identifier] = actn;
435
436 PhysicsScene.BeforeStep += actn;
437 }
438 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
439 }
440
441 // Unregister a pre step action. Safe to call if the action has not been registered.
442 // Returns 'true' if an action was actually removed
443 protected bool UnRegisterPreStepAction(string op, uint id)
444 {
445 string identifier = op + "-" + id.ToString();
446 bool removed = false;
447 lock (RegisteredPrestepActions)
448 {
449 if (RegisteredPrestepActions.ContainsKey(identifier))
450 {
451 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
452 RegisteredPrestepActions.Remove(identifier);
453 removed = true;
454 }
455 }
456 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
457 return removed;
458 }
459
460 protected void UnRegisterAllPreStepActions()
461 {
462 lock (RegisteredPrestepActions)
463 {
464 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
465 {
466 PhysicsScene.BeforeStep -= kvp.Value;
467 }
468 RegisteredPrestepActions.Clear();
469 }
470 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
471 }
472
473 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
474 {
475 string identifier = op + "-" + id.ToString();
476
477 lock (RegisteredPoststepActions)
478 {
479 // Clean out any existing action
480 UnRegisterPostStepAction(op, id);
481
482 RegisteredPoststepActions[identifier] = actn;
483
484 PhysicsScene.AfterStep += actn;
485 }
486 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
487 }
488
489 // Unregister a pre step action. Safe to call if the action has not been registered.
490 // Returns 'true' if an action was actually removed.
491 protected bool UnRegisterPostStepAction(string op, uint id)
492 {
493 string identifier = op + "-" + id.ToString();
494 bool removed = false;
495 lock (RegisteredPoststepActions)
496 {
497 if (RegisteredPoststepActions.ContainsKey(identifier))
498 {
499 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
500 RegisteredPoststepActions.Remove(identifier);
501 removed = true;
502 }
503 }
504 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
505 return removed;
506 }
507
508 protected void UnRegisterAllPostStepActions()
509 {
510 lock (RegisteredPoststepActions)
511 {
512 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
513 {
514 PhysicsScene.AfterStep -= kvp.Value;
515 }
516 RegisteredPoststepActions.Clear();
517 }
518 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
519 }
520
521 #endregion // Per Simulation Step actions
522
256 // High performance detailed logging routine used by the physical objects. 523 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 524 protected void DetailLog(string msg, params Object[] args)
258 { 525 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 526 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 527 PhysicsScene.DetailLog(msg, args);
261 } 528 }
529
262} 530}
263} 531}