diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 422 |
1 files changed, 286 insertions, 136 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 087b9bb..3e82642 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 | { |
35 | public class BSLinkset | 35 | 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 | BSPhysObject childx = child; |
259 | m_physicsScene.TaintedObject("AddChildToLinkset", delegate() | 335 | |
336 | DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
337 | rootx.LocalID, | ||
338 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | ||
339 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | ||
340 | |||
341 | PhysicsScene.TaintedObject("AddChildToLinkset", delegate() | ||
260 | { | 342 | { |
261 | // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); | 343 | DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); |
262 | // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | 344 | // build the physical binding between me and the child |
263 | PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child | 345 | m_taintChildren.Add(childx); |
346 | |||
347 | // Since this is taint-time, the body and shape could have changed for the child | ||
348 | PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody); | ||
264 | }); | 349 | }); |
265 | } | 350 | } |
266 | return; | 351 | return; |
@@ -270,30 +355,36 @@ 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 | BSPhysObject childx = child; |
288 | m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | 373 | |
374 | DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
375 | childx.LocalID, | ||
376 | rootx.LocalID, rootx.BSBody.ptr.ToString("X"), | ||
377 | childx.LocalID, childx.BSBody.ptr.ToString("X")); | ||
378 | |||
379 | PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | ||
289 | { | 380 | { |
290 | // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); | 381 | if (m_taintChildren.Contains(childx)) |
291 | // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | 382 | m_taintChildren.Remove(childx); |
292 | 383 | ||
293 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 384 | PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody); |
385 | RecomputeLinksetConstraintVariables(); | ||
294 | }); | 386 | }); |
295 | 387 | ||
296 | RecomputeLinksetConstraintVariables(); | ||
297 | } | 388 | } |
298 | else | 389 | else |
299 | { | 390 | { |
@@ -305,7 +396,8 @@ public class BSLinkset | |||
305 | 396 | ||
306 | // Create a constraint between me (root of linkset) and the passed prim (the child). | 397 | // Create a constraint between me (root of linkset) and the passed prim (the child). |
307 | // Called at taint time! | 398 | // Called at taint time! |
308 | private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim) | 399 | private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody, |
400 | BSPhysObject childPrim, BulletBody childBody) | ||
309 | { | 401 | { |
310 | // Zero motion for children so they don't interpolate | 402 | // Zero motion for children so they don't interpolate |
311 | childPrim.ZeroMotion(); | 403 | childPrim.ZeroMotion(); |
@@ -317,21 +409,38 @@ public class BSLinkset | |||
317 | // real world coordinate of midpoint between the two objects | 409 | // real world coordinate of midpoint between the two objects |
318 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | 410 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); |
319 | 411 | ||
412 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | ||
413 | rootPrim.LocalID, | ||
414 | rootPrim.LocalID, rootBody.ptr.ToString("X"), | ||
415 | childPrim.LocalID, childBody.ptr.ToString("X"), | ||
416 | rootPrim.Position, childPrim.Position, midPoint); | ||
417 | |||
320 | // create a constraint that allows no freedom of movement between the two objects | 418 | // create a constraint that allows no freedom of movement between the two objects |
321 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 419 | // 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); | 420 | |
323 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", | 421 | // 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); | 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. | ||
325 | BS6DofConstraint constrain = new BS6DofConstraint( | 431 | BS6DofConstraint constrain = new BS6DofConstraint( |
326 | m_physicsScene.World, rootPrim.Body, childPrim.Body, | 432 | PhysicsScene.World, |
433 | rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody, | ||
434 | childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody, | ||
327 | midPoint, | 435 | midPoint, |
328 | true, | 436 | true, |
329 | true | 437 | true |
330 | ); | 438 | ); |
331 | /* NOTE: attempt to build constraint with full frame computation, etc. | 439 | |
332 | * Using the midpoint is easier since it lets the Bullet code use the transforms | 440 | /* 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 | ||
333 | * of the objects. | 442 | * of the objects. |
334 | * Code left here as an example. | 443 | * Code left as a warning to future programmers. |
335 | // ================================================================================== | 444 | // ================================================================================== |
336 | // relative position normalized to the root prim | 445 | // relative position normalized to the root prim |
337 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | 446 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); |
@@ -343,7 +452,6 @@ public class BSLinkset | |||
343 | 452 | ||
344 | // create a constraint that allows no freedom of movement between the two objects | 453 | // create a constraint that allows no freedom of movement between the two objects |
345 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 454 | // 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); | 455 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
348 | BS6DofConstraint constrain = new BS6DofConstraint( | 456 | BS6DofConstraint constrain = new BS6DofConstraint( |
349 | PhysicsScene.World, rootPrim.Body, childPrim.Body, | 457 | PhysicsScene.World, rootPrim.Body, childPrim.Body, |
@@ -362,7 +470,7 @@ public class BSLinkset | |||
362 | // ================================================================================== | 470 | // ================================================================================== |
363 | */ | 471 | */ |
364 | 472 | ||
365 | m_physicsScene.Constraints.AddConstraint(constrain); | 473 | PhysicsScene.Constraints.AddConstraint(constrain); |
366 | 474 | ||
367 | // zero linear and angular limits makes the objects unable to move in relation to each other | 475 | // 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); | 476 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
@@ -374,46 +482,88 @@ public class BSLinkset | |||
374 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, | 482 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, |
375 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); | 483 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); |
376 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); | 484 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); |
485 | if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) | ||
486 | { | ||
487 | constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); | ||
488 | } | ||
377 | 489 | ||
378 | RecomputeLinksetConstraintVariables(); | 490 | RecomputeLinksetConstraintVariables(); |
379 | } | 491 | } |
380 | 492 | ||
381 | // Remove linkage between myself and a particular child | 493 | // 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 | ||
495 | // the bodies that were at unlink time. | ||
382 | // Called at taint time! | 496 | // Called at taint time! |
383 | private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim) | 497 | private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody, |
498 | BSPhysObject childPrim, BulletBody childBody) | ||
384 | { | 499 | { |
385 | // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", | 500 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", |
386 | // LogHeader, rootPrim.LocalID, childPrim.LocalID); | 501 | rootPrim.LocalID, |
387 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | 502 | rootPrim.LocalID, rootBody.ptr.ToString("X"), |
503 | childPrim.LocalID, childBody.ptr.ToString("X")); | ||
388 | 504 | ||
389 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 505 | // 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); | 506 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody); |
391 | 507 | ||
392 | // Make the child refresh its location | 508 | // Make the child refresh its location |
393 | BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); | 509 | BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); |
394 | } | 510 | } |
395 | 511 | ||
396 | // Remove linkage between myself and any possible children I might have | 512 | /* |
513 | // Remove linkage between myself and any possible children I might have. | ||
397 | // Called at taint time! | 514 | // Called at taint time! |
398 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim) | 515 | private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) |
399 | { | 516 | { |
400 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | ||
401 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 517 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
402 | 518 | ||
403 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); | 519 | PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); |
404 | } | 520 | } |
521 | */ | ||
405 | 522 | ||
406 | // Invoke the detailed logger and output something if it's enabled. | 523 | // Call each of the constraints that make up this linkset and recompute the |
407 | private void DebugLog(string msg, params Object[] args) | 524 | // various transforms and variables. Used when objects are added or removed |
525 | // from a linkset to make sure the constraints know about the new mass and | ||
526 | // geometry. | ||
527 | // Must only be called at taint time!! | ||
528 | private void RecomputeLinksetConstraintVariables() | ||
408 | { | 529 | { |
409 | if (m_physicsScene.ShouldDebugLog) | 530 | float linksetMass = LinksetMass; |
410 | m_physicsScene.Logger.DebugFormat(msg, args); | 531 | foreach (BSPhysObject child in m_taintChildren) |
532 | { | ||
533 | BSConstraint constrain; | ||
534 | if (PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.BSBody, child.BSBody, out constrain)) | ||
535 | { | ||
536 | // DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,taint,child={1},mass={2},A={3},B={4}", | ||
537 | // LinksetRoot.LocalID, child.LocalID, linksetMass, constrain.Body1.ID, constrain.Body2.ID); | ||
538 | constrain.RecomputeConstraintVariables(linksetMass); | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 | // Non-fatal error that happens when children are being added to the linkset but | ||
543 | // their constraints have not been created yet. | ||
544 | break; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | // If the whole linkset is not here, doesn't make sense to recompute linkset wide values | ||
549 | if (m_children.Count == m_taintChildren.Count) | ||
550 | { | ||
551 | // 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(); | ||
553 | BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | ||
554 | foreach (BSPhysObject child in m_taintChildren) | ||
555 | { | ||
556 | BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity); | ||
557 | } | ||
558 | } | ||
559 | return; | ||
411 | } | 560 | } |
412 | 561 | ||
562 | |||
413 | // Invoke the detailed logger and output something if it's enabled. | 563 | // Invoke the detailed logger and output something if it's enabled. |
414 | private void DetailLog(string msg, params Object[] args) | 564 | private void DetailLog(string msg, params Object[] args) |
415 | { | 565 | { |
416 | m_physicsScene.PhysicsLogging.Write(msg, args); | 566 | PhysicsScene.PhysicsLogging.Write(msg, args); |
417 | } | 567 | } |
418 | 568 | ||
419 | } | 569 | } |