OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BSLinkset.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyrightD
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 using System;
28 using System.Collections.Generic;
29 using System.Text;
30 
31 using OMV = OpenMetaverse;
32 
33 namespace OpenSim.Region.PhysicsModule.BulletS
34 {
35 
36 public abstract class BSLinkset
37 {
38  // private static string LogHeader = "[BULLETSIM LINKSET]";
39 
41  {
42  Constraint = 0, // linkset tied together with constraints
43  Compound = 1, // linkset tied together as a compound object
44  Manual = 2 // linkset tied together manually (code moves all the pieces)
45  }
46  // Create the correct type of linkset for this child
47  public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
48  {
49  BSLinkset ret = null;
50 
51  switch (parent.LinksetType)
52  {
53  case LinksetImplementation.Constraint:
54  ret = new BSLinksetConstraints(physScene, parent);
55  break;
56  case LinksetImplementation.Compound:
57  ret = new BSLinksetCompound(physScene, parent);
58  break;
59  case LinksetImplementation.Manual:
60  // ret = new BSLinksetManual(physScene, parent);
61  break;
62  default:
63  ret = new BSLinksetCompound(physScene, parent);
64  break;
65  }
66  if (ret == null)
67  {
68  physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
69  }
70  return ret;
71  }
72 
73  public class BSLinkInfo
74  {
76  public BSLinkInfo(BSPrimLinkable pMember)
77  {
78  member = pMember;
79  }
80  public virtual void ResetLink() { }
81  public virtual void SetLinkParameters(BSConstraint constrain) { }
82  // Returns 'true' if physical property updates from the child should be reported to the simulator
83  public virtual bool ShouldUpdateChildProperties() { return false; }
84  }
85 
86  public LinksetImplementation LinksetImpl { get; protected set; }
87 
88  public BSPrimLinkable LinksetRoot { get; protected set; }
89 
90  protected BSScene m_physicsScene { get; private set; }
91 
92  static int m_nextLinksetID = 1;
93  public int LinksetID { get; private set; }
94 
95  // The children under the root in this linkset.
96  // protected HashSet<BSPrimLinkable> m_children;
97  protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
98 
99  // We lock the diddling of linkset classes to prevent any badness.
100  // This locks the modification of the instances of this class. Changes
101  // to the physical representation is done via the tainting mechenism.
102  protected object m_linksetActivityLock = new Object();
103 
104  // We keep the prim's mass in the linkset structure since it could be dependent on other prims
105  public float LinksetMass { get; protected set; }
106 
107  public virtual bool LinksetIsColliding { get { return false; } }
108 
109  public OMV.Vector3 CenterOfMass
110  {
111  get { return ComputeLinksetCenterOfMass(); }
112  }
113 
114  public OMV.Vector3 GeometricCenter
115  {
116  get { return ComputeLinksetGeometricCenter(); }
117  }
118 
119  protected BSLinkset(BSScene scene, BSPrimLinkable parent)
120  {
121  // A simple linkset of one (no children)
122  LinksetID = m_nextLinksetID++;
123  // We create LOTS of linksets.
124  if (m_nextLinksetID <= 0)
125  m_nextLinksetID = 1;
126  m_physicsScene = scene;
127  LinksetRoot = parent;
128  m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
129  LinksetMass = parent.RawMass;
130  Rebuilding = false;
131  RebuildScheduled = false;
132 
133  parent.ClearDisplacement();
134  }
135 
136  // Link to a linkset where the child knows the parent.
137  // Parent changing should not happen so do some sanity checking.
138  // We return the parent's linkset so the child can track its membership.
139  // Called at runtime.
141  {
142  lock (m_linksetActivityLock)
143  {
144  // Don't add the root to its own linkset
145  if (!IsRoot(child))
146  AddChildToLinkset(child);
147  LinksetMass = ComputeLinksetMass();
148  }
149  return this;
150  }
151 
152  // Remove a child from a linkset.
153  // Returns a new linkset for the child which is a linkset of one (just the
154  // orphened child).
155  // Called at runtime.
156  public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
157  {
158  lock (m_linksetActivityLock)
159  {
160  if (IsRoot(child))
161  {
162  // Cannot remove the root from a linkset.
163  return this;
164  }
165  RemoveChildFromLinkset(child, inTaintTime);
166  LinksetMass = ComputeLinksetMass();
167  }
168 
169  // The child is down to a linkset of just itself
170  return BSLinkset.Factory(m_physicsScene, child);
171  }
172 
173  // Return 'true' if the passed object is the root object of this linkset
174  public bool IsRoot(BSPrimLinkable requestor)
175  {
176  return (requestor.LocalID == LinksetRoot.LocalID);
177  }
178 
179  public int NumberOfChildren { get { return m_children.Count; } }
180 
181  // Return 'true' if this linkset has any children (more than the root member)
182  public bool HasAnyChildren { get { return (m_children.Count > 0); } }
183 
184  // Return 'true' if this child is in this linkset
185  public bool HasChild(BSPrimLinkable child)
186  {
187  bool ret = false;
188  lock (m_linksetActivityLock)
189  {
190  ret = m_children.ContainsKey(child);
191  }
192  return ret;
193  }
194 
195  // Perform an action on each member of the linkset including root prim.
196  // Depends on the action on whether this should be done at taint time.
197  public delegate bool ForEachMemberAction(BSPrimLinkable obj);
198  public virtual bool ForEachMember(ForEachMemberAction action)
199  {
200  bool ret = false;
201  lock (m_linksetActivityLock)
202  {
203  action(LinksetRoot);
204  foreach (BSPrimLinkable po in m_children.Keys)
205  {
206  if (action(po))
207  break;
208  }
209  }
210  return ret;
211  }
212 
213  public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
214  {
215  bool ret = false;
216  BSLinkInfo found = null;
217  lock (m_linksetActivityLock)
218  {
219  ret = m_children.TryGetValue(child, out found);
220  }
221  foundInfo = found;
222  return ret;
223  }
224  // Perform an action on each member of the linkset including root prim.
225  // Depends on the action on whether this should be done at taint time.
226  public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
227  public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
228  {
229  bool ret = false;
230  lock (m_linksetActivityLock)
231  {
232  foreach (BSLinkInfo po in m_children.Values)
233  {
234  if (action(po))
235  break;
236  }
237  }
238  return ret;
239  }
240 
241  // Check the type of the link and return 'true' if the link is flexible and the
242  // updates from the child should be sent to the simulator so things change.
243  public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
244  {
245  bool ret = false;
246 
247  BSLinkInfo linkInfo;
248  if (m_children.TryGetValue(child, out linkInfo))
249  {
250  ret = linkInfo.ShouldUpdateChildProperties();
251  }
252 
253  return ret;
254  }
255 
256  // Called after a simulation step to post a collision with this object.
257  // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
258  // anything to add for the collision and it should be passed through normal processing.
259  // Default processing for a linkset.
260  public virtual bool HandleCollide(BSPhysObject collider, BSPhysObject collidee,
261  OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
262  {
263  bool ret = false;
264 
265  // prims in the same linkset cannot collide with each other
266  BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
267  if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
268  {
269  // By returning 'true', we tell the caller the collision has been 'handled' so it won't
270  // do anything about this collision and thus, effectivily, ignoring the collision.
271  ret = true;
272  }
273  else
274  {
275  // Not a collision between members of the linkset. Must be a real collision.
276  // So the linkset root can know if there is a collision anywhere in the linkset.
277  LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
278  }
279 
280  return ret;
281  }
282 
283  // I am the root of a linkset and a new child is being added
284  // Called while LinkActivity is locked.
285  protected abstract void AddChildToLinkset(BSPrimLinkable child);
286 
287  // I am the root of a linkset and one of my children is being removed.
288  // Safe to call even if the child is not really in my linkset.
289  protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
290 
291  // When physical properties are changed the linkset needs to recalculate
292  // its internal properties.
293  // May be called at runtime or taint-time.
294  public virtual void Refresh(BSPrimLinkable requestor)
295  {
296  LinksetMass = ComputeLinksetMass();
297  }
298 
299  // Flag denoting the linkset is in the process of being rebuilt.
300  // Used to know not the schedule a rebuild in the middle of a rebuild.
301  // Because of potential update calls that could want to schedule another rebuild.
302  protected bool Rebuilding { get; set; }
303 
304  // Flag saying a linkset rebuild has been scheduled.
305  // This is turned on when the rebuild is requested and turned off when
306  // the rebuild is complete. Used to limit modifications to the
307  // linkset parameters while the linkset is in an intermediate state.
308  // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
309  public bool RebuildScheduled { get; protected set; }
310 
311  // The object is going dynamic (physical). Do any setup necessary
312  // for a dynamic linkset.
313  // Only the state of the passed object can be modified. The rest of the linkset
314  // has not yet been fully constructed.
315  // Return 'true' if any properties updated on the passed object.
316  // Called at taint-time!
317  public abstract bool MakeDynamic(BSPrimLinkable child);
318 
319  public virtual bool AllPartsComplete
320  {
321  get {
322  bool ret = true;
323  this.ForEachMember((member) =>
324  {
325  if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
326  {
327  ret = false;
328  return true; // exit loop
329  }
330  return false; // continue loop
331  });
332  return ret;
333  }
334  }
335 
336  // The object is going static (non-physical). Do any setup necessary
337  // for a static linkset.
338  // Return 'true' if any properties updated on the passed object.
339  // Called at taint-time!
340  public abstract bool MakeStatic(BSPrimLinkable child);
341 
342  // Called when a parameter update comes from the physics engine for any object
343  // of the linkset is received.
344  // Passed flag is update came from physics engine (true) or the user (false).
345  // Called at taint-time!!
346  public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
347 
348  // Routine used when rebuilding the body of the root of the linkset
349  // Destroy all the constraints have have been made to root.
350  // This is called when the root body is changing.
351  // Returns 'true' of something was actually removed and would need restoring
352  // Called at taint-time!!
353  public abstract bool RemoveDependencies(BSPrimLinkable child);
354 
355  // ================================================================
356  // Some physical setting happen to all members of the linkset
357  public virtual void SetPhysicalFriction(float friction)
358  {
359  ForEachMember((member) =>
360  {
361  if (member.PhysBody.HasPhysicalBody)
362  m_physicsScene.PE.SetFriction(member.PhysBody, friction);
363  return false; // 'false' says to continue looping
364  }
365  );
366  }
367  public virtual void SetPhysicalRestitution(float restitution)
368  {
369  ForEachMember((member) =>
370  {
371  if (member.PhysBody.HasPhysicalBody)
372  m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
373  return false; // 'false' says to continue looping
374  }
375  );
376  }
377  public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
378  {
379  ForEachMember((member) =>
380  {
381  if (member.PhysBody.HasPhysicalBody)
382  m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
383  return false; // 'false' says to continue looping
384  }
385  );
386  }
387  public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
388  {
389  ForEachMember((member) =>
390  {
391  if (member.PhysBody.HasPhysicalBody)
392  {
393  OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
394  member.Inertia = inertia * inertiaFactor;
395  m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
396  m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
397  DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
398 
399  }
400  return false; // 'false' says to continue looping
401  }
402  );
403  }
404  public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
405  {
406  ForEachMember((member) =>
407  {
408  if (member.PhysBody.HasPhysicalBody)
409  m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
410  return false; // 'false' says to continue looping
411  }
412  );
413  }
414  public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
415  {
416  ForEachMember((member) =>
417  {
418  if (member.PhysBody.HasPhysicalBody)
419  m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
420  return false; // 'false' says to continue looping
421  }
422  );
423  }
424  public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
425  {
426  ForEachMember((member) =>
427  {
428  if (member.PhysBody.HasPhysicalBody)
429  m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
430  return false; // 'false' says to continue looping
431  }
432  );
433  }
434  // ================================================================
435  protected virtual float ComputeLinksetMass()
436  {
437  float mass = LinksetRoot.RawMass;
438  if (HasAnyChildren)
439  {
440  lock (m_linksetActivityLock)
441  {
442  foreach (BSPrimLinkable bp in m_children.Keys)
443  {
444  mass += bp.RawMass;
445  }
446  }
447  }
448  return mass;
449  }
450 
451  // Computes linkset's center of mass in world coordinates.
452  protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
453  {
454  OMV.Vector3 com;
455  lock (m_linksetActivityLock)
456  {
457  com = LinksetRoot.Position * LinksetRoot.RawMass;
458  float totalMass = LinksetRoot.RawMass;
459 
460  foreach (BSPrimLinkable bp in m_children.Keys)
461  {
462  com += bp.Position * bp.RawMass;
463  totalMass += bp.RawMass;
464  }
465  if (totalMass != 0f)
466  com /= totalMass;
467  }
468 
469  return com;
470  }
471 
472  protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
473  {
474  OMV.Vector3 com;
475  lock (m_linksetActivityLock)
476  {
477  com = LinksetRoot.Position;
478 
479  foreach (BSPrimLinkable bp in m_children.Keys)
480  {
481  com += bp.Position;
482  }
483  com /= (m_children.Count + 1);
484  }
485 
486  return com;
487  }
488 
489  #region Extension
490  public virtual object Extension(string pFunct, params object[] pParams)
491  {
492  return null;
493  }
494  #endregion // Extension
495 
496  // Invoke the detailed logger and output something if it's enabled.
497  protected void DetailLog(string msg, params Object[] args)
498  {
499  if (m_physicsScene.PhysicsLogging.Enabled)
500  m_physicsScene.DetailLog(msg, args);
501  }
502 }
503 }
OpenMetaverse OMV
bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
Definition: BSLinkset.cs:213
virtual bool HandleCollide(BSPhysObject collider, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
Definition: BSLinkset.cs:260
virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
Definition: BSLinkset.cs:404
virtual OMV.Vector3 ComputeLinksetGeometricCenter()
Definition: BSLinkset.cs:472
bool IsRoot(BSPrimLinkable requestor)
Definition: BSLinkset.cs:174
virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
Definition: BSLinkset.cs:424
virtual void SetPhysicalGravity(OMV.Vector3 gravity)
Definition: BSLinkset.cs:377
Dictionary< BSPrimLinkable, BSLinkInfo > m_children
Definition: BSLinkset.cs:97
BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
Definition: BSLinkset.cs:156
virtual void SetPhysicalFriction(float friction)
Definition: BSLinkset.cs:357
BSLinkset AddMeToLinkset(BSPrimLinkable child)
Definition: BSLinkset.cs:140
virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
Definition: BSLinkset.cs:414
virtual OMV.Vector3 ComputeLinksetCenterOfMass()
Definition: BSLinkset.cs:452
virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
Definition: BSLinkset.cs:387
virtual void SetPhysicalRestitution(float restitution)
Definition: BSLinkset.cs:367
void DetailLog(string msg, params Object[] args)
Definition: BSLinkset.cs:497
virtual object Extension(string pFunct, params object[] pParams)
Definition: BSLinkset.cs:490
static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
Definition: BSLinkset.cs:47
virtual bool ForEachMember(ForEachMemberAction action)
Definition: BSLinkset.cs:198
virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
Definition: BSLinkset.cs:243
virtual void Refresh(BSPrimLinkable requestor)
Definition: BSLinkset.cs:294
virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
Definition: BSLinkset.cs:227
BSLinkset(BSScene scene, BSPrimLinkable parent)
Definition: BSLinkset.cs:119