diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 437 |
1 files changed, 171 insertions, 266 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 087b9bb..436e043 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,35 +32,80 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | public class BSLinkset | 35 | public abstract class BSLinkset |
36 | { | 36 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; |
38 | 38 | ||
39 | private BSPrim m_linksetRoot; | 39 | public enum LinksetImplementation |
40 | public BSPrim LinksetRoot { get { return m_linksetRoot; } } | 40 | { |
41 | Constraint = 0, // linkset tied together with constraints | ||
42 | Compound = 1, // linkset tied together as a compound object | ||
43 | Manual = 2 // linkset tied together manually (code moves all the pieces) | ||
44 | } | ||
45 | // Create the correct type of linkset for this child | ||
46 | public static BSLinkset Factory(BSScene physScene, BSPhysObject parent) | ||
47 | { | ||
48 | BSLinkset ret = null; | ||
49 | |||
50 | switch ((int)physScene.Params.linksetImplementation) | ||
51 | { | ||
52 | case (int)LinksetImplementation.Constraint: | ||
53 | ret = new BSLinksetConstraints(physScene, parent); | ||
54 | break; | ||
55 | case (int)LinksetImplementation.Compound: | ||
56 | ret = new BSLinksetCompound(physScene, parent); | ||
57 | break; | ||
58 | case (int)LinksetImplementation.Manual: | ||
59 | // ret = new BSLinksetManual(physScene, parent); | ||
60 | break; | ||
61 | default: | ||
62 | ret = new BSLinksetCompound(physScene, parent); | ||
63 | break; | ||
64 | } | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | public BSPhysObject LinksetRoot { get; protected set; } | ||
41 | 69 | ||
42 | private BSScene m_physicsScene; | 70 | public BSScene PhysicsScene { get; private set; } |
43 | public BSScene PhysicsScene { get { return m_physicsScene; } } | ||
44 | 71 | ||
45 | // The children under the root in this linkset | 72 | static int m_nextLinksetID = 1; |
46 | private List<BSPrim> m_children; | 73 | public int LinksetID { get; private set; } |
74 | |||
75 | // The children under the root in this linkset. | ||
76 | protected HashSet<BSPhysObject> m_children; | ||
47 | 77 | ||
48 | // We lock the diddling of linkset classes to prevent any badness. | 78 | // We lock the diddling of linkset classes to prevent any badness. |
49 | // This locks the modification of the instances of this class. Changes | 79 | // This locks the modification of the instances of this class. Changes |
50 | // to the physical representation is done via the tainting mechenism. | 80 | // to the physical representation is done via the tainting mechenism. |
51 | private object m_linksetActivityLock = new Object(); | 81 | protected object m_linksetActivityLock = new Object(); |
82 | |||
83 | // Some linksets have a preferred physical shape. | ||
84 | // Returns SHAPE_UNKNOWN if there is no preference. Causes the correct shape to be selected. | ||
85 | public virtual ShapeData.PhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
86 | { | ||
87 | return ShapeData.PhysicsShapeType.SHAPE_UNKNOWN; | ||
88 | } | ||
52 | 89 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | ||
91 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
92 | { return member.RawPosition; } | ||
93 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
94 | { return member.RawOrientation; } | ||
95 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
96 | |||
53 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 97 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
54 | private float m_mass; | 98 | protected float m_mass; |
55 | public float LinksetMass | 99 | public float LinksetMass |
56 | { | 100 | { |
57 | get | 101 | get |
58 | { | 102 | { |
59 | m_mass = ComputeLinksetMass(); | ||
60 | return m_mass; | 103 | return m_mass; |
61 | } | 104 | } |
62 | } | 105 | } |
63 | 106 | ||
107 | public virtual bool LinksetIsColliding { get { return false; } } | ||
108 | |||
64 | public OMV.Vector3 CenterOfMass | 109 | public OMV.Vector3 CenterOfMass |
65 | { | 110 | { |
66 | get { return ComputeLinksetCenterOfMass(); } | 111 | get { return ComputeLinksetCenterOfMass(); } |
@@ -71,23 +116,31 @@ public class BSLinkset | |||
71 | get { return ComputeLinksetGeometricCenter(); } | 116 | get { return ComputeLinksetGeometricCenter(); } |
72 | } | 117 | } |
73 | 118 | ||
74 | public BSLinkset(BSScene scene, BSPrim parent) | 119 | protected void Initialize(BSScene scene, BSPhysObject parent) |
75 | { | 120 | { |
76 | // A simple linkset of one (no children) | 121 | // A simple linkset of one (no children) |
77 | m_physicsScene = scene; | 122 | LinksetID = m_nextLinksetID++; |
78 | m_linksetRoot = parent; | 123 | // We create LOTS of linksets. |
79 | m_children = new List<BSPrim>(); | 124 | if (m_nextLinksetID <= 0) |
80 | m_mass = parent.MassRaw; | 125 | m_nextLinksetID = 1; |
126 | PhysicsScene = scene; | ||
127 | LinksetRoot = parent; | ||
128 | m_children = new HashSet<BSPhysObject>(); | ||
129 | m_mass = parent.RawMass; | ||
81 | } | 130 | } |
82 | 131 | ||
83 | // Link to a linkset where the child knows the parent. | 132 | // Link to a linkset where the child knows the parent. |
84 | // Parent changing should not happen so do some sanity checking. | 133 | // Parent changing should not happen so do some sanity checking. |
85 | // We return the parent's linkset so the child can track its membership. | 134 | // We return the parent's linkset so the child can track its membership. |
86 | public BSLinkset AddMeToLinkset(BSPrim child) | 135 | // Called at runtime. |
136 | public BSLinkset AddMeToLinkset(BSPhysObject child) | ||
87 | { | 137 | { |
88 | lock (m_linksetActivityLock) | 138 | lock (m_linksetActivityLock) |
89 | { | 139 | { |
90 | AddChildToLinkset(child); | 140 | // Don't add the root to its own linkset |
141 | if (!IsRoot(child)) | ||
142 | AddChildToLinkset(child); | ||
143 | m_mass = ComputeLinksetMass(); | ||
91 | } | 144 | } |
92 | return this; | 145 | return this; |
93 | } | 146 | } |
@@ -95,36 +148,28 @@ public class BSLinkset | |||
95 | // Remove a child from a linkset. | 148 | // Remove a child from a linkset. |
96 | // Returns a new linkset for the child which is a linkset of one (just the | 149 | // Returns a new linkset for the child which is a linkset of one (just the |
97 | // orphened child). | 150 | // orphened child). |
98 | public BSLinkset RemoveMeFromLinkset(BSPrim child) | 151 | // Called at runtime. |
152 | public BSLinkset RemoveMeFromLinkset(BSPhysObject child) | ||
99 | { | 153 | { |
100 | lock (m_linksetActivityLock) | 154 | lock (m_linksetActivityLock) |
101 | { | 155 | { |
102 | if (IsRoot(child)) | 156 | if (IsRoot(child)) |
103 | { | 157 | { |
104 | // if root of linkset, take the linkset apart | 158 | // Cannot remove the root from a linkset. |
105 | while (m_children.Count > 0) | 159 | return this; |
106 | { | ||
107 | // Note that we don't do a foreach because the remove routine | ||
108 | // takes it out of the list. | ||
109 | RemoveChildFromOtherLinkset(m_children[0]); | ||
110 | } | ||
111 | m_children.Clear(); // just to make sure | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | // Just removing a child from an existing linkset | ||
116 | RemoveChildFromLinkset(child); | ||
117 | } | 160 | } |
161 | RemoveChildFromLinkset(child); | ||
162 | m_mass = ComputeLinksetMass(); | ||
118 | } | 163 | } |
119 | 164 | ||
120 | // The child is down to a linkset of just itself | 165 | // The child is down to a linkset of just itself |
121 | return new BSLinkset(PhysicsScene, child); | 166 | return BSLinkset.Factory(PhysicsScene, child); |
122 | } | 167 | } |
123 | 168 | ||
124 | // Return 'true' if the passed object is the root object of this linkset | 169 | // Return 'true' if the passed object is the root object of this linkset |
125 | public bool IsRoot(BSPrim requestor) | 170 | public bool IsRoot(BSPhysObject requestor) |
126 | { | 171 | { |
127 | return (requestor.LocalID == m_linksetRoot.LocalID); | 172 | return (requestor.LocalID == LinksetRoot.LocalID); |
128 | } | 173 | } |
129 | 174 | ||
130 | public int NumberOfChildren { get { return m_children.Count; } } | 175 | public int NumberOfChildren { get { return m_children.Count; } } |
@@ -133,12 +178,14 @@ public class BSLinkset | |||
133 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | 178 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } |
134 | 179 | ||
135 | // Return 'true' if this child is in this linkset | 180 | // Return 'true' if this child is in this linkset |
136 | public bool HasChild(BSPrim child) | 181 | public bool HasChild(BSPhysObject child) |
137 | { | 182 | { |
138 | bool ret = false; | 183 | bool ret = false; |
139 | lock (m_linksetActivityLock) | 184 | lock (m_linksetActivityLock) |
140 | { | 185 | { |
141 | foreach (BSPrim bp in m_children) | 186 | ret = m_children.Contains(child); |
187 | /* Safer version but the above should work | ||
188 | foreach (BSPhysObject bp in m_children) | ||
142 | { | 189 | { |
143 | if (child.LocalID == bp.LocalID) | 190 | if (child.LocalID == bp.LocalID) |
144 | { | 191 | { |
@@ -146,274 +193,132 @@ public class BSLinkset | |||
146 | break; | 193 | break; |
147 | } | 194 | } |
148 | } | 195 | } |
196 | */ | ||
149 | } | 197 | } |
150 | return ret; | 198 | return ret; |
151 | } | 199 | } |
152 | 200 | ||
153 | private float ComputeLinksetMass() | 201 | // Perform an action on each member of the linkset including root prim. |
154 | { | 202 | // Depends on the action on whether this should be done at taint time. |
155 | float mass = m_linksetRoot.MassRaw; | 203 | public delegate bool ForEachMemberAction(BSPhysObject obj); |
156 | foreach (BSPrim bp in m_children) | 204 | public virtual bool ForEachMember(ForEachMemberAction action) |
157 | { | ||
158 | mass += bp.MassRaw; | ||
159 | } | ||
160 | return mass; | ||
161 | } | ||
162 | |||
163 | private OMV.Vector3 ComputeLinksetCenterOfMass() | ||
164 | { | 205 | { |
165 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; | 206 | bool ret = false; |
166 | float totalMass = m_linksetRoot.MassRaw; | ||
167 | |||
168 | lock (m_linksetActivityLock) | 207 | lock (m_linksetActivityLock) |
169 | { | 208 | { |
170 | foreach (BSPrim bp in m_children) | 209 | action(LinksetRoot); |
210 | foreach (BSPhysObject po in m_children) | ||
171 | { | 211 | { |
172 | com += bp.Position * bp.MassRaw; | 212 | if (action(po)) |
173 | totalMass += bp.MassRaw; | 213 | break; |
174 | } | 214 | } |
175 | if (totalMass != 0f) | ||
176 | com /= totalMass; | ||
177 | } | 215 | } |
178 | 216 | return ret; | |
179 | return com; | ||
180 | } | 217 | } |
181 | 218 | ||
182 | private OMV.Vector3 ComputeLinksetGeometricCenter() | 219 | // I am the root of a linkset and a new child is being added |
183 | { | 220 | // Called while LinkActivity is locked. |
184 | OMV.Vector3 com = m_linksetRoot.Position; | 221 | protected abstract void AddChildToLinkset(BSPhysObject child); |
185 | |||
186 | lock (m_linksetActivityLock) | ||
187 | { | ||
188 | foreach (BSPrim bp in m_children) | ||
189 | { | ||
190 | com += bp.Position * bp.MassRaw; | ||
191 | } | ||
192 | com /= (m_children.Count + 1); | ||
193 | } | ||
194 | 222 | ||
195 | return com; | 223 | // I am the root of a linkset and one of my children is being removed. |
196 | } | 224 | // Safe to call even if the child is not really in my linkset. |
225 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | ||
197 | 226 | ||
198 | // When physical properties are changed the linkset needs to recalculate | 227 | // When physical properties are changed the linkset needs to recalculate |
199 | // its internal properties. | 228 | // its internal properties. |
200 | public void Refresh(BSPrim requestor) | 229 | // May be called at runtime or taint-time. |
201 | { | 230 | public abstract void Refresh(BSPhysObject requestor); |
202 | // If there are no children, there aren't any constraints to recompute | 231 | |
203 | if (!HasAnyChildren) | 232 | // The object is going dynamic (physical). Do any setup necessary |
204 | return; | 233 | // for a dynamic linkset. |
205 | 234 | // Only the state of the passed object can be modified. The rest of the linkset | |
206 | // Only the root does the recomputation | 235 | // has not yet been fully constructed. |
207 | if (IsRoot(requestor)) | 236 | // Return 'true' if any properties updated on the passed object. |
208 | { | 237 | // Called at taint-time! |
209 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() | 238 | public abstract bool MakeDynamic(BSPhysObject child); |
210 | { | 239 | |
211 | RecomputeLinksetConstraintVariables(); | 240 | // The object is going static (non-physical). Do any setup necessary |
212 | }); | 241 | // for a static linkset. |
213 | } | 242 | // Return 'true' if any properties updated on the passed object. |
214 | } | 243 | // Called at taint-time! |
215 | 244 | public abstract bool MakeStatic(BSPhysObject child); | |
216 | // Call each of the constraints that make up this linkset and recompute the | 245 | |
217 | // various transforms and variables. Used when objects are added or removed | 246 | // Called when a parameter update comes from the physics engine for any object |
218 | // from a linkset to make sure the constraints know about the new mass and | 247 | // of the linkset is received. |
219 | // geometry. | 248 | // Called at taint-time!! |
220 | // Must only be called at taint time!! | 249 | public abstract void UpdateProperties(BSPhysObject physObject); |
221 | private bool RecomputeLinksetConstraintVariables() | 250 | |
251 | // Routine used when rebuilding the body of the root of the linkset | ||
252 | // Destroy all the constraints have have been made to root. | ||
253 | // This is called when the root body is changing. | ||
254 | // Returns 'true' of something was actually removed and would need restoring | ||
255 | // Called at taint-time!! | ||
256 | public abstract bool RemoveBodyDependencies(BSPrim child); | ||
257 | |||
258 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
259 | // this routine will restore the removed constraints. | ||
260 | // Called at taint-time!! | ||
261 | public abstract void RestoreBodyDependencies(BSPrim child); | ||
262 | |||
263 | // ================================================================ | ||
264 | protected virtual float ComputeLinksetMass() | ||
222 | { | 265 | { |
223 | float linksetMass = LinksetMass; | 266 | float mass = LinksetRoot.RawMass; |
224 | lock (m_linksetActivityLock) | 267 | if (HasAnyChildren) |
225 | { | 268 | { |
226 | foreach (BSPrim child in m_children) | 269 | lock (m_linksetActivityLock) |
227 | { | 270 | { |
228 | BSConstraint constrain; | 271 | foreach (BSPhysObject bp in m_children) |
229 | if (m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.Body, child.Body, out constrain)) | ||
230 | { | ||
231 | // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", | ||
232 | // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); | ||
233 | constrain.RecomputeConstraintVariables(linksetMass); | ||
234 | } | ||
235 | else | ||
236 | { | 272 | { |
237 | // Non-fatal error that can happen when children are being added to the linkset but | 273 | mass += bp.RawMass; |
238 | // their constraints have not been created yet. | ||
239 | // Caused by the fact that m_children is built at run time but building constraints | ||
240 | // happens at taint time. | ||
241 | // m_physicsScene.Logger.ErrorFormat("[BULLETSIM LINKSET] RecomputeLinksetConstraintVariables: constraint not found for root={0}, child={1}", | ||
242 | // m_linksetRoot.Body.ID, child.Body.ID); | ||
243 | } | 274 | } |
244 | } | 275 | } |
245 | } | 276 | } |
246 | return false; | 277 | return mass; |
247 | } | 278 | } |
248 | 279 | ||
249 | // I am the root of a linkset and a new child is being added | 280 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() |
250 | // Called while LinkActivity is locked. | ||
251 | private void AddChildToLinkset(BSPrim child) | ||
252 | { | 281 | { |
253 | if (!HasChild(child)) | 282 | OMV.Vector3 com; |
283 | lock (m_linksetActivityLock) | ||
254 | { | 284 | { |
255 | m_children.Add(child); | 285 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
286 | float totalMass = LinksetRoot.RawMass; | ||
256 | 287 | ||
257 | BSPrim rootx = LinksetRoot; // capture the root as of now | 288 | foreach (BSPhysObject bp in m_children) |
258 | BSPrim childx = child; | ||
259 | m_physicsScene.TaintedObject("AddChildToLinkset", delegate() | ||
260 | { | 289 | { |
261 | // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); | 290 | com += bp.Position * bp.RawMass; |
262 | // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | 291 | totalMass += bp.RawMass; |
263 | PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child | 292 | } |
264 | }); | 293 | if (totalMass != 0f) |
294 | com /= totalMass; | ||
265 | } | 295 | } |
266 | return; | ||
267 | } | ||
268 | 296 | ||
269 | // Forcefully removing a child from a linkset. | 297 | return com; |
270 | // This is not being called by the child so we have to make sure the child doesn't think | ||
271 | // it's still connected to the linkset. | ||
272 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information | ||
273 | // has to be updated also (like pointer to prim's parent). | ||
274 | private void RemoveChildFromOtherLinkset(BSPrim pchild) | ||
275 | { | ||
276 | pchild.Linkset = new BSLinkset(m_physicsScene, pchild); | ||
277 | RemoveChildFromLinkset(pchild); | ||
278 | } | 298 | } |
279 | 299 | ||
280 | // I am the root of a linkset and one of my children is being removed. | 300 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() |
281 | // Safe to call even if the child is not really in my linkset. | ||
282 | private void RemoveChildFromLinkset(BSPrim child) | ||
283 | { | 301 | { |
284 | if (m_children.Remove(child)) | 302 | OMV.Vector3 com; |
303 | lock (m_linksetActivityLock) | ||
285 | { | 304 | { |
286 | BSPrim rootx = LinksetRoot; // capture the root as of now | 305 | com = LinksetRoot.Position; |
287 | BSPrim childx = child; | ||
288 | m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | ||
289 | { | ||
290 | // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); | ||
291 | // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | ||
292 | |||
293 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
294 | }); | ||
295 | 306 | ||
296 | RecomputeLinksetConstraintVariables(); | 307 | foreach (BSPhysObject bp in m_children) |
297 | } | 308 | { |
298 | else | 309 | com += bp.Position * bp.RawMass; |
299 | { | 310 | } |
300 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | 311 | com /= (m_children.Count + 1); |
301 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
302 | } | 312 | } |
303 | return; | ||
304 | } | ||
305 | |||
306 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
307 | // Called at taint time! | ||
308 | private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) | ||
309 | { | ||
310 | // Zero motion for children so they don't interpolate | ||
311 | childPrim.ZeroMotion(); | ||
312 | |||
313 | // Relative position normalized to the root prim | ||
314 | // Essentually a vector pointing from center of rootPrim to center of childPrim | ||
315 | OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position; | ||
316 | |||
317 | // real world coordinate of midpoint between the two objects | ||
318 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
319 | |||
320 | // create a constraint that allows no freedom of movement between the two objects | ||
321 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
322 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
323 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", | ||
324 | rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); | ||
325 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
326 | m_physicsScene.World, rootPrim.Body, childPrim.Body, | ||
327 | midPoint, | ||
328 | true, | ||
329 | true | ||
330 | ); | ||
331 | /* NOTE: attempt to build constraint with full frame computation, etc. | ||
332 | * Using the midpoint is easier since it lets the Bullet code use the transforms | ||
333 | * of the objects. | ||
334 | * Code left here as an example. | ||
335 | // ================================================================================== | ||
336 | // relative position normalized to the root prim | ||
337 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
338 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; | ||
339 | |||
340 | // relative rotation of the child to the parent | ||
341 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
342 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
343 | |||
344 | // create a constraint that allows no freedom of movement between the two objects | ||
345 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
346 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
347 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
348 | BS6DofConstraint constrain = new BS6DofConstraint( | ||
349 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | ||
350 | OMV.Vector3.Zero, | ||
351 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
352 | OMV.Vector3.Zero, | ||
353 | OMV.Quaternion.Inverse(childPrim.Orientation), | ||
354 | // A point half way between the parent and child | ||
355 | // childRelativePosition/2, | ||
356 | // childRelativeRotation, | ||
357 | // childRelativePosition/2, | ||
358 | // inverseChildRelativeRotation, | ||
359 | true, | ||
360 | true | ||
361 | ); | ||
362 | // ================================================================================== | ||
363 | */ | ||
364 | |||
365 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
366 | |||
367 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
368 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
369 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
370 | |||
371 | // tweek the constraint to increase stability | ||
372 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); | ||
373 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), | ||
374 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | ||
375 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | ||
376 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | ||
377 | |||
378 | RecomputeLinksetConstraintVariables(); | ||
379 | } | ||
380 | 313 | ||
381 | // Remove linkage between myself and a particular child | 314 | return com; |
382 | // Called at taint time! | ||
383 | private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) | ||
384 | { | ||
385 | // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", | ||
386 | // LogHeader, rootPrim.LocalID, childPrim.LocalID); | ||
387 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | ||
388 | |||
389 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
390 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body); | ||
391 | |||
392 | // Make the child refresh its location | ||
393 | BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); | ||
394 | } | ||
395 | |||
396 | // Remove linkage between myself and any possible children I might have | ||
397 | // Called at taint time! | ||
398 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) | ||
399 | { | ||
400 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | ||
401 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
402 | |||
403 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); | ||
404 | } | ||
405 | |||
406 | // Invoke the detailed logger and output something if it's enabled. | ||
407 | private void DebugLog(string msg, params Object[] args) | ||
408 | { | ||
409 | if (m_physicsScene.ShouldDebugLog) | ||
410 | m_physicsScene.Logger.DebugFormat(msg, args); | ||
411 | } | 315 | } |
412 | 316 | ||
413 | // Invoke the detailed logger and output something if it's enabled. | 317 | // Invoke the detailed logger and output something if it's enabled. |
414 | private void DetailLog(string msg, params Object[] args) | 318 | protected void DetailLog(string msg, params Object[] args) |
415 | { | 319 | { |
416 | m_physicsScene.PhysicsLogging.Write(msg, args); | 320 | if (PhysicsScene.PhysicsLogging.Enabled) |
321 | PhysicsScene.DetailLog(msg, args); | ||
417 | } | 322 | } |
418 | 323 | ||
419 | } | 324 | } |