BSLinksetCompound.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  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 OpenSim.Framework;
  31. using OMV = OpenMetaverse;
  32. namespace OpenSim.Region.Physics.BulletSPlugin
  33. {
  34. public sealed class BSLinksetCompound : BSLinkset
  35. {
  36. #pragma warning disable 414
  37. private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
  38. #pragma warning restore 414
  39. public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
  40. : base(scene, parent)
  41. {
  42. LinksetImpl = LinksetImplementation.Compound;
  43. }
  44. // ================================================================
  45. // Changing the physical property of the linkset only needs to change the root
  46. public override void SetPhysicalFriction(float friction)
  47. {
  48. if (LinksetRoot.PhysBody.HasPhysicalBody)
  49. m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
  50. }
  51. public override void SetPhysicalRestitution(float restitution)
  52. {
  53. if (LinksetRoot.PhysBody.HasPhysicalBody)
  54. m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
  55. }
  56. public override void SetPhysicalGravity(OMV.Vector3 gravity)
  57. {
  58. if (LinksetRoot.PhysBody.HasPhysicalBody)
  59. m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
  60. }
  61. public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
  62. {
  63. OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
  64. LinksetRoot.Inertia = inertia * inertiaFactor;
  65. m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
  66. m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
  67. }
  68. public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
  69. {
  70. if (LinksetRoot.PhysBody.HasPhysicalBody)
  71. m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
  72. }
  73. public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
  74. {
  75. if (LinksetRoot.PhysBody.HasPhysicalBody)
  76. m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
  77. }
  78. public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
  79. {
  80. if (LinksetRoot.PhysBody.HasPhysicalBody)
  81. m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
  82. }
  83. // ================================================================
  84. // When physical properties are changed the linkset needs to recalculate
  85. // its internal properties.
  86. public override void Refresh(BSPrimLinkable requestor)
  87. {
  88. // Something changed so do the rebuilding thing
  89. ScheduleRebuild(requestor);
  90. base.Refresh(requestor);
  91. }
  92. // Schedule a refresh to happen after all the other taint processing.
  93. private void ScheduleRebuild(BSPrimLinkable requestor)
  94. {
  95. // When rebuilding, it is possible to set properties that would normally require a rebuild.
  96. // If already rebuilding, don't request another rebuild.
  97. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
  98. lock (m_linksetActivityLock)
  99. {
  100. if (!RebuildScheduled && !Rebuilding && HasAnyChildren)
  101. {
  102. InternalScheduleRebuild(requestor);
  103. }
  104. }
  105. }
  106. // Must be called with m_linksetActivityLock or race conditions will haunt you.
  107. private void InternalScheduleRebuild(BSPrimLinkable requestor)
  108. {
  109. DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}",
  110. requestor.LocalID, Rebuilding, HasAnyChildren);
  111. RebuildScheduled = true;
  112. m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
  113. {
  114. if (HasAnyChildren)
  115. {
  116. if (this.AllPartsComplete)
  117. {
  118. RecomputeLinksetCompound();
  119. }
  120. else
  121. {
  122. DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete",
  123. requestor.LocalID);
  124. InternalScheduleRebuild(requestor);
  125. }
  126. }
  127. RebuildScheduled = false;
  128. });
  129. }
  130. // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
  131. // Only the state of the passed object can be modified. The rest of the linkset
  132. // has not yet been fully constructed.
  133. // Return 'true' if any properties updated on the passed object.
  134. // Called at taint-time!
  135. public override bool MakeDynamic(BSPrimLinkable child)
  136. {
  137. bool ret = false;
  138. DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
  139. if (IsRoot(child))
  140. {
  141. // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
  142. Refresh(LinksetRoot);
  143. }
  144. return ret;
  145. }
  146. // The object is going static (non-physical). We do not do anything for static linksets.
  147. // Return 'true' if any properties updated on the passed object.
  148. // Called at taint-time!
  149. public override bool MakeStatic(BSPrimLinkable child)
  150. {
  151. bool ret = false;
  152. DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
  153. child.ClearDisplacement();
  154. if (IsRoot(child))
  155. {
  156. // Schedule a rebuild to verify that the root shape is set to the real shape.
  157. Refresh(LinksetRoot);
  158. }
  159. return ret;
  160. }
  161. // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
  162. // Called at taint-time.
  163. public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
  164. {
  165. if (!LinksetRoot.IsPhysicallyActive)
  166. {
  167. // No reason to do this physical stuff for static linksets.
  168. DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
  169. return;
  170. }
  171. // The user moving a child around requires the rebuilding of the linkset compound shape
  172. // One problem is this happens when a border is crossed -- the simulator implementation
  173. // stores the position into the group which causes the move of the object
  174. // but it also means all the child positions get updated.
  175. // What would cause an unnecessary rebuild so we make sure the linkset is in a
  176. // region before bothering to do a rebuild.
  177. if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
  178. {
  179. // If a child of the linkset is updating only the position or rotation, that can be done
  180. // without rebuilding the linkset.
  181. // If a handle for the child can be fetch, we update the child here. If a rebuild was
  182. // scheduled by someone else, the rebuild will just replace this setting.
  183. bool updatedChild = false;
  184. // Anything other than updating position or orientation usually means a physical update
  185. // and that is caused by us updating the object.
  186. if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
  187. {
  188. // Find the physical instance of the child
  189. if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
  190. {
  191. // It is possible that the linkset is still under construction and the child is not yet
  192. // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
  193. // build the whole thing with the new position or rotation.
  194. // The index must be checked because Bullet references the child array but does no validity
  195. // checking of the child index passed.
  196. int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
  197. if (updated.LinksetChildIndex < numLinksetChildren)
  198. {
  199. BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
  200. if (linksetChildShape.HasPhysicalShape)
  201. {
  202. // Found the child shape within the compound shape
  203. m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
  204. updated.RawPosition - LinksetRoot.RawPosition,
  205. updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
  206. true /* shouldRecalculateLocalAabb */);
  207. updatedChild = true;
  208. DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
  209. updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
  210. }
  211. else // DEBUG DEBUG
  212. { // DEBUG DEBUG
  213. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
  214. updated.LocalID, linksetChildShape);
  215. } // DEBUG DEBUG
  216. }
  217. else // DEBUG DEBUG
  218. { // DEBUG DEBUG
  219. // the child is not yet in the compound shape. This is non-fatal.
  220. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
  221. updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
  222. } // DEBUG DEBUG
  223. }
  224. else // DEBUG DEBUG
  225. { // DEBUG DEBUG
  226. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
  227. } // DEBUG DEBUG
  228. if (!updatedChild)
  229. {
  230. // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
  231. // Note: there are several ways through this code that will not update the child if
  232. // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
  233. // there will already be a rebuild scheduled.
  234. DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
  235. updated.LocalID, whichUpdated);
  236. Refresh(updated);
  237. }
  238. }
  239. }
  240. }
  241. // Routine called when rebuilding the body of some member of the linkset.
  242. // If one of the bodies is being changed, the linkset needs rebuilding.
  243. // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
  244. // Returns 'true' of something was actually removed and would need restoring
  245. // Called at taint-time!!
  246. public override bool RemoveDependencies(BSPrimLinkable child)
  247. {
  248. bool ret = false;
  249. DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
  250. child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
  251. Refresh(child);
  252. return ret;
  253. }
  254. // ================================================================
  255. // Add a new child to the linkset.
  256. // Called while LinkActivity is locked.
  257. protected override void AddChildToLinkset(BSPrimLinkable child)
  258. {
  259. if (!HasChild(child))
  260. {
  261. m_children.Add(child, new BSLinkInfo(child));
  262. DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
  263. // Rebuild the compound shape with the new child shape included
  264. Refresh(child);
  265. }
  266. return;
  267. }
  268. // Remove the specified child from the linkset.
  269. // Safe to call even if the child is not really in the linkset.
  270. protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
  271. {
  272. child.ClearDisplacement();
  273. if (m_children.Remove(child))
  274. {
  275. DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
  276. child.LocalID,
  277. LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
  278. child.LocalID, child.PhysBody.AddrString);
  279. // Cause the child's body to be rebuilt and thus restored to normal operation
  280. child.ForceBodyShapeRebuild(inTaintTime);
  281. if (!HasAnyChildren)
  282. {
  283. // The linkset is now empty. The root needs rebuilding.
  284. LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
  285. }
  286. else
  287. {
  288. // Rebuild the compound shape with the child removed
  289. Refresh(LinksetRoot);
  290. }
  291. }
  292. return;
  293. }
  294. // Called before the simulation step to make sure the compound based linkset
  295. // is all initialized.
  296. // Constraint linksets are rebuilt every time.
  297. // Note that this works for rebuilding just the root after a linkset is taken apart.
  298. // Called at taint time!!
  299. private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
  300. // Number of times to perform rebuilds on broken linkset children. This should only happen when
  301. // a linkset is initially being created and should happen only one or two times at the most.
  302. // This exists to cause a looping problem to be reported while not rebuilding a linkset forever.
  303. private static int LinksetRebuildFailureLoopPrevention = 10;
  304. private void RecomputeLinksetCompound()
  305. {
  306. try
  307. {
  308. Rebuilding = true;
  309. // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
  310. // to what they should be as if the root was not in a linkset.
  311. // Not that bad since we only get into this routine if there are children in the linkset and
  312. // something has been updated/changed.
  313. // Have to do the rebuild before checking for physical because this might be a linkset
  314. // being destructed and going non-physical.
  315. LinksetRoot.ForceBodyShapeRebuild(true);
  316. // There is no reason to build all this physical stuff for a non-physical or empty linkset.
  317. if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
  318. {
  319. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
  320. return; // Note the 'finally' clause at the botton which will get executed.
  321. }
  322. // Get a new compound shape to build the linkset shape in.
  323. BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
  324. // Compute a displacement for each component so it is relative to the center-of-mass.
  325. // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
  326. OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
  327. OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
  328. OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
  329. // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
  330. OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
  331. if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
  332. {
  333. // Zero everything if center-of-mass displacement is not being done.
  334. centerDisplacementV = OMV.Vector3.Zero;
  335. LinksetRoot.ClearDisplacement();
  336. }
  337. else
  338. {
  339. // The actual center-of-mass could have been set by the user.
  340. centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
  341. }
  342. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
  343. LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
  344. // Add the shapes of all the components of the linkset
  345. int memberIndex = 1;
  346. ForEachMember((cPrim) =>
  347. {
  348. if (IsRoot(cPrim))
  349. {
  350. // Root shape is always index zero.
  351. cPrim.LinksetChildIndex = 0;
  352. }
  353. else
  354. {
  355. cPrim.LinksetChildIndex = memberIndex;
  356. memberIndex++;
  357. }
  358. // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
  359. BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
  360. // Offset the child shape from the center-of-mass and rotate it to root relative.
  361. OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
  362. OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
  363. // Add the child shape to the compound shape being built
  364. if (childShape.physShapeInfo.HasPhysicalShape)
  365. {
  366. m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
  367. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
  368. LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
  369. // Since we are borrowing the shape of the child, disable the origional child body
  370. if (!IsRoot(cPrim))
  371. {
  372. m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
  373. m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
  374. // We don't want collisions from the old linkset children.
  375. m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
  376. cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
  377. }
  378. }
  379. else
  380. {
  381. // The linkset must be in an intermediate state where all the children have not yet
  382. // been constructed. This sometimes happens on startup when everything is getting
  383. // built and some shapes have to wait for assets to be read in.
  384. // Just skip this linkset for the moment and cause the shape to be rebuilt next tick.
  385. // One problem might be that the shape is broken somehow and it never becomes completely
  386. // available. This might cause the rebuild to happen over and over.
  387. InternalScheduleRebuild(LinksetRoot);
  388. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}",
  389. LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
  390. // Output an annoying warning. It should only happen once but if it keeps coming out,
  391. // the user knows there is something wrong and will report it.
  392. m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader);
  393. m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}",
  394. LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape);
  395. // This causes the loop to bail on building the rest of this linkset.
  396. // The rebuild operation will fix it up next tick or declare the object unbuildable.
  397. return true;
  398. }
  399. return false; // 'false' says to move onto the next child in the list
  400. });
  401. // Replace the root shape with the built compound shape.
  402. // Object removed and added to world to get collision cache rebuilt for new shape.
  403. LinksetRoot.PhysShape.Dereference(m_physicsScene);
  404. LinksetRoot.PhysShape = linksetShape;
  405. m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
  406. m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
  407. m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
  408. DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
  409. LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
  410. // With all of the linkset packed into the root prim, it has the mass of everyone.
  411. LinksetMass = ComputeLinksetMass();
  412. LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
  413. if (UseBulletSimRootOffsetHack)
  414. {
  415. // Enable the physical position updator to return the position and rotation of the root shape.
  416. // This enables a feature in the C++ code to return the world coordinates of the first shape in the
  417. // compound shape. This aleviates the need to offset the returned physical position by the
  418. // center-of-mass offset.
  419. // TODO: either debug this feature or remove it.
  420. m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
  421. }
  422. }
  423. finally
  424. {
  425. Rebuilding = false;
  426. }
  427. // See that the Aabb surrounds the new shape
  428. m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
  429. }
  430. }
  431. }