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