diff options
author | Robert Adams | 2012-08-15 11:36:21 -0700 |
---|---|---|
committer | Robert Adams | 2012-08-15 12:08:17 -0700 |
commit | 9efe7bf7ba741b0d61ef71c09b5848c424e3c258 (patch) | |
tree | e0222568715cfffb32c619520c1dc4e4c393a05a /OpenSim/Region/Physics/BulletSPlugin | |
parent | BulletSim: clean up detail logging by adding many more debug log statements a... (diff) | |
download | opensim-SC-9efe7bf7ba741b0d61ef71c09b5848c424e3c258.zip opensim-SC-9efe7bf7ba741b0d61ef71c09b5848c424e3c258.tar.gz opensim-SC-9efe7bf7ba741b0d61ef71c09b5848c424e3c258.tar.bz2 opensim-SC-9efe7bf7ba741b0d61ef71c09b5848c424e3c258.tar.xz |
BulletSim: add locking to constraintCollection and rename some of the public method variables to reduce confusion between a physics scene and the real scene.
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | 94 | ||||
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 250 |
2 files changed, 197 insertions, 147 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs index 862b744..22ea367 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs | |||
@@ -56,21 +56,25 @@ public class BSConstraintCollection : IDisposable | |||
56 | 56 | ||
57 | public void Clear() | 57 | public void Clear() |
58 | { | 58 | { |
59 | foreach (BSConstraint cons in m_constraints) | 59 | lock (m_constraints) |
60 | { | 60 | { |
61 | cons.Dispose(); | 61 | foreach (BSConstraint cons in m_constraints) |
62 | { | ||
63 | cons.Dispose(); | ||
64 | } | ||
65 | m_constraints.Clear(); | ||
62 | } | 66 | } |
63 | m_constraints.Clear(); | ||
64 | } | 67 | } |
65 | 68 | ||
66 | public bool AddConstraint(BSConstraint cons) | 69 | public bool AddConstraint(BSConstraint cons) |
67 | { | 70 | { |
68 | // There is only one constraint between any bodies. Remove any old just to make sure. | 71 | lock (m_constraints) |
69 | RemoveAndDestroyConstraint(cons.Body1, cons.Body2); | 72 | { |
70 | 73 | // There is only one constraint between any bodies. Remove any old just to make sure. | |
71 | m_world.scene.DetailLog("{0},BSConstraintCollection.AddConstraint,call,body1={1},body2={2}", BSScene.DetailLogZero, cons.Body1.ID, cons.Body2.ID); | 74 | RemoveAndDestroyConstraint(cons.Body1, cons.Body2); |
72 | 75 | ||
73 | m_constraints.Add(cons); | 76 | m_constraints.Add(cons); |
77 | } | ||
74 | 78 | ||
75 | return true; | 79 | return true; |
76 | } | 80 | } |
@@ -84,16 +88,19 @@ public class BSConstraintCollection : IDisposable | |||
84 | 88 | ||
85 | uint lookingID1 = body1.ID; | 89 | uint lookingID1 = body1.ID; |
86 | uint lookingID2 = body2.ID; | 90 | uint lookingID2 = body2.ID; |
87 | ForEachConstraint(delegate(BSConstraint constrain) | 91 | lock (m_constraints) |
88 | { | 92 | { |
89 | if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) | 93 | foreach (BSConstraint constrain in m_constraints) |
90 | || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) | ||
91 | { | 94 | { |
92 | foundConstraint = constrain; | 95 | if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) |
93 | found = true; | 96 | || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) |
97 | { | ||
98 | foundConstraint = constrain; | ||
99 | found = true; | ||
100 | break; | ||
101 | } | ||
94 | } | 102 | } |
95 | return found; | 103 | } |
96 | }); | ||
97 | returnConstraint = foundConstraint; | 104 | returnConstraint = foundConstraint; |
98 | return found; | 105 | return found; |
99 | } | 106 | } |
@@ -103,17 +110,16 @@ public class BSConstraintCollection : IDisposable | |||
103 | // Return 'true' if a constraint was found and destroyed. | 110 | // Return 'true' if a constraint was found and destroyed. |
104 | public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) | 111 | public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) |
105 | { | 112 | { |
106 | // return BulletSimAPI.RemoveConstraint(m_world.ID, obj1.ID, obj2.ID); | ||
107 | |||
108 | bool ret = false; | 113 | bool ret = false; |
109 | BSConstraint constrain; | 114 | lock (m_constraints) |
110 | |||
111 | if (this.TryGetConstraint(body1, body2, out constrain)) | ||
112 | { | 115 | { |
113 | m_world.scene.DetailLog("{0},BSConstraintCollection.RemoveAndDestroyConstraint,taint,body1={1},body2={2}", BSScene.DetailLogZero, body1.ID, body2.ID); | 116 | BSConstraint constrain; |
114 | // remove the constraint from our collection | 117 | if (this.TryGetConstraint(body1, body2, out constrain)) |
115 | RemoveAndDestroyConstraint(constrain); | 118 | { |
116 | ret = true; | 119 | // remove the constraint from our collection |
120 | RemoveAndDestroyConstraint(constrain); | ||
121 | ret = true; | ||
122 | } | ||
117 | } | 123 | } |
118 | 124 | ||
119 | return ret; | 125 | return ret; |
@@ -122,8 +128,11 @@ public class BSConstraintCollection : IDisposable | |||
122 | // The constraint MUST exist in the collection | 128 | // The constraint MUST exist in the collection |
123 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) | 129 | public bool RemoveAndDestroyConstraint(BSConstraint constrain) |
124 | { | 130 | { |
125 | // remove the constraint from our collection | 131 | lock (m_constraints) |
126 | m_constraints.Remove(constrain); | 132 | { |
133 | // remove the constraint from our collection | ||
134 | m_constraints.Remove(constrain); | ||
135 | } | ||
127 | // tell the engine that all its structures need to be freed | 136 | // tell the engine that all its structures need to be freed |
128 | constrain.Dispose(); | 137 | constrain.Dispose(); |
129 | // we destroyed something | 138 | // we destroyed something |
@@ -138,16 +147,15 @@ public class BSConstraintCollection : IDisposable | |||
138 | 147 | ||
139 | List<BSConstraint> toRemove = new List<BSConstraint>(); | 148 | List<BSConstraint> toRemove = new List<BSConstraint>(); |
140 | uint lookingID = body1.ID; | 149 | uint lookingID = body1.ID; |
141 | ForEachConstraint(delegate(BSConstraint constrain) | 150 | lock (m_constraints) |
142 | { | 151 | { |
143 | if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) | 152 | foreach (BSConstraint constrain in m_constraints) |
144 | { | 153 | { |
145 | toRemove.Add(constrain); | 154 | if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) |
155 | { | ||
156 | toRemove.Add(constrain); | ||
157 | } | ||
146 | } | 158 | } |
147 | return false; | ||
148 | }); | ||
149 | lock (m_constraints) | ||
150 | { | ||
151 | foreach (BSConstraint constrain in toRemove) | 159 | foreach (BSConstraint constrain in toRemove) |
152 | { | 160 | { |
153 | m_constraints.Remove(constrain); | 161 | m_constraints.Remove(constrain); |
@@ -159,28 +167,16 @@ public class BSConstraintCollection : IDisposable | |||
159 | 167 | ||
160 | public bool RecalculateAllConstraints() | 168 | public bool RecalculateAllConstraints() |
161 | { | 169 | { |
162 | ForEachConstraint(delegate(BSConstraint constrain) | 170 | bool ret = false; |
163 | { | ||
164 | constrain.CalculateTransforms(); | ||
165 | return false; | ||
166 | }); | ||
167 | return true; | ||
168 | } | ||
169 | |||
170 | // Lock the constraint list and loop through it. | ||
171 | // The constraint action returns 'true' if it wants the loop aborted. | ||
172 | private void ForEachConstraint(ConstraintAction action) | ||
173 | { | ||
174 | lock (m_constraints) | 171 | lock (m_constraints) |
175 | { | 172 | { |
176 | foreach (BSConstraint constrain in m_constraints) | 173 | foreach (BSConstraint constrain in m_constraints) |
177 | { | 174 | { |
178 | if (action(constrain)) | 175 | constrain.CalculateTransforms(); |
179 | break; | 176 | ret = true; |
180 | } | 177 | } |
181 | } | 178 | } |
179 | return ret; | ||
182 | } | 180 | } |
183 | |||
184 | |||
185 | } | 181 | } |
186 | } | 182 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 4a71612..087b9bb 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -37,11 +37,12 @@ public class BSLinkset | |||
37 | private static string LogHeader = "[BULLETSIM LINKSET]"; | 37 | private static string LogHeader = "[BULLETSIM LINKSET]"; |
38 | 38 | ||
39 | private BSPrim m_linksetRoot; | 39 | private BSPrim m_linksetRoot; |
40 | public BSPrim Root { get { return m_linksetRoot; } } | 40 | public BSPrim LinksetRoot { get { return m_linksetRoot; } } |
41 | 41 | ||
42 | private BSScene m_scene; | 42 | private BSScene m_physicsScene; |
43 | public BSScene Scene { get { return m_scene; } } | 43 | public BSScene PhysicsScene { get { return m_physicsScene; } } |
44 | 44 | ||
45 | // The children under the root in this linkset | ||
45 | private List<BSPrim> m_children; | 46 | private List<BSPrim> m_children; |
46 | 47 | ||
47 | // We lock the diddling of linkset classes to prevent any badness. | 48 | // We lock the diddling of linkset classes to prevent any badness. |
@@ -73,7 +74,7 @@ public class BSLinkset | |||
73 | public BSLinkset(BSScene scene, BSPrim parent) | 74 | public BSLinkset(BSScene scene, BSPrim parent) |
74 | { | 75 | { |
75 | // A simple linkset of one (no children) | 76 | // A simple linkset of one (no children) |
76 | m_scene = scene; | 77 | m_physicsScene = scene; |
77 | m_linksetRoot = parent; | 78 | m_linksetRoot = parent; |
78 | m_children = new List<BSPrim>(); | 79 | m_children = new List<BSPrim>(); |
79 | m_mass = parent.MassRaw; | 80 | m_mass = parent.MassRaw; |
@@ -91,6 +92,9 @@ public class BSLinkset | |||
91 | return this; | 92 | return this; |
92 | } | 93 | } |
93 | 94 | ||
95 | // Remove a child from a linkset. | ||
96 | // Returns a new linkset for the child which is a linkset of one (just the | ||
97 | // orphened child). | ||
94 | public BSLinkset RemoveMeFromLinkset(BSPrim child) | 98 | public BSLinkset RemoveMeFromLinkset(BSPrim child) |
95 | { | 99 | { |
96 | lock (m_linksetActivityLock) | 100 | lock (m_linksetActivityLock) |
@@ -114,60 +118,9 @@ public class BSLinkset | |||
114 | } | 118 | } |
115 | 119 | ||
116 | // The child is down to a linkset of just itself | 120 | // The child is down to a linkset of just itself |
117 | return new BSLinkset(Scene, child); | 121 | return new BSLinkset(PhysicsScene, child); |
118 | } | 122 | } |
119 | 123 | ||
120 | /* DEPRECATED: this is really bad in that it trys to unlink other prims. | ||
121 | // An existing linkset had one of its members rebuilt or something. | ||
122 | // Go through the linkset and rebuild the pointers to the bodies of the linkset members. | ||
123 | public BSLinkset RefreshLinkset(BSPrim requestor) | ||
124 | { | ||
125 | BSLinkset ret = requestor.Linkset; | ||
126 | |||
127 | lock (m_linksetActivityLock) | ||
128 | { | ||
129 | // The body pointer is refetched in case anything has moved. | ||
130 | System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID); | ||
131 | if (aPtr == System.IntPtr.Zero) | ||
132 | { | ||
133 | // That's odd. We can't find the root of the linkset. | ||
134 | // The linkset is somehow dead. The requestor is now a member of a linkset of one. | ||
135 | DetailLog("{0},RefreshLinkset.RemoveRoot,child={1}", m_linksetRoot.LocalID, m_linksetRoot.LocalID); | ||
136 | ret = RemoveMeFromLinkset(m_linksetRoot); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | // Reconstruct the pointer to the body of the linkset root. | ||
141 | DetailLog("{0},RefreshLinkset.RebuildRoot,rootID={1},ptr={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, aPtr); | ||
142 | m_linksetRoot.Body = new BulletBody(m_linksetRoot.LocalID, aPtr); | ||
143 | |||
144 | List<BSPrim> toRemove = new List<BSPrim>(); | ||
145 | foreach (BSPrim bsp in m_children) | ||
146 | { | ||
147 | aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, bsp.LocalID); | ||
148 | if (aPtr == System.IntPtr.Zero) | ||
149 | { | ||
150 | toRemove.Add(bsp); | ||
151 | } | ||
152 | else | ||
153 | { | ||
154 | // Reconstruct the pointer to the body of the linkset root. | ||
155 | DetailLog("{0},RefreshLinkset.RebuildChild,rootID={1},ptr={2}", bsp.LocalID, m_linksetRoot.LocalID, aPtr); | ||
156 | bsp.Body = new BulletBody(bsp.LocalID, aPtr); | ||
157 | } | ||
158 | } | ||
159 | foreach (BSPrim bsp in toRemove) | ||
160 | { | ||
161 | RemoveChildFromOtherLinkset(bsp); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | return ret; | ||
167 | } | ||
168 | */ | ||
169 | |||
170 | |||
171 | // Return 'true' if the passed object is the root object of this linkset | 124 | // Return 'true' if the passed object is the root object of this linkset |
172 | public bool IsRoot(BSPrim requestor) | 125 | public bool IsRoot(BSPrim requestor) |
173 | { | 126 | { |
@@ -183,12 +136,15 @@ public class BSLinkset | |||
183 | public bool HasChild(BSPrim child) | 136 | public bool HasChild(BSPrim child) |
184 | { | 137 | { |
185 | bool ret = false; | 138 | bool ret = false; |
186 | foreach (BSPrim bp in m_children) | 139 | lock (m_linksetActivityLock) |
187 | { | 140 | { |
188 | if (child.LocalID == bp.LocalID) | 141 | foreach (BSPrim bp in m_children) |
189 | { | 142 | { |
190 | ret = true; | 143 | if (child.LocalID == bp.LocalID) |
191 | break; | 144 | { |
145 | ret = true; | ||
146 | break; | ||
147 | } | ||
192 | } | 148 | } |
193 | } | 149 | } |
194 | return ret; | 150 | return ret; |
@@ -209,13 +165,16 @@ public class BSLinkset | |||
209 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; | 165 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; |
210 | float totalMass = m_linksetRoot.MassRaw; | 166 | float totalMass = m_linksetRoot.MassRaw; |
211 | 167 | ||
212 | foreach (BSPrim bp in m_children) | 168 | lock (m_linksetActivityLock) |
213 | { | 169 | { |
214 | com += bp.Position * bp.MassRaw; | 170 | foreach (BSPrim bp in m_children) |
215 | totalMass += bp.MassRaw; | 171 | { |
172 | com += bp.Position * bp.MassRaw; | ||
173 | totalMass += bp.MassRaw; | ||
174 | } | ||
175 | if (totalMass != 0f) | ||
176 | com /= totalMass; | ||
216 | } | 177 | } |
217 | if (totalMass != 0f) | ||
218 | com /= totalMass; | ||
219 | 178 | ||
220 | return com; | 179 | return com; |
221 | } | 180 | } |
@@ -224,29 +183,84 @@ public class BSLinkset | |||
224 | { | 183 | { |
225 | OMV.Vector3 com = m_linksetRoot.Position; | 184 | OMV.Vector3 com = m_linksetRoot.Position; |
226 | 185 | ||
227 | foreach (BSPrim bp in m_children) | 186 | lock (m_linksetActivityLock) |
228 | { | 187 | { |
229 | com += bp.Position * bp.MassRaw; | 188 | foreach (BSPrim bp in m_children) |
189 | { | ||
190 | com += bp.Position * bp.MassRaw; | ||
191 | } | ||
192 | com /= (m_children.Count + 1); | ||
230 | } | 193 | } |
231 | com /= (m_children.Count + 1); | ||
232 | 194 | ||
233 | return com; | 195 | return com; |
234 | } | 196 | } |
235 | 197 | ||
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 | |||
236 | // I am the root of a linkset and a new child is being added | 249 | // I am the root of a linkset and a new child is being added |
237 | // Called while LinkActivity is locked. | 250 | // Called while LinkActivity is locked. |
238 | public void AddChildToLinkset(BSPrim child) | 251 | private void AddChildToLinkset(BSPrim child) |
239 | { | 252 | { |
240 | if (!HasChild(child)) | 253 | if (!HasChild(child)) |
241 | { | 254 | { |
242 | m_children.Add(child); | 255 | m_children.Add(child); |
243 | 256 | ||
244 | BSPrim root = Root; // capture the root as of now | 257 | BSPrim rootx = LinksetRoot; // capture the root as of now |
245 | m_scene.TaintedObject("AddChildToLinkset", delegate() | 258 | BSPrim childx = child; |
259 | m_physicsScene.TaintedObject("AddChildToLinkset", delegate() | ||
246 | { | 260 | { |
247 | DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); | 261 | // DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); |
248 | DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | 262 | // DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); |
249 | PhysicallyLinkAChildToRoot(root, child); // build the physical binding between me and the child | 263 | PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child |
250 | }); | 264 | }); |
251 | } | 265 | } |
252 | return; | 266 | return; |
@@ -257,31 +271,34 @@ public class BSLinkset | |||
257 | // it's still connected to the linkset. | 271 | // it's still connected to the linkset. |
258 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information | 272 | // Normal OpenSimulator operation will never do this because other SceneObjectPart information |
259 | // has to be updated also (like pointer to prim's parent). | 273 | // has to be updated also (like pointer to prim's parent). |
260 | public void RemoveChildFromOtherLinkset(BSPrim pchild) | 274 | private void RemoveChildFromOtherLinkset(BSPrim pchild) |
261 | { | 275 | { |
262 | pchild.Linkset = new BSLinkset(m_scene, pchild); | 276 | pchild.Linkset = new BSLinkset(m_physicsScene, pchild); |
263 | RemoveChildFromLinkset(pchild); | 277 | RemoveChildFromLinkset(pchild); |
264 | } | 278 | } |
265 | 279 | ||
266 | // I am the root of a linkset and one of my children is being removed. | 280 | // I am the root of a linkset and one of my children is being removed. |
267 | // Safe to call even if the child is not really in my linkset. | 281 | // Safe to call even if the child is not really in my linkset. |
268 | public void RemoveChildFromLinkset(BSPrim child) | 282 | private void RemoveChildFromLinkset(BSPrim child) |
269 | { | 283 | { |
270 | if (m_children.Remove(child)) | 284 | if (m_children.Remove(child)) |
271 | { | 285 | { |
272 | BSPrim root = Root; // capture the root as of now | 286 | BSPrim rootx = LinksetRoot; // capture the root as of now |
273 | m_scene.TaintedObject("RemoveChildFromLinkset", delegate() | 287 | BSPrim childx = child; |
288 | m_physicsScene.TaintedObject("RemoveChildFromLinkset", delegate() | ||
274 | { | 289 | { |
275 | DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); | 290 | // DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); |
276 | DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); | 291 | // DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID); |
277 | 292 | ||
278 | PhysicallyUnlinkAChildFromRoot(root, child); | 293 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
279 | }); | 294 | }); |
295 | |||
296 | RecomputeLinksetConstraintVariables(); | ||
280 | } | 297 | } |
281 | else | 298 | else |
282 | { | 299 | { |
283 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | 300 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. |
284 | // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | 301 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); |
285 | } | 302 | } |
286 | return; | 303 | return; |
287 | } | 304 | } |
@@ -293,37 +310,72 @@ public class BSLinkset | |||
293 | // Zero motion for children so they don't interpolate | 310 | // Zero motion for children so they don't interpolate |
294 | childPrim.ZeroMotion(); | 311 | childPrim.ZeroMotion(); |
295 | 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 | // ================================================================================== | ||
296 | // relative position normalized to the root prim | 336 | // relative position normalized to the root prim |
297 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | 337 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); |
298 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; | 338 | OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation; |
299 | 339 | ||
300 | // relative rotation of the child to the parent | 340 | // relative rotation of the child to the parent |
301 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | 341 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; |
342 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
302 | 343 | ||
303 | // create a constraint that allows no freedom of movement between the two objects | 344 | // create a constraint that allows no freedom of movement between the two objects |
304 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 345 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
305 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | 346 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); |
306 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | 347 | DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
307 | BS6DofConstraint constrain = new BS6DofConstraint( | 348 | BS6DofConstraint constrain = new BS6DofConstraint( |
308 | m_scene.World, rootPrim.Body, childPrim.Body, | 349 | PhysicsScene.World, rootPrim.Body, childPrim.Body, |
309 | childRelativePosition, | ||
310 | childRelativeRotation, | ||
311 | OMV.Vector3.Zero, | 350 | OMV.Vector3.Zero, |
312 | -childRelativeRotation | 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 | ||
313 | ); | 361 | ); |
314 | m_scene.Constraints.AddConstraint(constrain); | 362 | // ================================================================================== |
363 | */ | ||
364 | |||
365 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
315 | 366 | ||
316 | // zero linear and angular limits makes the objects unable to move in relation to each other | 367 | // zero linear and angular limits makes the objects unable to move in relation to each other |
317 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 368 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
318 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | 369 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); |
319 | 370 | ||
320 | // tweek the constraint to increase stability | 371 | // tweek the constraint to increase stability |
321 | constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset)); | 372 | constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); |
322 | constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor), | 373 | constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), |
323 | m_scene.Params.linkConstraintTransMotorMaxVel, | 374 | PhysicsScene.Params.linkConstraintTransMotorMaxVel, |
324 | m_scene.Params.linkConstraintTransMotorMaxForce); | 375 | PhysicsScene.Params.linkConstraintTransMotorMaxForce); |
325 | constrain.SetCFMAndERP(m_scene.Params.linkConstraintCFM, m_scene.Params.linkConstraintERP); | 376 | constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); |
326 | 377 | ||
378 | RecomputeLinksetConstraintVariables(); | ||
327 | } | 379 | } |
328 | 380 | ||
329 | // Remove linkage between myself and a particular child | 381 | // Remove linkage between myself and a particular child |
@@ -334,7 +386,9 @@ public class BSLinkset | |||
334 | // LogHeader, rootPrim.LocalID, childPrim.LocalID); | 386 | // LogHeader, rootPrim.LocalID, childPrim.LocalID); |
335 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); | 387 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); |
336 | 388 | ||
337 | m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body); | 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 | |||
338 | // Make the child refresh its location | 392 | // Make the child refresh its location |
339 | BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); | 393 | BulletSimAPI.PushUpdate2(childPrim.Body.Ptr); |
340 | } | 394 | } |
@@ -346,20 +400,20 @@ public class BSLinkset | |||
346 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | 400 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); |
347 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | 401 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); |
348 | 402 | ||
349 | m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); | 403 | m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body); |
350 | } | 404 | } |
351 | 405 | ||
352 | // Invoke the detailed logger and output something if it's enabled. | 406 | // Invoke the detailed logger and output something if it's enabled. |
353 | private void DebugLog(string msg, params Object[] args) | 407 | private void DebugLog(string msg, params Object[] args) |
354 | { | 408 | { |
355 | if (m_scene.ShouldDebugLog) | 409 | if (m_physicsScene.ShouldDebugLog) |
356 | m_scene.Logger.DebugFormat(msg, args); | 410 | m_physicsScene.Logger.DebugFormat(msg, args); |
357 | } | 411 | } |
358 | 412 | ||
359 | // Invoke the detailed logger and output something if it's enabled. | 413 | // Invoke the detailed logger and output something if it's enabled. |
360 | private void DetailLog(string msg, params Object[] args) | 414 | private void DetailLog(string msg, params Object[] args) |
361 | { | 415 | { |
362 | m_scene.PhysicsLogging.Write(msg, args); | 416 | m_physicsScene.PhysicsLogging.Write(msg, args); |
363 | } | 417 | } |
364 | 418 | ||
365 | } | 419 | } |