BSLinkset.cs 11 KB

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