diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 185 |
1 files changed, 95 insertions, 90 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 3e82642..43b1262 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -52,8 +52,8 @@ public class BSLinkset | |||
52 | // the physical 'taint' children separately. | 52 | // the physical 'taint' children separately. |
53 | // After taint processing and before the simulation step, these | 53 | // After taint processing and before the simulation step, these |
54 | // two lists must be the same. | 54 | // two lists must be the same. |
55 | private List<BSPhysObject> m_children; | 55 | private HashSet<BSPhysObject> m_children; |
56 | private List<BSPhysObject> m_taintChildren; | 56 | private HashSet<BSPhysObject> m_taintChildren; |
57 | 57 | ||
58 | // We lock the diddling of linkset classes to prevent any badness. | 58 | // We lock the diddling of linkset classes to prevent any badness. |
59 | // This locks the modification of the instances of this class. Changes | 59 | // This locks the modification of the instances of this class. Changes |
@@ -90,8 +90,8 @@ public class BSLinkset | |||
90 | m_nextLinksetID = 1; | 90 | m_nextLinksetID = 1; |
91 | PhysicsScene = scene; | 91 | PhysicsScene = scene; |
92 | LinksetRoot = parent; | 92 | LinksetRoot = parent; |
93 | m_children = new List<BSPhysObject>(); | 93 | m_children = new HashSet<BSPhysObject>(); |
94 | m_taintChildren = new List<BSPhysObject>(); | 94 | m_taintChildren = new HashSet<BSPhysObject>(); |
95 | m_mass = parent.MassRaw; | 95 | m_mass = parent.MassRaw; |
96 | } | 96 | } |
97 | 97 | ||
@@ -160,6 +160,28 @@ public class BSLinkset | |||
160 | return ret; | 160 | return ret; |
161 | } | 161 | } |
162 | 162 | ||
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 | |||
163 | // The object is going dynamic (physical). Do any setup necessary | 185 | // The object is going dynamic (physical). Do any setup necessary |
164 | // for a dynamic linkset. | 186 | // for a dynamic linkset. |
165 | // Only the state of the passed object can be modified. The rest of the linkset | 187 | // Only the state of the passed object can be modified. The rest of the linkset |
@@ -182,22 +204,19 @@ public class BSLinkset | |||
182 | return false; | 204 | return false; |
183 | } | 205 | } |
184 | 206 | ||
185 | // When physical properties are changed the linkset needs to recalculate | 207 | // If the software is handling the movement of all the objects in a linkset |
186 | // its internal properties. | 208 | // (like if one doesn't use constraints for static linksets), this is called |
187 | // Called at runtime. | 209 | // when an update for the root of the linkset is received. |
188 | public void Refresh(BSPhysObject requestor) | 210 | // Called at taint-time!! |
211 | public void UpdateProperties(BSPhysObject physObject) | ||
189 | { | 212 | { |
190 | // If there are no children, there can't be any constraints to recompute | 213 | // The root local properties have been updated. Apply to the children if appropriate. |
191 | if (!HasAnyChildren) | 214 | if (IsRoot(physObject) && HasAnyChildren) |
192 | return; | ||
193 | |||
194 | // Only the root does the recomputation | ||
195 | if (IsRoot(requestor)) | ||
196 | { | 215 | { |
197 | PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate() | 216 | if (!physObject.IsPhysical) |
198 | { | 217 | { |
199 | RecomputeLinksetConstraintVariables(); | 218 | // TODO: implement software linkset update for static object linksets |
200 | }); | 219 | } |
201 | } | 220 | } |
202 | } | 221 | } |
203 | 222 | ||
@@ -215,13 +234,10 @@ public class BSLinkset | |||
215 | if (IsRoot(child)) | 234 | if (IsRoot(child)) |
216 | { | 235 | { |
217 | // If the one with the dependency is root, must undo all children | 236 | // If the one with the dependency is root, must undo all children |
218 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}", | 237 | DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", |
219 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); | 238 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X")); |
220 | foreach (BSPhysObject bpo in m_taintChildren) | 239 | |
221 | { | 240 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
222 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); | ||
223 | ret = true; | ||
224 | } | ||
225 | } | 241 | } |
226 | else | 242 | else |
227 | { | 243 | { |
@@ -229,20 +245,16 @@ public class BSLinkset | |||
229 | child.LocalID, | 245 | child.LocalID, |
230 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | 246 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), |
231 | child.LocalID, child.BSBody.ptr.ToString("X")); | 247 | child.LocalID, child.BSBody.ptr.ToString("X")); |
232 | // Remove the dependency on the body of this one | 248 | // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child); |
233 | if (m_taintChildren.Contains(child)) | 249 | // Despite the function name, this removes any link to the specified object. |
234 | { | 250 | ret = PhysicallyUnlinkAllChildrenFromRoot(child); |
235 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); | ||
236 | ret = true; | ||
237 | } | ||
238 | } | 251 | } |
239 | } | 252 | } |
240 | return ret; | 253 | return ret; |
241 | } | 254 | } |
242 | 255 | ||
243 | // Routine used when rebuilding the body of the root of the linkset | 256 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
244 | // This is called after RemoveAllLinksToRoot() to restore all the constraints. | 257 | // this routine will restore the removed constraints. |
245 | // This is called when the root body has been changed. | ||
246 | // Called at taint-time!! | 258 | // Called at taint-time!! |
247 | public void RestoreBodyDependencies(BSPrim child) | 259 | public void RestoreBodyDependencies(BSPrim child) |
248 | { | 260 | { |
@@ -254,7 +266,7 @@ public class BSLinkset | |||
254 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); | 266 | child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count); |
255 | foreach (BSPhysObject bpo in m_taintChildren) | 267 | foreach (BSPhysObject bpo in m_taintChildren) |
256 | { | 268 | { |
257 | PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody); | 269 | PhysicallyLinkAChildToRoot(LinksetRoot, bpo); |
258 | } | 270 | } |
259 | } | 271 | } |
260 | else | 272 | else |
@@ -263,7 +275,7 @@ public class BSLinkset | |||
263 | LinksetRoot.LocalID, | 275 | LinksetRoot.LocalID, |
264 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), | 276 | LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"), |
265 | child.LocalID, child.BSBody.ptr.ToString("X")); | 277 | child.LocalID, child.BSBody.ptr.ToString("X")); |
266 | PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody); | 278 | PhysicallyLinkAChildToRoot(LinksetRoot, child); |
267 | } | 279 | } |
268 | } | 280 | } |
269 | } | 281 | } |
@@ -330,22 +342,22 @@ public class BSLinkset | |||
330 | { | 342 | { |
331 | m_children.Add(child); | 343 | m_children.Add(child); |
332 | 344 | ||
333 | BSPhysObject rootx = LinksetRoot; // capture the root and body as of now | 345 | BSPhysObject rootx = LinksetRoot; // capture the root as of now |
334 | BSPhysObject childx = child; | 346 | BSPhysObject childx = child; |
335 | 347 | ||
336 | DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 348 | DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
337 | rootx.LocalID, | ||
338 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | ||
339 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | ||
340 | 349 | ||
341 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() | 350 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() |
342 | { | 351 | { |
343 | DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); | 352 | DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}", |
344 | // build the physical binding between me and the child | 353 | rootx.LocalID, |
345 | m_taintChildren.Add(childx); | 354 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), |
346 | 355 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | |
347 | // Since this is taint-time, the body and shape could have changed for the child | 356 | // Since this is taint-time, the body and shape could have changed for the child |
348 | PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); | 357 | rootx.ForcePosition = rootx.Position; // DEBUG |
358 | childx.ForcePosition = childx.Position; // DEBUG | ||
359 | PhysicallyLinkAChildToRoot(rootx, childx); | ||
360 | m_taintChildren.Add(child); | ||
349 | }); | 361 | }); |
350 | } | 362 | } |
351 | return; | 363 | return; |
@@ -378,10 +390,8 @@ public class BSLinkset | |||
378 | 390 | ||
379 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | 391 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() |
380 | { | 392 | { |
381 | if (m_taintChildren.Contains(childx)) | 393 | m_taintChildren.Remove(child); |
382 | m_taintChildren.Remove(childx); | 394 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
383 | |||
384 | PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody); | ||
385 | RecomputeLinksetConstraintVariables(); | 395 | RecomputeLinksetConstraintVariables(); |
386 | }); | 396 | }); |
387 | 397 | ||
@@ -396,8 +406,7 @@ public class BSLinkset | |||
396 | 406 | ||
397 | // 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). |
398 | // Called at taint time! | 408 | // Called at taint time! |
399 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, | 409 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
400 | BSPhysObject childPrim, BulletBody childBody) | ||
401 | { | 410 | { |
402 | // Zero motion for children so they don't interpolate | 411 | // Zero motion for children so they don't interpolate |
403 | childPrim.ZeroMotion(); | 412 | childPrim.ZeroMotion(); |
@@ -409,33 +418,17 @@ public class BSLinkset | |||
409 | // real world coordinate of midpoint between the two objects | 418 | // real world coordinate of midpoint between the two objects |
410 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | 419 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); |
411 | 420 | ||
412 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 421 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", |
413 | rootPrim.LocalID, | 422 | rootPrim.LocalID, |
414 | rootPrim.LocalID, rootBody.ptr.ToString("X"), | 423 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), |
415 | childPrim.LocalID, childBody.ptr.ToString("X"), | 424 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"), |
416 | rootPrim.Position, childPrim.Position, midPoint); | 425 | rootPrim.Position, childPrim.Position, midPoint); |
417 | 426 | ||
418 | // 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 |
419 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 428 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
420 | 429 | ||
421 | // There is great subtlty in these paramters. Notice the check for a ptr of zero. | ||
422 | // We pass the BulletBody structure into the taint in order to capture the pointer | ||
423 | // of the body at the time of constraint creation. This doesn't work for the very first | ||
424 | // construction because there is no body yet. The body | ||
425 | // is constructed later at taint time. Thus we use the body address at time of the | ||
426 | // taint creation but, if it is zero, use what's in the prim at the moment. | ||
427 | // There is a possible race condition since shape can change without a taint call | ||
428 | // (like changing to a mesh that is already constructed). The fix for that would be | ||
429 | // to only change BSShape at taint time thus syncronizing these operations at | ||
430 | // the cost of efficiency and lag. | ||
431 | BS6DofConstraint constrain = new BS6DofConstraint( | 430 | BS6DofConstraint constrain = new BS6DofConstraint( |
432 | PhysicsScene.World, | 431 | PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true ); |
433 | rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody, | ||
434 | childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody, | ||
435 | midPoint, | ||
436 | true, | ||
437 | true | ||
438 | ); | ||
439 | 432 | ||
440 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 433 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
441 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | 434 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms |
@@ -452,7 +445,7 @@ public class BSLinkset | |||
452 | 445 | ||
453 | // 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 |
454 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 447 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
455 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | 448 | DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
456 | BS6DofConstraint constrain = new BS6DofConstraint( | 449 | BS6DofConstraint constrain = new BS6DofConstraint( |
457 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | 450 | PhysicsScene.World, rootPrim.Body, childPrim.Body, |
458 | OMV.Vector3.Zero, | 451 | OMV.Vector3.Zero, |
@@ -486,39 +479,44 @@ public class BSLinkset | |||
486 | { | 479 | { |
487 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | 480 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); |
488 | } | 481 | } |
489 | |||
490 | RecomputeLinksetConstraintVariables(); | ||
491 | } | 482 | } |
492 | 483 | ||
493 | // Remove linkage between myself and a particular child | 484 | // Remove linkage between myself and a particular child |
494 | // The root and child bodies are passed in because we need to remove the constraint between | 485 | // The root and child bodies are passed in because we need to remove the constraint between |
495 | // the bodies that were at unlink time. | 486 | // the bodies that were at unlink time. |
496 | // Called at taint time! | 487 | // Called at taint time! |
497 | private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, | 488 | private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) |
498 | BSPhysObject childPrim, BulletBody childBody) | ||
499 | { | 489 | { |
500 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | 490 | bool ret = false; |
491 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
501 | rootPrim.LocalID, | 492 | rootPrim.LocalID, |
502 | rootPrim.LocalID, rootBody.ptr.ToString("X"), | 493 | rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"), |
503 | childPrim.LocalID, childBody.ptr.ToString("X")); | 494 | childPrim.LocalID, childPrim.BSBody.ptr.ToString("X")); |
504 | 495 | ||
505 | // 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 |
506 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); | 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 | } | ||
507 | 503 | ||
508 | // Make the child refresh its location | 504 | return ret; |
509 | BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); | ||
510 | } | 505 | } |
511 | 506 | ||
512 | /* | ||
513 | // Remove linkage between myself and any possible children I might have. | 507 | // Remove linkage between myself and any possible children I might have. |
514 | // Called at taint time! | 508 | // Called at taint time! |
515 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) | 509 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) |
516 | { | 510 | { |
517 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 511 | DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
512 | bool ret = false; | ||
518 | 513 | ||
519 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); | 514 | if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody)) |
515 | { | ||
516 | ret = true; | ||
517 | } | ||
518 | return ret; | ||
520 | } | 519 | } |
521 | */ | ||
522 | 520 | ||
523 | // Call each of the constraints that make up this linkset and recompute the | 521 | // Call each of the constraints that make up this linkset and recompute the |
524 | // various transforms and variables. Used when objects are added or removed | 522 | // various transforms and variables. Used when objects are added or removed |
@@ -550,11 +548,17 @@ public class BSLinkset | |||
550 | { | 548 | { |
551 | // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass | 549 | // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass |
552 | OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); | 550 | OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass(); |
553 | BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | 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")); | ||
554 | foreach (BSPhysObject child in m_taintChildren) | 555 | foreach (BSPhysObject child in m_taintChildren) |
555 | { | 556 | { |
556 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | 557 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, |
558 | centerOfMass, OMV.Quaternion.Identity); | ||
557 | } | 559 | } |
560 | |||
561 | // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr); // DEBUG DEBUG DEBUG | ||
558 | } | 562 | } |
559 | return; | 563 | return; |
560 | } | 564 | } |
@@ -563,7 +567,8 @@ public class BSLinkset | |||
563 | // Invoke the detailed logger and output something if it's enabled. | 567 | // Invoke the detailed logger and output something if it's enabled. |
564 | private void DetailLog(string msg, params Object[] args) | 568 | private void DetailLog(string msg, params Object[] args) |
565 | { | 569 | { |
566 | PhysicsScene.PhysicsLogging.Write(msg, args); | 570 | if (PhysicsScene.PhysicsLogging.Enabled) |
571 | PhysicsScene.DetailLog(msg, args); | ||
567 | } | 572 | } |
568 | 573 | ||
569 | } | 574 | } |