123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyrightD
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Collections.Generic;
- using System.Text;
- using OMV = OpenMetaverse;
- namespace OpenSim.Region.PhysicsModule.BulletS
- {
- public abstract class BSLinkset
- {
- // private static string LogHeader = "[BULLETSIM LINKSET]";
- public enum LinksetImplementation
- {
- Constraint = 0, // linkset tied together with constraints
- Compound = 1, // linkset tied together as a compound object
- Manual = 2 // linkset tied together manually (code moves all the pieces)
- }
- // Create the correct type of linkset for this child
- public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent)
- {
- BSLinkset ret = null;
- switch (parent.LinksetType)
- {
- case LinksetImplementation.Constraint:
- ret = new BSLinksetConstraints(physScene, parent);
- break;
- case LinksetImplementation.Compound:
- ret = new BSLinksetCompound(physScene, parent);
- break;
- case LinksetImplementation.Manual:
- // ret = new BSLinksetManual(physScene, parent);
- break;
- default:
- ret = new BSLinksetCompound(physScene, parent);
- break;
- }
- if (ret == null)
- {
- physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID);
- }
- return ret;
- }
- public class BSLinkInfo
- {
- public BSPrimLinkable member;
- public BSLinkInfo(BSPrimLinkable pMember)
- {
- member = pMember;
- }
- public virtual void ResetLink() { }
- public virtual void SetLinkParameters(BSConstraint constrain) { }
- // Returns 'true' if physical property updates from the child should be reported to the simulator
- public virtual bool ShouldUpdateChildProperties() { return false; }
- }
- public LinksetImplementation LinksetImpl { get; protected set; }
- public BSPrimLinkable LinksetRoot { get; protected set; }
- protected BSScene m_physicsScene { get; private set; }
- static int m_nextLinksetID = 1;
- public int LinksetID { get; private set; }
- // The children under the root in this linkset.
- // protected HashSet<BSPrimLinkable> m_children;
- protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children;
- // We lock the diddling of linkset classes to prevent any badness.
- // This locks the modification of the instances of this class. Changes
- // to the physical representation is done via the tainting mechenism.
- protected object m_linksetActivityLock = new Object();
- // We keep the prim's mass in the linkset structure since it could be dependent on other prims
- public float LinksetMass { get; protected set; }
- public virtual bool LinksetIsColliding { get { return false; } }
- public OMV.Vector3 CenterOfMass
- {
- get { return ComputeLinksetCenterOfMass(); }
- }
- public OMV.Vector3 GeometricCenter
- {
- get { return ComputeLinksetGeometricCenter(); }
- }
- protected BSLinkset(BSScene scene, BSPrimLinkable parent)
- {
- // A simple linkset of one (no children)
- LinksetID = m_nextLinksetID++;
- // We create LOTS of linksets.
- if (m_nextLinksetID <= 0)
- m_nextLinksetID = 1;
- m_physicsScene = scene;
- LinksetRoot = parent;
- m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>();
- LinksetMass = parent.RawMass;
- Rebuilding = false;
- RebuildScheduled = false;
- parent.ClearDisplacement();
- }
- // Link to a linkset where the child knows the parent.
- // Parent changing should not happen so do some sanity checking.
- // We return the parent's linkset so the child can track its membership.
- // Called at runtime.
- public BSLinkset AddMeToLinkset(BSPrimLinkable child)
- {
- lock (m_linksetActivityLock)
- {
- // Don't add the root to its own linkset
- if (!IsRoot(child))
- AddChildToLinkset(child);
- LinksetMass = ComputeLinksetMass();
- }
- return this;
- }
- // Remove a child from a linkset.
- // Returns a new linkset for the child which is a linkset of one (just the
- // orphened child).
- // Called at runtime.
- public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime)
- {
- lock (m_linksetActivityLock)
- {
- if (IsRoot(child))
- {
- // Cannot remove the root from a linkset.
- return this;
- }
- RemoveChildFromLinkset(child, inTaintTime);
- LinksetMass = ComputeLinksetMass();
- }
- // The child is down to a linkset of just itself
- return BSLinkset.Factory(m_physicsScene, child);
- }
- // Return 'true' if the passed object is the root object of this linkset
- public bool IsRoot(BSPrimLinkable requestor)
- {
- return (requestor.LocalID == LinksetRoot.LocalID);
- }
- public int NumberOfChildren { get { return m_children.Count; } }
- // Return 'true' if this linkset has any children (more than the root member)
- public bool HasAnyChildren { get { return (m_children.Count > 0); } }
- // Return 'true' if this child is in this linkset
- public bool HasChild(BSPrimLinkable child)
- {
- bool ret = false;
- lock (m_linksetActivityLock)
- {
- ret = m_children.ContainsKey(child);
- }
- return ret;
- }
- // Perform an action on each member of the linkset including root prim.
- // Depends on the action on whether this should be done at taint time.
- public delegate bool ForEachMemberAction(BSPrimLinkable obj);
- public virtual bool ForEachMember(ForEachMemberAction action)
- {
- bool ret = false;
- lock (m_linksetActivityLock)
- {
- action(LinksetRoot);
- foreach (BSPrimLinkable po in m_children.Keys)
- {
- if (action(po))
- break;
- }
- }
- return ret;
- }
- public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo)
- {
- bool ret = false;
- BSLinkInfo found = null;
- lock (m_linksetActivityLock)
- {
- ret = m_children.TryGetValue(child, out found);
- }
- foundInfo = found;
- return ret;
- }
- // Perform an action on each member of the linkset including root prim.
- // Depends on the action on whether this should be done at taint time.
- public delegate bool ForEachLinkInfoAction(BSLinkInfo obj);
- public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action)
- {
- bool ret = false;
- lock (m_linksetActivityLock)
- {
- foreach (BSLinkInfo po in m_children.Values)
- {
- if (action(po))
- break;
- }
- }
- return ret;
- }
- // Check the type of the link and return 'true' if the link is flexible and the
- // updates from the child should be sent to the simulator so things change.
- public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child)
- {
- bool ret = false;
- BSLinkInfo linkInfo;
- if (m_children.TryGetValue(child, out linkInfo))
- {
- ret = linkInfo.ShouldUpdateChildProperties();
- }
- return ret;
- }
- // Called after a simulation step to post a collision with this object.
- // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have
- // anything to add for the collision and it should be passed through normal processing.
- // Default processing for a linkset.
- public virtual bool HandleCollide(BSPhysObject collider, BSPhysObject collidee,
- OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
- {
- bool ret = false;
- // prims in the same linkset cannot collide with each other
- BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
- if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID))
- {
- // By returning 'true', we tell the caller the collision has been 'handled' so it won't
- // do anything about this collision and thus, effectivily, ignoring the collision.
- ret = true;
- }
- else
- {
- // Not a collision between members of the linkset. Must be a real collision.
- // So the linkset root can know if there is a collision anywhere in the linkset.
- LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep;
- }
- return ret;
- }
- // I am the root of a linkset and a new child is being added
- // Called while LinkActivity is locked.
- protected abstract void AddChildToLinkset(BSPrimLinkable child);
- // I am the root of a linkset and one of my children is being removed.
- // Safe to call even if the child is not really in my linkset.
- protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime);
- // When physical properties are changed the linkset needs to recalculate
- // its internal properties.
- // May be called at runtime or taint-time.
- public virtual void Refresh(BSPrimLinkable requestor)
- {
- LinksetMass = ComputeLinksetMass();
- }
- // Flag denoting the linkset is in the process of being rebuilt.
- // Used to know not the schedule a rebuild in the middle of a rebuild.
- // Because of potential update calls that could want to schedule another rebuild.
- protected bool Rebuilding { get; set; }
- // Flag saying a linkset rebuild has been scheduled.
- // This is turned on when the rebuild is requested and turned off when
- // the rebuild is complete. Used to limit modifications to the
- // linkset parameters while the linkset is in an intermediate state.
- // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object
- public bool RebuildScheduled { get; protected set; }
- // The object is going dynamic (physical). Do any setup necessary
- // for a dynamic linkset.
- // Only the state of the passed object can be modified. The rest of the linkset
- // has not yet been fully constructed.
- // Return 'true' if any properties updated on the passed object.
- // Called at taint-time!
- public abstract bool MakeDynamic(BSPrimLinkable child);
- public virtual bool AllPartsComplete
- {
- get {
- bool ret = true;
- this.ForEachMember((member) =>
- {
- if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting)
- {
- ret = false;
- return true; // exit loop
- }
- return false; // continue loop
- });
- return ret;
- }
- }
- // The object is going static (non-physical). Do any setup necessary
- // for a static linkset.
- // Return 'true' if any properties updated on the passed object.
- // Called at taint-time!
- public abstract bool MakeStatic(BSPrimLinkable child);
- // Called when a parameter update comes from the physics engine for any object
- // of the linkset is received.
- // Passed flag is update came from physics engine (true) or the user (false).
- // Called at taint-time!!
- public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject);
- // Routine used when rebuilding the body of the root of the linkset
- // Destroy all the constraints have have been made to root.
- // This is called when the root body is changing.
- // Returns 'true' of something was actually removed and would need restoring
- // Called at taint-time!!
- public abstract bool RemoveDependencies(BSPrimLinkable child);
- // ================================================================
- // Some physical setting happen to all members of the linkset
- public virtual void SetPhysicalFriction(float friction)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.SetFriction(member.PhysBody, friction);
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void SetPhysicalRestitution(float restitution)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.SetRestitution(member.PhysBody, restitution);
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void SetPhysicalGravity(OMV.Vector3 gravity)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.SetGravity(member.PhysBody, gravity);
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- {
- OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
- member.Inertia = inertia * inertiaFactor;
- m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
- m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
- DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
- }
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags);
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
- return false; // 'false' says to continue looping
- }
- );
- }
- public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
- {
- ForEachMember((member) =>
- {
- if (member.PhysBody.HasPhysicalBody)
- m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags);
- return false; // 'false' says to continue looping
- }
- );
- }
- // ================================================================
- protected virtual float ComputeLinksetMass()
- {
- float mass = LinksetRoot.RawMass;
- if (HasAnyChildren)
- {
- lock (m_linksetActivityLock)
- {
- foreach (BSPrimLinkable bp in m_children.Keys)
- {
- mass += bp.RawMass;
- }
- }
- }
- return mass;
- }
- // Computes linkset's center of mass in world coordinates.
- protected virtual OMV.Vector3 ComputeLinksetCenterOfMass()
- {
- OMV.Vector3 com;
- lock (m_linksetActivityLock)
- {
- com = LinksetRoot.Position * LinksetRoot.RawMass;
- float totalMass = LinksetRoot.RawMass;
- foreach (BSPrimLinkable bp in m_children.Keys)
- {
- com += bp.Position * bp.RawMass;
- totalMass += bp.RawMass;
- }
- if (totalMass != 0f)
- com /= totalMass;
- }
- return com;
- }
- protected virtual OMV.Vector3 ComputeLinksetGeometricCenter()
- {
- OMV.Vector3 com;
- lock (m_linksetActivityLock)
- {
- com = LinksetRoot.Position;
- foreach (BSPrimLinkable bp in m_children.Keys)
- {
- com += bp.Position;
- }
- com /= (m_children.Count + 1);
- }
- return com;
- }
- #region Extension
- public virtual object Extension(string pFunct, params object[] pParams)
- {
- return null;
- }
- #endregion // Extension
- // Invoke the detailed logger and output something if it's enabled.
- protected void DetailLog(string msg, params Object[] args)
- {
- if (m_physicsScene.PhysicsLogging.Enabled)
- m_physicsScene.DetailLog(msg, args);
- }
- }
- }
|