BSLinkset.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. using OMV = OpenMetaverse;
  31. namespace OpenSim.Region.Physics.BulletSPlugin
  32. {
  33. public abstract class BSLinkset
  34. {
  35. // private static string LogHeader = "[BULLETSIM LINKSET]";
  36. public enum LinksetImplementation
  37. {
  38. Constraint = 0, // linkset tied together with constraints
  39. Compound = 1, // linkset tied together as a compound object
  40. Manual = 2 // linkset tied together manually (code moves all the pieces)
  41. }
  42. // Create the correct type of linkset for this child
  43. public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
  44. {
  45. BSLinkset ret = null;
  46. switch (parent.LinksetType)
  47. {
  48. case LinksetImplementation.Constraint:
  49. ret = new BSLinksetConstraints(physScene, parent);
  50. break;
  51. case LinksetImplementation.Compound:
  52. ret = new BSLinksetCompound(physScene, parent);
  53. break;
  54. case LinksetImplementation.Manual:
  55. // ret = new BSLinksetManual(physScene, parent);
  56. break;
  57. default:
  58. ret = new BSLinksetCompound(physScene, parent);
  59. break;
  60. }
  61. if (ret == null)
  62. {
  63. physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
  64. }
  65. return ret;
  66. }
  67. public BSPrimLinkable LinksetRoot { get; protected set; }
  68. protected BSScene m_physicsScene { get; private set; }
  69. static int m_nextLinksetID = 1;
  70. public int LinksetID { get; private set; }
  71. // The children under the root in this linkset.
  72. protected HashSet<BSPrimLinkable> m_children;
  73. // We lock the diddling of linkset classes to prevent any badness.
  74. // This locks the modification of the instances of this class. Changes
  75. // to the physical representation is done via the tainting mechenism.
  76. protected object m_linksetActivityLock = new Object();
  77. // We keep the prim's mass in the linkset structure since it could be dependent on other prims
  78. public float LinksetMass { get; protected set; }
  79. public virtual bool LinksetIsColliding { get { return false; } }
  80. public OMV.Vector3 CenterOfMass
  81. {
  82. get { return ComputeLinksetCenterOfMass(); }
  83. }
  84. public OMV.Vector3 GeometricCenter
  85. {
  86. get { return ComputeLinksetGeometricCenter(); }
  87. }
  88. protected BSLinkset(BSScene scene, BSPrimLinkable parent)
  89. {
  90. // A simple linkset of one (no children)
  91. LinksetID = m_nextLinksetID++;
  92. // We create LOTS of linksets.
  93. if (m_nextLinksetID <= 0)
  94. m_nextLinksetID = 1;
  95. m_physicsScene = scene;
  96. LinksetRoot = parent;
  97. m_children = new HashSet<BSPrimLinkable>();
  98. LinksetMass = parent.RawMass;
  99. Rebuilding = false;
  100. parent.ClearDisplacement();
  101. }
  102. // Link to a linkset where the child knows the parent.
  103. // Parent changing should not happen so do some sanity checking.
  104. // We return the parent's linkset so the child can track its membership.
  105. // Called at runtime.
  106. public BSLinkset AddMeToLinkset(BSPrimLinkable child)
  107. {
  108. lock (m_linksetActivityLock)
  109. {
  110. // Don't add the root to its own linkset
  111. if (!IsRoot(child))
  112. AddChildToLinkset(child);
  113. LinksetMass = ComputeLinksetMass();
  114. }
  115. return this;
  116. }
  117. // Remove a child from a linkset.
  118. // Returns a new linkset for the child which is a linkset of one (just the
  119. // orphened child).
  120. // Called at runtime.
  121. public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
  122. {
  123. lock (m_linksetActivityLock)
  124. {
  125. if (IsRoot(child))
  126. {
  127. // Cannot remove the root from a linkset.
  128. return this;
  129. }
  130. RemoveChildFromLinkset(child);
  131. LinksetMass = ComputeLinksetMass();
  132. }
  133. // The child is down to a linkset of just itself
  134. return BSLinkset.Factory(m_physicsScene, child);
  135. }
  136. // Return 'true' if the passed object is the root object of this linkset
  137. public bool IsRoot(BSPrimLinkable requestor)
  138. {
  139. return (requestor.LocalID == LinksetRoot.LocalID);
  140. }
  141. public int NumberOfChildren { get { return m_children.Count; } }
  142. // Return 'true' if this linkset has any children (more than the root member)
  143. public bool HasAnyChildren { get { return (m_children.Count > 0); } }
  144. // Return 'true' if this child is in this linkset
  145. public bool HasChild(BSPrimLinkable child)
  146. {
  147. bool ret = false;
  148. lock (m_linksetActivityLock)
  149. {
  150. ret = m_children.Contains(child);
  151. /* Safer version but the above should work
  152. foreach (BSPrimLinkable bp in m_children)
  153. {
  154. if (child.LocalID == bp.LocalID)
  155. {
  156. ret = true;
  157. break;
  158. }
  159. }
  160. */
  161. }
  162. return ret;
  163. }
  164. // Perform an action on each member of the linkset including root prim.
  165. // Depends on the action on whether this should be done at taint time.
  166. public delegate bool ForEachMemberAction(BSPrimLinkable obj);
  167. public virtual bool ForEachMember(ForEachMemberAction action)
  168. {
  169. bool ret = false;
  170. lock (m_linksetActivityLock)
  171. {
  172. action(LinksetRoot);
  173. foreach (BSPrimLinkable po in m_children)
  174. {
  175. if (action(po))
  176. break;
  177. }
  178. }
  179. return ret;
  180. }
  181. // I am the root of a linkset and a new child is being added
  182. // Called while LinkActivity is locked.
  183. protected abstract void AddChildToLinkset(BSPrimLinkable child);
  184. // I am the root of a linkset and one of my children is being removed.
  185. // Safe to call even if the child is not really in my linkset.
  186. protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
  187. // When physical properties are changed the linkset needs to recalculate
  188. // its internal properties.
  189. // May be called at runtime or taint-time.
  190. public virtual void Refresh(BSPrimLinkable requestor)
  191. {
  192. LinksetMass = ComputeLinksetMass();
  193. }
  194. // Flag denoting the linkset is in the process of being rebuilt.
  195. // Used to know not the schedule a rebuild in the middle of a rebuild.
  196. protected bool Rebuilding { get; set; }
  197. // The object is going dynamic (physical). Do any setup necessary
  198. // for a dynamic linkset.
  199. // Only the state of the passed object can be modified. The rest of the linkset
  200. // has not yet been fully constructed.
  201. // Return 'true' if any properties updated on the passed object.
  202. // Called at taint-time!
  203. public abstract bool MakeDynamic(BSPrimLinkable child);
  204. // The object is going static (non-physical). Do any setup necessary
  205. // for a static linkset.
  206. // Return 'true' if any properties updated on the passed object.
  207. // Called at taint-time!
  208. public abstract bool MakeStatic(BSPrimLinkable child);
  209. // Called when a parameter update comes from the physics engine for any object
  210. // of the linkset is received.
  211. // Passed flag is update came from physics engine (true) or the user (false).
  212. // Called at taint-time!!
  213. public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
  214. // Routine used when rebuilding the body of the root of the linkset
  215. // Destroy all the constraints have have been made to root.
  216. // This is called when the root body is changing.
  217. // Returns 'true' of something was actually removed and would need restoring
  218. // Called at taint-time!!
  219. public abstract bool RemoveDependencies(BSPrimLinkable child);
  220. // ================================================================
  221. protected virtual float ComputeLinksetMass()
  222. {
  223. float mass = LinksetRoot.RawMass;
  224. if (HasAnyChildren)
  225. {
  226. lock (m_linksetActivityLock)
  227. {
  228. foreach (BSPrimLinkable bp in m_children)
  229. {
  230. mass += bp.RawMass;
  231. }
  232. }
  233. }
  234. return mass;
  235. }
  236. // Computes linkset's center of mass in world coordinates.
  237. protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
  238. {
  239. OMV.Vector3 com;
  240. lock (m_linksetActivityLock)
  241. {
  242. com = LinksetRoot.Position * LinksetRoot.RawMass;
  243. float totalMass = LinksetRoot.RawMass;
  244. foreach (BSPrimLinkable bp in m_children)
  245. {
  246. com += bp.Position * bp.RawMass;
  247. totalMass += bp.RawMass;
  248. }
  249. if (totalMass != 0f)
  250. com /= totalMass;
  251. }
  252. return com;
  253. }
  254. protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
  255. {
  256. OMV.Vector3 com;
  257. lock (m_linksetActivityLock)
  258. {
  259. com = LinksetRoot.Position;
  260. foreach (BSPrimLinkable bp in m_children)
  261. {
  262. com += bp.Position;
  263. }
  264. com /= (m_children.Count + 1);
  265. }
  266. return com;
  267. }
  268. // Invoke the detailed logger and output something if it's enabled.
  269. protected void DetailLog(string msg, params Object[] args)
  270. {
  271. if (m_physicsScene.PhysicsLogging.Enabled)
  272. m_physicsScene.DetailLog(msg, args);
  273. }
  274. }
  275. }