aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs422
1 files changed, 287 insertions, 135 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 087b9bb..4f225ae 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -36,14 +36,24 @@ public 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 List<BSPhysObject> m_children;
56 private List<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 List<BSPhysObject>();
94 m_taintChildren = new List<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,192 @@ public class BSLinkset
150 return ret; 160 return ret;
151 } 161 }
152 162
153 private float ComputeLinksetMass() 163 // The object is going dynamic (physical). Do any setup necessary
164 // for a dynamic linkset.
165 // Only the state of the passed object can be modified. The rest of the linkset
166 // has not yet been fully constructed.
167 // Return 'true' if any properties updated on the passed object.
168 // Called at taint-time!
169 public bool MakeDynamic(BSPhysObject child)
170 {
171 // What is done for each object in BSPrim is what we want.
172 return false;
173 }
174
175 // The object is going static (non-physical). Do any setup necessary
176 // for a static linkset.
177 // Return 'true' if any properties updated on the passed object.
178 // Called at taint-time!
179 public bool MakeStatic(BSPhysObject child)
180 {
181 // What is done for each object in BSPrim is what we want.
182 return false;
183 }
184
185 // When physical properties are changed the linkset needs to recalculate
186 // its internal properties.
187 // Called at runtime.
188 public void Refresh(BSPhysObject requestor)
154 { 189 {
155 float mass = m_linksetRoot.MassRaw; 190 // If there are no children, there can't be any constraints to recompute
156 foreach (BSPrim bp in m_children) 191 if (!HasAnyChildren)
192 return;
193
194 // Only the root does the recomputation
195 if (IsRoot(requestor))
157 { 196 {
158 mass += bp.MassRaw; 197 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
198 {
199 RecomputeLinksetConstraintVariables();
200 });
159 } 201 }
160 return mass;
161 } 202 }
162 203
163 private OMV.Vector3 ComputeLinksetCenterOfMass() 204 // Routine used when rebuilding the body of the root of the linkset
205 // Destroy all the constraints have have been made to root.
206 // This is called when the root body is changing.
207 // Returns 'true' of something eas actually removed and would need restoring
208 // Called at taint-time!!
209 public bool RemoveBodyDependencies(BSPrim child)
164 { 210 {
165 OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; 211 bool ret = false;
166 float totalMass = m_linksetRoot.MassRaw;
167 212
168 lock (m_linksetActivityLock) 213 lock (m_linksetActivityLock)
169 { 214 {
170 foreach (BSPrim bp in m_children) 215 if (IsRoot(child))
171 { 216 {
172 com += bp.Position * bp.MassRaw; 217 // If the one with the dependency is root, must undo all children
173 totalMass += bp.MassRaw; 218 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
219 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
220 foreach (BSPhysObject bpo in m_taintChildren)
221 {
222 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
223 ret = true;
224 }
225 }
226 else
227 {
228 DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
229 child.LocalID,
230 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
231 child.LocalID, child.BSBody.ptr.ToString("X"));
232 // Remove the dependency on the body of this one
233 if (m_taintChildren.Contains(child))
234 {
235 PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
236 ret = true;
237 }
174 } 238 }
175 if (totalMass != 0f)
176 com /= totalMass;
177 } 239 }
178 240 return ret;
179 return com;
180 } 241 }
181 242
182 private OMV.Vector3 ComputeLinksetGeometricCenter() 243 // Routine used when rebuilding the body of the root of the linkset
244 // This is called after RemoveAllLinksToRoot() to restore all the constraints.
245 // This is called when the root body has been changed.
246 // Called at taint-time!!
247 public void RestoreBodyDependencies(BSPrim child)
183 { 248 {
184 OMV.Vector3 com = m_linksetRoot.Position;
185
186 lock (m_linksetActivityLock) 249 lock (m_linksetActivityLock)
187 { 250 {
188 foreach (BSPrim bp in m_children) 251 if (IsRoot(child))
189 { 252 {
190 com += bp.Position * bp.MassRaw; 253 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreChildrenForRoot,rID={1},numChild={2}",
254 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
255 foreach (BSPhysObject bpo in m_taintChildren)
256 {
257 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
258 }
259 }
260 else
261 {
262 DetailLog("{0},BSLinkset.RestoreBodyDependencies,restoreSingleChild,rID={1},rBody={2},cID={3},cBody={4}",
263 LinksetRoot.LocalID,
264 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
265 child.LocalID, child.BSBody.ptr.ToString("X"));
266 PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
191 } 267 }
192 com /= (m_children.Count + 1);
193 } 268 }
194
195 return com;
196 } 269 }
197 270
198 // When physical properties are changed the linkset needs to recalculate 271 // ================================================================
199 // its internal properties. 272 // Below this point is internal magic
200 public void Refresh(BSPrim requestor) 273
274 private float ComputeLinksetMass()
201 { 275 {
202 // If there are no children, there aren't any constraints to recompute 276 float mass;
203 if (!HasAnyChildren) 277 lock (m_linksetActivityLock)
204 return; 278 {
279 mass = LinksetRoot.MassRaw;
280 foreach (BSPhysObject bp in m_taintChildren)
281 {
282 mass += bp.MassRaw;
283 }
284 }
285 return mass;
286 }
205 287
206 // Only the root does the recomputation 288 private OMV.Vector3 ComputeLinksetCenterOfMass()
207 if (IsRoot(requestor)) 289 {
290 OMV.Vector3 com;
291 lock (m_linksetActivityLock)
208 { 292 {
209 PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() 293 com = LinksetRoot.Position * LinksetRoot.MassRaw;
294 float totalMass = LinksetRoot.MassRaw;
295
296 foreach (BSPhysObject bp in m_taintChildren)
210 { 297 {
211 RecomputeLinksetConstraintVariables(); 298 com += bp.Position * bp.MassRaw;
212 }); 299 totalMass += bp.MassRaw;
300 }
301 if (totalMass != 0f)
302 com /= totalMass;
213 } 303 }
304
305 return com;
214 } 306 }
215 307
216 // Call each of the constraints that make up this linkset and recompute the 308 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 { 309 {
223 float linksetMass = LinksetMass; 310 OMV.Vector3 com;
224 lock (m_linksetActivityLock) 311 lock (m_linksetActivityLock)
225 { 312 {
226 foreach (BSPrim child in m_children) 313 com = LinksetRoot.Position;
314
315 foreach (BSPhysObject bp in m_taintChildren)
227 { 316 {
228 BSConstraint constrain; 317 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 } 318 }
319 com /= (m_taintChildren.Count + 1);
245 } 320 }
246 return false; 321
322 return com;
247 } 323 }
248 324
249 // I am the root of a linkset and a new child is being added 325 // I am the root of a linkset and a new child is being added
250 // Called while LinkActivity is locked. 326 // Called while LinkActivity is locked.
251 private void AddChildToLinkset(BSPrim child) 327 private void AddChildToLinkset(BSPhysObject child)
252 { 328 {
253 if (!HasChild(child)) 329 if (!HasChild(child))
254 { 330 {
255 m_children.Add(child); 331 m_children.Add(child);
256 332
257 BSPrim rootx = LinksetRoot; // capture the root as of now 333 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
258 BSPrim childx = child; 334 BulletBody rootBodyx = LinksetRoot.BSBody;
259 m_physicsScene.TaintedObject("AddChildToLinkset", delegate() 335 BSPhysObject childx = child;
336 BulletBody childBodyx = child.BSBody;
337
338 DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
339 rootx.LocalID,
340 rootx.LocalID, rootBodyx.ptr.ToString("X"),
341 childx.LocalID, childBodyx.ptr.ToString("X"));
342
343 PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
260 { 344 {
261 // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); 345 DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
262 // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 346 // build the physical binding between me and the child
263 PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child 347 m_taintChildren.Add(childx);
348 PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
264 }); 349 });
265 } 350 }
266 return; 351 return;
@@ -270,30 +355,38 @@ public class BSLinkset
270 // This is not being called by the child so we have to make sure the child doesn't think 355 // 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. 356 // it's still connected to the linkset.
272 // Normal OpenSimulator operation will never do this because other SceneObjectPart information 357 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
273 // has to be updated also (like pointer to prim's parent). 358 // also has to be updated (like pointer to prim's parent).
274 private void RemoveChildFromOtherLinkset(BSPrim pchild) 359 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
275 { 360 {
276 pchild.Linkset = new BSLinkset(m_physicsScene, pchild); 361 pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
277 RemoveChildFromLinkset(pchild); 362 RemoveChildFromLinkset(pchild);
278 } 363 }
279 364
280 // I am the root of a linkset and one of my children is being removed. 365 // 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. 366 // Safe to call even if the child is not really in my linkset.
282 private void RemoveChildFromLinkset(BSPrim child) 367 private void RemoveChildFromLinkset(BSPhysObject child)
283 { 368 {
284 if (m_children.Remove(child)) 369 if (m_children.Remove(child))
285 { 370 {
286 BSPrim rootx = LinksetRoot; // capture the root as of now 371 BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
287 BSPrim childx = child; 372 BulletBody rootBodyx = LinksetRoot.BSBody;
288 m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() 373 BSPhysObject childx = child;
374 BulletBody childBodyx = child.BSBody;
375
376 DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
377 childx.LocalID,
378 rootx.LocalID, rootBodyx.ptr.ToString("X"),
379 childx.LocalID, childBodyx.ptr.ToString("X"));
380
381 PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
289 { 382 {
290 // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); 383 if (m_taintChildren.Contains(childx))
291 // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); 384 m_taintChildren.Remove(childx);
292 385
293 PhysicallyUnlinkAChildFromRoot(rootx, childx); 386 PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
387 RecomputeLinksetConstraintVariables();
294 }); 388 });
295 389
296 RecomputeLinksetConstraintVariables();
297 } 390 }
298 else 391 else
299 { 392 {
@@ -305,7 +398,8 @@ public class BSLinkset
305 398
306 // Create a constraint between me (root of linkset) and the passed prim (the child). 399 // Create a constraint between me (root of linkset) and the passed prim (the child).
307 // Called at taint time! 400 // Called at taint time!
308 private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) 401 private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
402 BSPhysObject childPrim, BulletBody childBody)
309 { 403 {
310 // Zero motion for children so they don't interpolate 404 // Zero motion for children so they don't interpolate
311 childPrim.ZeroMotion(); 405 childPrim.ZeroMotion();
@@ -317,21 +411,38 @@ public class BSLinkset
317 // real world coordinate of midpoint between the two objects 411 // real world coordinate of midpoint between the two objects
318 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); 412 OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
319 413
414 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
415 rootPrim.LocalID,
416 rootPrim.LocalID, rootBody.ptr.ToString("X"),
417 childPrim.LocalID, childBody.ptr.ToString("X"),
418 rootPrim.Position, childPrim.Position, midPoint);
419
320 // create a constraint that allows no freedom of movement between the two objects 420 // create a constraint that allows no freedom of movement between the two objects
321 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 421 // 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); 422
323 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", 423 // There is great subtlty in these paramters. Notice the check for a ptr of zero.
324 rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); 424 // We pass the BulletBody structure into the taint in order to capture the pointer
425 // of the body at the time of constraint creation. This doesn't work for the very first
426 // construction because there is no body yet. The body
427 // is constructed later at taint time. Thus we use the body address at time of the
428 // taint creation but, if it is zero, use what's in the prim at the moment.
429 // There is a possible race condition since shape can change without a taint call
430 // (like changing to a mesh that is already constructed). The fix for that would be
431 // to only change BSShape at taint time thus syncronizing these operations at
432 // the cost of efficiency and lag.
325 BS6DofConstraint constrain = new BS6DofConstraint( 433 BS6DofConstraint constrain = new BS6DofConstraint(
326 m_physicsScene.World, rootPrim.Body, childPrim.Body, 434 PhysicsScene.World,
435 rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
436 childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
327 midPoint, 437 midPoint,
328 true, 438 true,
329 true 439 true
330 ); 440 );
331 /* NOTE: attempt to build constraint with full frame computation, etc. 441
332 * Using the midpoint is easier since it lets the Bullet code use the transforms 442 /* NOTE: below is an attempt to build constraint with full frame computation, etc.
443 * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
333 * of the objects. 444 * of the objects.
334 * Code left here as an example. 445 * Code left as a warning to future programmers.
335 // ================================================================================== 446 // ==================================================================================
336 // relative position normalized to the root prim 447 // relative position normalized to the root prim
337 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); 448 OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
@@ -343,7 +454,6 @@ public class BSLinkset
343 454
344 // create a constraint that allows no freedom of movement between the two objects 455 // create a constraint that allows no freedom of movement between the two objects
345 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 456 // 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); 457 DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
348 BS6DofConstraint constrain = new BS6DofConstraint( 458 BS6DofConstraint constrain = new BS6DofConstraint(
349 PhysicsScene.World, rootPrim.Body, childPrim.Body, 459 PhysicsScene.World, rootPrim.Body, childPrim.Body,
@@ -362,7 +472,7 @@ public class BSLinkset
362 // ================================================================================== 472 // ==================================================================================
363 */ 473 */
364 474
365 m_physicsScene.Constraints.AddConstraint(constrain); 475 PhysicsScene.Constraints.AddConstraint(constrain);
366 476
367 // zero linear and angular limits makes the objects unable to move in relation to each other 477 // 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); 478 constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
@@ -374,46 +484,88 @@ public class BSLinkset
374 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 484 PhysicsScene.Params.linkConstraintTransMotorMaxVel,
375 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 485 PhysicsScene.Params.linkConstraintTransMotorMaxForce);
376 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 486 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
487 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
488 {
489 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
490 }
377 491
378 RecomputeLinksetConstraintVariables(); 492 RecomputeLinksetConstraintVariables();
379 } 493 }
380 494
381 // Remove linkage between myself and a particular child 495 // Remove linkage between myself and a particular child
496 // The root and child bodies are passed in because we need to remove the constraint between
497 // the bodies that were at unlink time.
382 // Called at taint time! 498 // Called at taint time!
383 private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) 499 private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
500 BSPhysObject childPrim, BulletBody childBody)
384 { 501 {
385 // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 502 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
386 // LogHeader, rootPrim.LocalID, childPrim.LocalID); 503 rootPrim.LocalID,
387 DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); 504 rootPrim.LocalID, rootBody.ptr.ToString("X"),
505 childPrim.LocalID, childBody.ptr.ToString("X"));
388 506
389 // Find the constraint for this link and get rid of it from the overall collection and from my list 507 // 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); 508 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
391 509
392 // Make the child refresh its location 510 // Make the child refresh its location
393 BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); 511 BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
394 } 512 }
395 513
396 // Remove linkage between myself and any possible children I might have 514 /*
515 // Remove linkage between myself and any possible children I might have.
397 // Called at taint time! 516 // Called at taint time!
398 private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) 517 private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
399 { 518 {
400 // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
401 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); 519 DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
402 520
403 m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); 521 PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
404 } 522 }
523 */
405 524
406 // Invoke the detailed logger and output something if it's enabled. 525 // Call each of the constraints that make up this linkset and recompute the
407 private void DebugLog(string msg, params Object[] args) 526 // various transforms and variables. Used when objects are added or removed
527 // from a linkset to make sure the constraints know about the new mass and
528 // geometry.
529 // Must only be called at taint time!!
530 private void RecomputeLinksetConstraintVariables()
408 { 531 {
409 if (m_physicsScene.ShouldDebugLog) 532 float linksetMass = LinksetMass;
410 m_physicsScene.Logger.DebugFormat(msg, args); 533 foreach (BSPhysObject child in m_taintChildren)
534 {
535 BSConstraint constrain;
536 if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain))
537 {
538 // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}",
539 // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID);
540 constrain.RecomputeConstraintVariables(linksetMass);
541 }
542 else
543 {
544 // Non-fatal error that happens when children are being added to the linkset but
545 // their constraints have not been created yet.
546 break;
547 }
548 }
549
550 // If the whole linkset is not here, doesn't make sense to recompute linkset wide values
551 if (m_children.Count == m_taintChildren.Count)
552 {
553 // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
554 OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
555 BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
556 foreach (BSPhysObject child in m_taintChildren)
557 {
558 BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
559 }
560 }
561 return;
411 } 562 }
412 563
564
413 // Invoke the detailed logger and output something if it's enabled. 565 // Invoke the detailed logger and output something if it's enabled.
414 private void DetailLog(string msg, params Object[] args) 566 private void DetailLog(string msg, params Object[] args)
415 { 567 {
416 m_physicsScene.PhysicsLogging.Write(msg, args); 568 PhysicsScene.PhysicsLogging.Write(msg, args);
417 } 569 }
418 570
419} 571}