aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs445
1 files changed, 300 insertions, 145 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 087b9bb..43b1262 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -34,16 +34,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public class BSLinkset 35public 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 BSPhysObject LinksetRoot { get; protected set; }
40 public BSPrim LinksetRoot { get { return m_linksetRoot; } }
41 40
42 private BSScene m_physicsScene; 41 public BSScene PhysicsScene { get; private set; }
43 public BSScene PhysicsScene { get { return m_physicsScene; } }
44 42
45 // The children under the root in this linkset 43 static int m_nextLinksetID = 1;
46 private List<BSPrim> m_children; 44 public int LinksetID { get; private set; }
45
46 // The children under the root in this linkset.
47 // There are two lists of children: the current children at runtime
48 // and the children at taint-time. For instance, if you delink a
49 // child from the linkset, the child is removed from m_children
50 // but the constraint won't be removed until taint time.
51 // Two lists lets this track the 'current' children and
52 // the physical 'taint' children separately.
53 // After taint processing and before the simulation step, these
54 // two lists must be the same.
55 private HashSet<BSPhysObject> m_children;
56 private HashSet<BSPhysObject> m_taintChildren;
47 57
48 // We lock the diddling of linkset classes to prevent any badness. 58 // We lock the diddling of linkset classes to prevent any badness.
49 // This locks the modification of the instances of this class. Changes 59 // This locks the modification of the instances of this class. Changes
@@ -52,9 +62,9 @@ public class BSLinkset
52 62
53 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 63 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
54 private float m_mass; 64 private float m_mass;
55 public float LinksetMass 65 public float LinksetMass
56 { 66 {
57 get 67 get
58 { 68 {
59 m_mass = ComputeLinksetMass(); 69 m_mass = ComputeLinksetMass();
60 return m_mass; 70 return m_mass;
@@ -71,23 +81,31 @@ public class BSLinkset
71 get { return ComputeLinksetGeometricCenter(); } 81 get { return ComputeLinksetGeometricCenter(); }
72 } 82 }
73 83
74 public BSLinkset(BSScene scene, BSPrim parent) 84 public BSLinkset(BSScene scene, BSPhysObject parent)
75 { 85 {
76 // A simple linkset of one (no children) 86 // A simple linkset of one (no children)
77 m_physicsScene = scene; 87 LinksetID = m_nextLinksetID++;
78 m_linksetRoot = parent; 88 // We create LOTS of linksets.
79 m_children = new List<BSPrim>(); 89 if (m_nextLinksetID <= 0)
90 m_nextLinksetID = 1;
91 PhysicsScene = scene;
92 LinksetRoot = parent;
93 m_children = new HashSet<BSPhysObject>();
94 m_taintChildren = new HashSet<BSPhysObject>();
80 m_mass = parent.MassRaw; 95 m_mass = parent.MassRaw;
81 } 96 }
82 97
83 // Link to a linkset where the child knows the parent. 98 // Link to a linkset where the child knows the parent.
84 // Parent changing should not happen so do some sanity checking. 99 // Parent changing should not happen so do some sanity checking.
85 // We return the parent's linkset so the child can track its membership. 100 // We return the parent's linkset so the child can track its membership.
86 public BSLinkset AddMeToLinkset(BSPrim child) 101 // Called at runtime.
102 public BSLinkset AddMeToLinkset(BSPhysObject child)
87 { 103 {
88 lock (m_linksetActivityLock) 104 lock (m_linksetActivityLock)
89 { 105 {
90 AddChildToLinkset(child); 106 // Don't add the root to its own linkset
107 if (!IsRoot(child))
108 AddChildToLinkset(child);
91 } 109 }
92 return this; 110 return this;
93 } 111 }
@@ -95,26 +113,18 @@ public class BSLinkset
95 // Remove a child from a linkset. 113 // Remove a child from a linkset.
96 // Returns a new linkset for the child which is a linkset of one (just the 114 // Returns a new linkset for the child which is a linkset of one (just the
97 // orphened child). 115 // orphened child).
98 public BSLinkset RemoveMeFromLinkset(BSPrim child) 116 // Called at runtime.
117 public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
99 { 118 {
100 lock (m_linksetActivityLock) 119 lock (m_linksetActivityLock)
101 { 120 {
102 if (IsRoot(child)) 121 if (IsRoot(child))
103 { 122 {
104 // if root of linkset, take the linkset apart 123 // Cannot remove the root from a linkset.
105 while (m_children.Count > 0) 124 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 } 125 }
126
127 RemoveChildFromLinkset(child);
118 } 128 }
119 129
120 // The child is down to a linkset of just itself 130 // The child is down to a linkset of just itself
@@ -122,9 +132,9 @@ public class BSLinkset
122 } 132 }
123 133
124 // Return 'true' if the passed object is the root object of this linkset 134 // Return 'true' if the passed object is the root object of this linkset
125 public bool IsRoot(BSPrim requestor) 135 public bool IsRoot(BSPhysObject requestor)
126 { 136 {
127 return (requestor.LocalID == m_linksetRoot.LocalID); 137 return (requestor.LocalID == LinksetRoot.LocalID);
128 } 138 }
129 139
130 public int NumberOfChildren { get { return m_children.Count; } } 140 public int NumberOfChildren { get { return m_children.Count; } }
@@ -133,12 +143,12 @@ public class BSLinkset
133 public bool HasAnyChildren { get { return (m_children.Count > 0); } } 143 public bool HasAnyChildren { get { return (m_children.Count > 0); } }
134 144
135 // Return 'true' if this child is in this linkset 145 // Return 'true' if this child is in this linkset
136 public bool HasChild(BSPrim child) 146 public bool HasChild(BSPhysObject child)
137 { 147 {
138 bool ret = false; 148 bool ret = false;
139 lock (m_linksetActivityLock) 149 lock (m_linksetActivityLock)
140 { 150 {
141 foreach (BSPrim bp in m_children) 151 foreach (BSPhysObject bp in m_children)
142 { 152 {
143 if (child.LocalID == bp.LocalID) 153 if (child.LocalID == bp.LocalID)
144 { 154 {
@@ -150,117 +160,204 @@ public class BSLinkset
150 return ret; 160 return ret;
151 } 161 }
152 162
153 private float ComputeLinksetMass() 163 // When physical properties are changed the linkset needs to recalculate
164 // its internal properties.
165 // May be called at runtime or taint-time (just pass the appropriate flag).
166 public void Refresh(BSPhysObject requestor, bool inTaintTime)
167 {
168 // If there are no children, not physical or not root, I am not the one that recomputes the constraints
169 // (For the moment, static linksets do create constraints so remove the test for physical.)
170 if (!HasAnyChildren || /*!requestor.IsPhysical ||*/ !IsRoot(requestor))
171 return;
172
173 BSScene.TaintCallback refreshOperation = delegate()
174 {
175 RecomputeLinksetConstraintVariables();
176 DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
177 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
178 };
179 if (inTaintTime)
180 refreshOperation();
181 else
182 PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
183 }
184
185 // The object is going dynamic (physical). Do any setup necessary
186 // for a dynamic linkset.
187 // Only the state of the passed object can be modified. The rest of the linkset
188 // has not yet been fully constructed.
189 // Return 'true' if any properties updated on the passed object.
190 // Called at taint-time!
191 public bool MakeDynamic(BSPhysObject child)
192 {
193 // What is done for each object in BSPrim is what we want.
194 return false;
195 }
196
197 // The object is going static (non-physical). Do any setup necessary
198 // for a static linkset.
199 // Return 'true' if any properties updated on the passed object.
200 // Called at taint-time!
201 public bool MakeStatic(BSPhysObject child)
202 {
203 // What is done for each object in BSPrim is what we want.
204 return false;
205 }
206
207 // If the software is handling the movement of all the objects in a linkset
208 // (like if one doesn't use constraints for static linksets), this is called
209 // when an update for the root of the linkset is received.
210 // Called at taint-time!!
211 public void UpdateProperties(BSPhysObject physObject)
154 { 212 {
155 float mass = m_linksetRoot.MassRaw; 213 // The root local properties have been updated. Apply to the children if appropriate.
156 foreach (BSPrim bp in m_children) 214 if (IsRoot(physObject) && HasAnyChildren)
157 { 215 {
158 mass += bp.MassRaw; 216 if (!physObject.IsPhysical)
217 {
218 // TODO: implement software linkset update for static object linksets
219 }
159 } 220 }
160 return mass;
161 } 221 }
162 222
163 private OMV.Vector3 ComputeLinksetCenterOfMass() 223 // Routine used when rebuilding the body of the root of the linkset
224 // Destroy all the constraints have have been made to root.
225 // This is called when the root body is changing.
226 // Returns 'true' of something eas actually removed and would need restoring
227 // Called at taint-time!!
228 public bool RemoveBodyDependencies(BSPrim child)
164 { 229 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 230 bool ret = false;
166 float totalMass = m_linksetRoot.MassRaw;
167 231
168 lock (m_linksetActivityLock) 232 lock (m_linksetActivityLock)
169 { 233 {
170 foreach (BSPrim bp in m_children) 234 if (IsRoot(child))
171 { 235 {
172 com += bp.Position * bp.MassRaw; 236 // If the one with the dependency is root, must undo all children
173 totalMass += bp.MassRaw; 237 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
238 child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
239
240 ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
241 }
242 else
243 {
244 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
245 child.LocalID,
246 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
247 child.LocalID, child.BSBody.ptr.ToString("X"));
248 // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
249 // Despite the function name, this removes any link to the specified object.
250 ret = PhysicallyUnlinkAllChildrenFromRoot(child);
174 } 251 }
175 if (totalMass != 0f)
176 com /= totalMass;
177 } 252 }
178 253 return ret;
179 return com;
180 } 254 }
181 255
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 256 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
257 // this routine will restore the removed constraints.
258 // Called at taint-time!!
259 public void RestoreBodyDependencies(BSPrim child)
183 { 260 {
184 OMV.Vector3 com = m_linksetRoot.Position;
185
186 lock (m_linksetActivityLock) 261 lock (m_linksetActivityLock)
187 { 262 {
188 foreach (BSPrim bp in m_children) 263 if (IsRoot(child))
189 { 264 {
190 com += bp.Position * bp.MassRaw; 265 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
266 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
267 foreach (BSPhysObject bpo in m_taintChildren)
268 {
269 PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
270 }
271 }
272 else
273 {
274 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
275 LinksetRoot.LocalID,
276 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
277 child.LocalID, child.BSBody.ptr.ToString("X"));
278 PhysicallyLinkAChildToRoot(LinksetRoot, child);
191 } 279 }
192 com /= (m_children.Count + 1);
193 } 280 }
194
195 return com;
196 } 281 }
197 282
198 // When physical properties are changed the linkset needs to recalculate 283 // ================================================================
199 // its internal properties. 284 // Below this point is internal magic
200 public void Refresh(BSPrim requestor) 285
286 private float ComputeLinksetMass()
201 { 287 {
202 // If there are no children, there aren't any constraints to recompute 288 float mass;
203 if (!HasAnyChildren) 289 lock (m_linksetActivityLock)
204 return; 290 {
291 mass = LinksetRoot.MassRaw;
292 foreach (BSPhysObject bp in m_taintChildren)
293 {
294 mass += bp.MassRaw;
295 }
296 }
297 return mass;
298 }
205 299
206 // Only the root does the recomputation 300 private OMV.Vector3 ComputeLinksetCenterOfMass()
207 if (IsRoot(requestor)) 301 {
302 OMV.Vector3 com;
303 lock (m_linksetActivityLock)
208 { 304 {
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 305 com = LinksetRoot.Position * LinksetRoot.MassRaw;
306 float totalMass = LinksetRoot.MassRaw;
307
308 foreach (BSPhysObject bp in m_taintChildren)
210 { 309 {
211 RecomputeLinksetConstraintVariables(); 310 com += bp.Position * bp.MassRaw;
212 }); 311 totalMass += bp.MassRaw;
312 }
313 if (totalMass != 0f)
314 com /= totalMass;
213 } 315 }
316
317 return com;
214 } 318 }
215 319
216 // Call each of the constraints that make up this linkset and recompute the 320 private OMV.Vector3 ComputeLinksetGeometricCenter()
217 // various transforms and variables. Used when objects are added or removed
218 // from a linkset to make sure the constraints know about the new mass and
219 // geometry.
220 // Must only be called at taint time!!
221 private bool RecomputeLinksetConstraintVariables()
222 { 321 {
223 float linksetMass = LinksetMass; 322 OMV.Vector3 com;
224 lock (m_linksetActivityLock) 323 lock (m_linksetActivityLock)
225 { 324 {
226 foreach (BSPrim child in m_children) 325 com = LinksetRoot.Position;
326
327 foreach (BSPhysObject bp in m_taintChildren)
227 { 328 {
228 BSConstraint constrain; 329 com += bp.Position * bp.MassRaw;
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 {
237 // Non-fatal error that can happen when children are being added to the linkset but
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 }
244 } 330 }
331 com /= (m_taintChildren.Count + 1);
245 } 332 }
246 return false; 333
334 return com;
247 } 335 }
248 336
249 // I am the root of a linkset and a new child is being added 337 // I am the root of a linkset and a new child is being added
250 // Called while LinkActivity is locked. 338 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child) 339 private void AddChildToLinkset(BSPhysObject child)
252 { 340 {
253 if (!HasChild(child)) 341 if (!HasChild(child))
254 { 342 {
255 m_children.Add(child); 343 m_children.Add(child);
256 344
257 BSPrim rootx = LinksetRoot; // capture the root as of now 345 BSPhysObject rootx = LinksetRoot; // capture the root as of now
258 BSPrim childx = child; 346 BSPhysObject childx = child;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate() 347
348 DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
349
350 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
260 { 351 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); 352 DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}",
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 353 rootx.LocalID,
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 354 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
355 childx.LocalID, childx.BSBody.ptr.ToString("X"));
356 // Since this is taint-time, the body and shape could have changed for the child
357 rootx.ForcePosition = rootx.Position; // DEBUG
358 childx.ForcePosition = childx.Position; // DEBUG
359 PhysicallyLinkAChildToRoot(rootx, childx);
360 m_taintChildren.Add(child);
264 }); 361 });
265 } 362 }
266 return; 363 return;
@@ -270,30 +367,34 @@ public class BSLinkset
270 // This is not being called by the child so we have to make sure the child doesn't think 367 // 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. 368 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 369 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent). 370 // also has to be updated (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild) 371 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
275 { 372 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild); 373 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
277 RemoveChildFromLinkset(pchild); 374 RemoveChildFromLinkset(pchild);
278 } 375 }
279 376
280 // I am the root of a linkset and one of my children is being removed. 377 // I am the root of a linkset and one of my children is being removed.
281 // Safe to call even if the child is not really in my linkset. 378 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child) 379 private void RemoveChildFromLinkset(BSPhysObject child)
283 { 380 {
284 if (m_children.Remove(child)) 381 if (m_children.Remove(child))
285 { 382 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now 383 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
287 BSPrim childx = child; 384 BSPhysObject childx = child;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 385
289 { 386 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); 387 childx.LocalID,
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 388 rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
389 childx.LocalID, childx.BSBody.ptr.ToString("X"));
292 390
391 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
392 {
393 m_taintChildren.Remove(child);
293 PhysicallyUnlinkAChildFromRoot(rootx, childx); 394 PhysicallyUnlinkAChildFromRoot(rootx, childx);
395 RecomputeLinksetConstraintVariables();
294 }); 396 });
295 397
296 RecomputeLinksetConstraintVariables();
297 } 398 }
298 else 399 else
299 { 400 {
@@ -305,7 +406,7 @@ public class BSLinkset
305 406
306 // Create a constraint between me (root of linkset) and the passed prim (the child). 407 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time! 408 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) 409 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
309 { 410 {
310 // Zero motion for children so they don't interpolate 411 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion(); 412 childPrim.ZeroMotion();
@@ -317,21 +418,22 @@ public class BSLinkset
317 // real world coordinate of midpoint between the two objects 418 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 419 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319 420
421 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
422 rootPrim.LocalID,
423 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
424 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
425 rootPrim.Position, childPrim.Position, midPoint);
426
320 // create a constraint that allows no freedom of movement between the two objects 427 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 428 // 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); 429
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( 430 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body, 431 PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
327 midPoint, 432
328 true, 433 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
329 true 434 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
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. 435 * of the objects.
334 * Code left here as an example. 436 * Code left as a warning to future programmers.
335 // ================================================================================== 437 // ==================================================================================
336 // relative position normalized to the root prim 438 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); 439 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@@ -343,8 +445,7 @@ public class BSLinkset
343 445
344 // create a constraint that allows no freedom of movement between the two objects 446 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 447 // 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); 448 DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
347 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint( 449 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body, 450 PhysicsScene.World, rootPrim.Body, childPrim.Body,
350 OMV.Vector3.Zero, 451 OMV.Vector3.Zero,
@@ -362,7 +463,7 @@ public class BSLinkset
362 // ================================================================================== 463 // ==================================================================================
363 */ 464 */
364 465
365 m_physicsScene.Constraints.AddConstraint(constrain); 466 PhysicsScene.Constraints.AddConstraint(constrain);
366 467
367 // zero linear and angular limits makes the objects unable to move in relation to each other 468 // 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); 469 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -374,46 +475,100 @@ public class BSLinkset
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 475 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 476 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 477 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
377 478 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
378 RecomputeLinksetConstraintVariables(); 479 {
480 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
481 }
379 } 482 }
380 483
381 // Remove linkage between myself and a particular child 484 // Remove linkage between myself and a particular child
485 // The root and child bodies are passed in because we need to remove the constraint between
486 // the bodies that were at unlink time.
382 // Called at taint time! 487 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) 488 private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
384 { 489 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 490 bool ret = false;
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID); 491 DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 492 rootPrim.LocalID,
493 rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
494 childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
388 495
389 // Find the constraint for this link and get rid of it from the overall collection and from my list 496 // 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); 497 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
498 {
499 // Make the child refresh its location
500 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
501 ret = true;
502 }
391 503
392 // Make the child refresh its location 504 return ret;
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
394 } 505 }
395 506
396 // Remove linkage between myself and any possible children I might have 507 // Remove linkage between myself and any possible children I might have.
397 // Called at taint time! 508 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) 509 private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
399 { 510 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); 511 DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 512 bool ret = false;
402 513
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); 514 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
515 {
516 ret = true;
517 }
518 return ret;
404 } 519 }
405 520
406 // Invoke the detailed logger and output something if it's enabled. 521 // Call each of the constraints that make up this linkset and recompute the
407 private void DebugLog(string msg, params Object[] args) 522 // various transforms and variables. Used when objects are added or removed
523 // from a linkset to make sure the constraints know about the new mass and
524 // geometry.
525 // Must only be called at taint time!!
526 private void RecomputeLinksetConstraintVariables()
408 { 527 {
409 if (m_physicsScene.ShouldDebugLog) 528 float linksetMass = LinksetMass;
410 m_physicsScene.Logger.DebugFormat(msg, args); 529 foreach (BSPhysObject child in m_taintChildren)
530 {
531 BSConstraint constrain;
532 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
533 {
534 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
535 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
536 constrain.RecomputeConstraintVariables(linksetMass);
537 }
538 else
539 {
540 // Non-fatal error that happens when children are being added to the linkset but
541 // their constraints have not been created yet.
542 break;
543 }
544 }
545
546 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
547 if (m_children.Count == m_taintChildren.Count)
548 {
549 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
550 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
551 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr,
552 centerOfMass, OMV.Quaternion.Identity);
553 DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
554 LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
555 foreach (BSPhysObject child in m_taintChildren)
556 {
557 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr,
558 centerOfMass, OMV.Quaternion.Identity);
559 }
560
561 // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG
562 }
563 return;
411 } 564 }
412 565
566
413 // Invoke the detailed logger and output something if it's enabled. 567 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 568 private void DetailLog(string msg, params Object[] args)
415 { 569 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 570 if (PhysicsScene.PhysicsLogging.Enabled)
571 PhysicsScene.DetailLog(msg, args);
417 } 572 }
418 573
419} 574}