aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs385
1 files changed, 385 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
new file mode 100755
index 0000000..8a750b5
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -0,0 +1,385 @@
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 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35public class BSLinksetConstraints : BSLinkset
36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent)
40 {
41 base.Initialize(scene, parent);
42 }
43
44 // When physical properties are changed the linkset needs to recalculate
45 // its internal properties.
46 // May be called at runtime or taint-time (just pass the appropriate flag).
47 public override void Refresh(BSPhysObject requestor, bool inTaintTime)
48 {
49 // If there are no children or not root, I am not the one that recomputes the constraints
50 if (!HasAnyChildren || !IsRoot(requestor))
51 return;
52
53 BSScene.TaintCallback refreshOperation = delegate()
54 {
55 RecomputeLinksetConstraintVariables();
56 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
57 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
58 };
59 if (inTaintTime)
60 refreshOperation();
61 else
62 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
63 }
64
65 // The object is going dynamic (physical). Do any setup necessary
66 // for a dynamic linkset.
67 // Only the state of the passed object can be modified. The rest of the linkset
68 // has not yet been fully constructed.
69 // Return 'true' if any properties updated on the passed object.
70 // Called at taint-time!
71 public override bool MakeDynamic(BSPhysObject child)
72 {
73 // What is done for each object in BSPrim is what we want.
74 return false;
75 }
76
77 // The object is going static (non-physical). Do any setup necessary
78 // for a static linkset.
79 // Return 'true' if any properties updated on the passed object.
80 // Called at taint-time!
81 public override bool MakeStatic(BSPhysObject child)
82 {
83 // What is done for each object in BSPrim is what we want.
84 return false;
85 }
86
87 // Called at taint-time!!
88 public override void UpdateProperties(BSPhysObject updated)
89 {
90 // Nothing to do for constraints on property updates
91 }
92
93 // Routine used when rebuilding the body of the root of the linkset
94 // Destroy all the constraints have have been made to root.
95 // This is called when the root body is changing.
96 // Returns 'true' of something eas actually removed and would need restoring
97 // Called at taint-time!!
98 public override bool RemoveBodyDependencies(BSPrim child)
99 {
100 bool ret = false;
101
102 lock (m_linksetActivityLock)
103 {
104 if (IsRoot(child))
105 {
106 // If the one with the dependency is root, must undo all children
107 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
108 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
109
110 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
111 }
112 else
113 {
114 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
115 child.LocalID,
116 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
117 child.LocalID, child.BSBody.ptr.ToString("X"));
118 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
119 // Despite the function name, this removes any link to the specified object.
120 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
121 }
122 }
123 return ret;
124 }
125
126 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
127 // this routine will restore the removed constraints.
128 // Called at taint-time!!
129 public override void RestoreBodyDependencies(BSPrim child)
130 {
131 lock (m_linksetActivityLock)
132 {
133 if (IsRoot(child))
134 {
135 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
136 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
137 foreach (BSPhysObject bpo in m_taintChildren)
138 {
139 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
140 }
141 }
142 else
143 {
144 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
145 LinksetRoot.LocalID,
146 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
147 child.LocalID, child.BSBody.ptr.ToString("X"));
148 PhysicallyLinkAChildToRoot(LinksetRoot, child);
149 }
150 }
151 }
152
153 // ================================================================
154 // Below this point is internal magic
155
156 // I am the root of a linkset and a new child is being added
157 // Called while LinkActivity is locked.
158 protected override void AddChildToLinkset(BSPhysObject child)
159 {
160 if (!HasChild(child))
161 {
162 m_children.Add(child);
163
164 BSPhysObject rootx = LinksetRoot; // capture the root as of now
165 BSPhysObject childx = child;
166
167 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
168
169 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
170 {
171 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
172 rootx.LocalID,
173 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
174 childx.LocalID, childx.BSBody.ptr.ToString("X"));
175 // Since this is taint-time, the body and shape could have changed for the child
176 rootx.ForcePosition = rootx.Position; // DEBUG
177 childx.ForcePosition = childx.Position; // DEBUG
178 PhysicallyLinkAChildToRoot(rootx, childx);
179 m_taintChildren.Add(child);
180 });
181 }
182 return;
183 }
184
185 // Forcefully removing a child from a linkset.
186 // This is not being called by the child so we have to make sure the child doesn't think
187 // it's still connected to the linkset.
188 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
189 // also has to be updated (like pointer to prim's parent).
190 protected override void RemoveChildFromOtherLinkset(BSPhysObject pchild)
191 {
192 pchild.Linkset = BSLinkset.Factory(PhysicsScene, pchild);
193 RemoveChildFromLinkset(pchild);
194 }
195
196 // I am the root of a linkset and one of my children is being removed.
197 // Safe to call even if the child is not really in my linkset.
198 protected override void RemoveChildFromLinkset(BSPhysObject child)
199 {
200 if (m_children.Remove(child))
201 {
202 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
203 BSPhysObject childx = child;
204
205 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
206 childx.LocalID,
207 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
208 childx.LocalID, childx.BSBody.ptr.ToString("X"));
209
210 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
211 {
212 m_taintChildren.Remove(child);
213 PhysicallyUnlinkAChildFromRoot(rootx, childx);
214 RecomputeLinksetConstraintVariables();
215 });
216
217 }
218 else
219 {
220 // This will happen if we remove the root of the linkset first. Non-fatal occurance.
221 // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
222 }
223 return;
224 }
225
226 // Create a constraint between me (root of linkset) and the passed prim (the child).
227 // Called at taint time!
228 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
229 {
230 // Zero motion for children so they don't interpolate
231 childPrim.ZeroMotion();
232
233 // Relative position normalized to the root prim
234 // Essentually a vector pointing from center of rootPrim to center of childPrim
235 OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;
236
237 // real world coordinate of midpoint between the two objects
238 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
239
240 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
241 rootPrim.LocalID,
242 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
243 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
244 rootPrim.Position, childPrim.Position, midPoint);
245
246 // create a constraint that allows no freedom of movement between the two objects
247 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
248
249 BS6DofConstraint constrain = new BS6DofConstraint(
250 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
251
252 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
253 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
254 * of the objects.
255 * Code left as a warning to future programmers.
256 // ==================================================================================
257 // relative position normalized to the root prim
258 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
259 OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
260
261 // relative rotation of the child to the parent
262 OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
263 OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
264
265 // create a constraint that allows no freedom of movement between the two objects
266 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
267 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
268 BS6DofConstraint constrain = new BS6DofConstraint(
269 PhysicsScene.World, rootPrim.Body, childPrim.Body,
270 OMV.Vector3.Zero,
271 OMV.Quaternion.Inverse(rootPrim.Orientation),
272 OMV.Vector3.Zero,
273 OMV.Quaternion.Inverse(childPrim.Orientation),
274 // A point half way between the parent and child
275 // childRelativePosition/2,
276 // childRelativeRotation,
277 // childRelativePosition/2,
278 // inverseChildRelativeRotation,
279 true,
280 true
281 );
282 // ==================================================================================
283 */
284
285 PhysicsScene.Constraints.AddConstraint(constrain);
286
287 // zero linear and angular limits makes the objects unable to move in relation to each other
288 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
289 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
290
291 // tweek the constraint to increase stability
292 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
293 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
294 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
295 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
296 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
297 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
298 {
299 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
300 }
301 }
302
303 // Remove linkage between myself and a particular child
304 // The root and child bodies are passed in because we need to remove the constraint between
305 // the bodies that were at unlink time.
306 // Called at taint time!
307 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
308 {
309 bool ret = false;
310 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
311 rootPrim.LocalID,
312 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
313 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
314
315 // Find the constraint for this link and get rid of it from the overall collection and from my list
316 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
317 {
318 // Make the child refresh its location
319 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
320 ret = true;
321 }
322
323 return ret;
324 }
325
326 // Remove linkage between myself and any possible children I might have.
327 // Called at taint time!
328 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
329 {
330 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
331 bool ret = false;
332
333 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
334 {
335 ret = true;
336 }
337 return ret;
338 }
339
340 // Call each of the constraints that make up this linkset and recompute the
341 // various transforms and variables. Used when objects are added or removed
342 // from a linkset to make sure the constraints know about the new mass and
343 // geometry.
344 // Must only be called at taint time!!
345 private void RecomputeLinksetConstraintVariables()
346 {
347 float linksetMass = LinksetMass;
348 foreach (BSPhysObject child in m_taintChildren)
349 {
350 BSConstraint constrain;
351 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
352 {
353 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
354 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
355 constrain.RecomputeConstraintVariables(linksetMass);
356 }
357 else
358 {
359 // Non-fatal error that happens when children are being added to the linkset but
360 // their constraints have not been created yet.
361 break;
362 }
363 }
364
365 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
366 if (m_children.Count == m_taintChildren.Count)
367 {
368 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
369 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
370 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
371 centerOfMass, OMV.Quaternion.Identity);
372 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
373 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
374 foreach (BSPhysObject child in m_taintChildren)
375 {
376 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
377 centerOfMass, OMV.Quaternion.Identity);
378 }
379
380 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
381 }
382 return;
383 }
384}
385}