BSLinkset.cs 12 KB

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