BSLinkset.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  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 class BSLinkInfo
  68. {
  69. public BSPrimLinkable member;
  70. public BSLinkInfo(BSPrimLinkable pMember)
  71. {
  72. member = pMember;
  73. }
  74. }
  75. public LinksetImplementation LinksetImpl { get; protected set; }
  76. public BSPrimLinkable LinksetRoot { get; protected set; }
  77. protected BSScene m_physicsScene { get; private set; }
  78. static int m_nextLinksetID = 1;
  79. public int LinksetID { get; private set; }
  80. // The children under the root in this linkset.
  81. // protected HashSet<BSPrimLinkable> m_children;
  82. protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
  83. // We lock the diddling of linkset classes to prevent any badness.
  84. // This locks the modification of the instances of this class. Changes
  85. // to the physical representation is done via the tainting mechenism.
  86. protected object m_linksetActivityLock = new Object();
  87. // We keep the prim's mass in the linkset structure since it could be dependent on other prims
  88. public float LinksetMass { get; protected set; }
  89. public virtual bool LinksetIsColliding { get { return false; } }
  90. public OMV.Vector3 CenterOfMass
  91. {
  92. get { return ComputeLinksetCenterOfMass(); }
  93. }
  94. public OMV.Vector3 GeometricCenter
  95. {
  96. get { return ComputeLinksetGeometricCenter(); }
  97. }
  98. protected BSLinkset(BSScene scene, BSPrimLinkable parent)
  99. {
  100. // A simple linkset of one (no children)
  101. LinksetID = m_nextLinksetID++;
  102. // We create LOTS of linksets.
  103. if (m_nextLinksetID <= 0)
  104. m_nextLinksetID = 1;
  105. m_physicsScene = scene;
  106. LinksetRoot = parent;
  107. m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
  108. LinksetMass = parent.RawMass;
  109. Rebuilding = false;
  110. parent.ClearDisplacement();
  111. }
  112. // Link to a linkset where the child knows the parent.
  113. // Parent changing should not happen so do some sanity checking.
  114. // We return the parent's linkset so the child can track its membership.
  115. // Called at runtime.
  116. public BSLinkset AddMeToLinkset(BSPrimLinkable child)
  117. {
  118. lock (m_linksetActivityLock)
  119. {
  120. // Don't add the root to its own linkset
  121. if (!IsRoot(child))
  122. AddChildToLinkset(child);
  123. LinksetMass = ComputeLinksetMass();
  124. }
  125. return this;
  126. }
  127. // Remove a child from a linkset.
  128. // Returns a new linkset for the child which is a linkset of one (just the
  129. // orphened child).
  130. // Called at runtime.
  131. public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child)
  132. {
  133. lock (m_linksetActivityLock)
  134. {
  135. if (IsRoot(child))
  136. {
  137. // Cannot remove the root from a linkset.
  138. return this;
  139. }
  140. RemoveChildFromLinkset(child);
  141. LinksetMass = ComputeLinksetMass();
  142. }
  143. // The child is down to a linkset of just itself
  144. return BSLinkset.Factory(m_physicsScene, child);
  145. }
  146. // Return 'true' if the passed object is the root object of this linkset
  147. public bool IsRoot(BSPrimLinkable requestor)
  148. {
  149. return (requestor.LocalID == LinksetRoot.LocalID);
  150. }
  151. public int NumberOfChildren { get { return m_children.Count; } }
  152. // Return 'true' if this linkset has any children (more than the root member)
  153. public bool HasAnyChildren { get { return (m_children.Count > 0); } }
  154. // Return 'true' if this child is in this linkset
  155. public bool HasChild(BSPrimLinkable child)
  156. {
  157. bool ret = false;
  158. lock (m_linksetActivityLock)
  159. {
  160. ret = m_children.ContainsKey(child);
  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.Keys)
  174. {
  175. if (action(po))
  176. break;
  177. }
  178. }
  179. return ret;
  180. }
  181. // Perform an action on each member of the linkset including root prim.
  182. // Depends on the action on whether this should be done at taint time.
  183. public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
  184. public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
  185. {
  186. bool ret = false;
  187. lock (m_linksetActivityLock)
  188. {
  189. foreach (BSLinkInfo po in m_children.Values)
  190. {
  191. if (action(po))
  192. break;
  193. }
  194. }
  195. return ret;
  196. }
  197. // Called after a simulation step to post a collision with this object.
  198. // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
  199. // anything to add for the collision and it should be passed through normal processing.
  200. // Default processing for a linkset.
  201. public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee,
  202. OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
  203. {
  204. bool ret = false;
  205. // prims in the same linkset cannot collide with each other
  206. BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
  207. if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
  208. {
  209. // By returning 'true', we tell the caller the collision has been 'handled' so it won't
  210. // do anything about this collision and thus, effectivily, ignoring the collision.
  211. ret = true;
  212. }
  213. else
  214. {
  215. // Not a collision between members of the linkset. Must be a real collision.
  216. // So the linkset root can know if there is a collision anywhere in the linkset.
  217. LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
  218. }
  219. return ret;
  220. }
  221. // I am the root of a linkset and a new child is being added
  222. // Called while LinkActivity is locked.
  223. protected abstract void AddChildToLinkset(BSPrimLinkable child);
  224. // I am the root of a linkset and one of my children is being removed.
  225. // Safe to call even if the child is not really in my linkset.
  226. protected abstract void RemoveChildFromLinkset(BSPrimLinkable child);
  227. // When physical properties are changed the linkset needs to recalculate
  228. // its internal properties.
  229. // May be called at runtime or taint-time.
  230. public virtual void Refresh(BSPrimLinkable requestor)
  231. {
  232. LinksetMass = ComputeLinksetMass();
  233. }
  234. // Flag denoting the linkset is in the process of being rebuilt.
  235. // Used to know not the schedule a rebuild in the middle of a rebuild.
  236. protected bool Rebuilding { get; set; }
  237. // The object is going dynamic (physical). Do any setup necessary
  238. // for a dynamic linkset.
  239. // Only the state of the passed object can be modified. The rest of the linkset
  240. // has not yet been fully constructed.
  241. // Return 'true' if any properties updated on the passed object.
  242. // Called at taint-time!
  243. public abstract bool MakeDynamic(BSPrimLinkable child);
  244. // The object is going static (non-physical). Do any setup necessary
  245. // for a static linkset.
  246. // Return 'true' if any properties updated on the passed object.
  247. // Called at taint-time!
  248. public abstract bool MakeStatic(BSPrimLinkable child);
  249. // Called when a parameter update comes from the physics engine for any object
  250. // of the linkset is received.
  251. // Passed flag is update came from physics engine (true) or the user (false).
  252. // Called at taint-time!!
  253. public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
  254. // Routine used when rebuilding the body of the root of the linkset
  255. // Destroy all the constraints have have been made to root.
  256. // This is called when the root body is changing.
  257. // Returns 'true' of something was actually removed and would need restoring
  258. // Called at taint-time!!
  259. public abstract bool RemoveDependencies(BSPrimLinkable child);
  260. // ================================================================
  261. // Some physical setting happen to all members of the linkset
  262. public virtual void SetPhysicalFriction(float friction)
  263. {
  264. ForEachMember((member) =>
  265. {
  266. if (member.PhysBody.HasPhysicalBody)
  267. m_physicsScene.PE.SetFriction(member.PhysBody, friction);
  268. return false; // 'false' says to continue looping
  269. }
  270. );
  271. }
  272. public virtual void SetPhysicalRestitution(float restitution)
  273. {
  274. ForEachMember((member) =>
  275. {
  276. if (member.PhysBody.HasPhysicalBody)
  277. m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
  278. return false; // 'false' says to continue looping
  279. }
  280. );
  281. }
  282. public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
  283. {
  284. ForEachMember((member) =>
  285. {
  286. if (member.PhysBody.HasPhysicalBody)
  287. m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
  288. return false; // 'false' says to continue looping
  289. }
  290. );
  291. }
  292. public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
  293. {
  294. ForEachMember((member) =>
  295. {
  296. if (member.PhysBody.HasPhysicalBody)
  297. {
  298. OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
  299. member.Inertia = inertia * inertiaFactor;
  300. m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
  301. m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
  302. DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
  303. }
  304. return false; // 'false' says to continue looping
  305. }
  306. );
  307. }
  308. public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
  309. {
  310. ForEachMember((member) =>
  311. {
  312. if (member.PhysBody.HasPhysicalBody)
  313. m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
  314. return false; // 'false' says to continue looping
  315. }
  316. );
  317. }
  318. public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
  319. {
  320. ForEachMember((member) =>
  321. {
  322. if (member.PhysBody.HasPhysicalBody)
  323. m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
  324. return false; // 'false' says to continue looping
  325. }
  326. );
  327. }
  328. public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
  329. {
  330. ForEachMember((member) =>
  331. {
  332. if (member.PhysBody.HasPhysicalBody)
  333. m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
  334. return false; // 'false' says to continue looping
  335. }
  336. );
  337. }
  338. // ================================================================
  339. protected virtual float ComputeLinksetMass()
  340. {
  341. float mass = LinksetRoot.RawMass;
  342. if (HasAnyChildren)
  343. {
  344. lock (m_linksetActivityLock)
  345. {
  346. foreach (BSPrimLinkable bp in m_children.Keys)
  347. {
  348. mass += bp.RawMass;
  349. }
  350. }
  351. }
  352. return mass;
  353. }
  354. // Computes linkset's center of mass in world coordinates.
  355. protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
  356. {
  357. OMV.Vector3 com;
  358. lock (m_linksetActivityLock)
  359. {
  360. com = LinksetRoot.Position * LinksetRoot.RawMass;
  361. float totalMass = LinksetRoot.RawMass;
  362. foreach (BSPrimLinkable bp in m_children.Keys)
  363. {
  364. com += bp.Position * bp.RawMass;
  365. totalMass += bp.RawMass;
  366. }
  367. if (totalMass != 0f)
  368. com /= totalMass;
  369. }
  370. return com;
  371. }
  372. protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
  373. {
  374. OMV.Vector3 com;
  375. lock (m_linksetActivityLock)
  376. {
  377. com = LinksetRoot.Position;
  378. foreach (BSPrimLinkable bp in m_children.Keys)
  379. {
  380. com += bp.Position;
  381. }
  382. com /= (m_children.Count + 1);
  383. }
  384. return com;
  385. }
  386. // Invoke the detailed logger and output something if it's enabled.
  387. protected void DetailLog(string msg, params Object[] args)
  388. {
  389. if (m_physicsScene.PhysicsLogging.Enabled)
  390. m_physicsScene.DetailLog(msg, args);
  391. }
  392. }
  393. }