diff options
Diffstat (limited to '')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs new file mode 100755 index 0000000..6f8430c --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -0,0 +1,352 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | public class BSLinkset | ||
36 | { | ||
37 | private static string LogHeader = "[BULLETSIM LINKSET]"; | ||
38 | |||
39 | private BSPrim m_linksetRoot; | ||
40 | public BSPrim Root { get { return m_linksetRoot; } } | ||
41 | |||
42 | private BSScene m_scene; | ||
43 | |||
44 | private List<BSPrim> m_children; | ||
45 | |||
46 | // We lock the diddling of linkset classes to prevent any badness. | ||
47 | // This locks the modification of the instances of this class. Changes | ||
48 | // to the physical representation is done via the tainting mechenism. | ||
49 | private object m_linksetActivityLock = new Object(); | ||
50 | |||
51 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | ||
52 | private float m_mass; | ||
53 | public float LinksetMass | ||
54 | { | ||
55 | get | ||
56 | { | ||
57 | m_mass = ComputeLinksetMass(); | ||
58 | return m_mass; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | public OMV.Vector3 CenterOfMass | ||
63 | { | ||
64 | get { return ComputeLinksetCenterOfMass(); } | ||
65 | } | ||
66 | |||
67 | public OMV.Vector3 GeometricCenter | ||
68 | { | ||
69 | get { return ComputeLinksetGeometricCenter(); } | ||
70 | } | ||
71 | |||
72 | public BSLinkset(BSScene scene, BSPrim parent) | ||
73 | { | ||
74 | // A simple linkset of one (no children) | ||
75 | m_scene = scene; | ||
76 | m_linksetRoot = parent; | ||
77 | m_children = new List<BSPrim>(); | ||
78 | m_mass = parent.MassRaw; | ||
79 | } | ||
80 | |||
81 | // Link to a linkset where the child knows the parent. | ||
82 | // Parent changing should not happen so do some sanity checking. | ||
83 | // We return the parent's linkset so the child can track it's membership. | ||
84 | public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent) | ||
85 | { | ||
86 | lock (m_linksetActivityLock) | ||
87 | { | ||
88 | parent.Linkset.AddChildToLinkset(child); | ||
89 | } | ||
90 | return parent.Linkset; | ||
91 | } | ||
92 | |||
93 | public BSLinkset RemoveMeFromLinkset(BSPrim child) | ||
94 | { | ||
95 | lock (m_linksetActivityLock) | ||
96 | { | ||
97 | if (IsRoot(child)) | ||
98 | { | ||
99 | // if root of linkset, take the linkset apart | ||
100 | while (m_children.Count > 0) | ||
101 | { | ||
102 | // Note that we don't do a foreach because the remove routine | ||
103 | // takes it out of the list. | ||
104 | RemoveChildFromLinkset(m_children[0]); | ||
105 | } | ||
106 | m_children.Clear(); // just to make sure | ||
107 | } | ||
108 | else | ||
109 | { | ||
110 | // Just removing a child from an existing linkset | ||
111 | RemoveChildFromLinkset(child); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // The child is down to a linkset of just itself | ||
116 | return new BSLinkset(m_scene, child); | ||
117 | } | ||
118 | |||
119 | // An existing linkset had one of its members rebuilt or something. | ||
120 | // Go through the linkset and rebuild the pointers to the bodies of the linkset members. | ||
121 | public BSLinkset RefreshLinkset(BSPrim requestor) | ||
122 | { | ||
123 | BSLinkset ret = requestor.Linkset; | ||
124 | |||
125 | lock (m_linksetActivityLock) | ||
126 | { | ||
127 | System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID); | ||
128 | if (aPtr == System.IntPtr.Zero) | ||
129 | { | ||
130 | // That's odd. We can't find the root of the linkset. | ||
131 | // The linkset is somehow dead. The requestor is now a member of a linkset of one. | ||
132 | DetailLog("{0},RefreshLinkset.RemoveRoot,child={1}", m_linksetRoot.LocalID, m_linksetRoot.LocalID); | ||
133 | ret = RemoveMeFromLinkset(m_linksetRoot); | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | // Reconstruct the pointer to the body of the linkset root. | ||
138 | DetailLog("{0},RefreshLinkset.RebuildRoot,rootID={1},ptr={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, aPtr); | ||
139 | m_linksetRoot.Body = new BulletBody(m_linksetRoot.LocalID, aPtr); | ||
140 | |||
141 | List<BSPrim> toRemove = new List<BSPrim>(); | ||
142 | foreach (BSPrim bsp in m_children) | ||
143 | { | ||
144 | aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, bsp.LocalID); | ||
145 | if (aPtr == System.IntPtr.Zero) | ||
146 | { | ||
147 | toRemove.Add(bsp); | ||
148 | } | ||
149 | else | ||
150 | { | ||
151 | // Reconstruct the pointer to the body of the linkset root. | ||
152 | DetailLog("{0},RefreshLinkset.RebuildChild,rootID={1},ptr={2}", bsp.LocalID, m_linksetRoot.LocalID, aPtr); | ||
153 | bsp.Body = new BulletBody(bsp.LocalID, aPtr); | ||
154 | } | ||
155 | } | ||
156 | foreach (BSPrim bsp in toRemove) | ||
157 | { | ||
158 | RemoveChildFromLinkset(bsp); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | |||
167 | // Return 'true' if the passed object is the root object of this linkset | ||
168 | public bool IsRoot(BSPrim requestor) | ||
169 | { | ||
170 | return (requestor.LocalID == m_linksetRoot.LocalID); | ||
171 | } | ||
172 | |||
173 | // Return 'true' if this linkset has any children (more than the root member) | ||
174 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | ||
175 | |||
176 | // Return 'true' if this child is in this linkset | ||
177 | public bool HasChild(BSPrim child) | ||
178 | { | ||
179 | bool ret = false; | ||
180 | foreach (BSPrim bp in m_children) | ||
181 | { | ||
182 | if (child.LocalID == bp.LocalID) | ||
183 | { | ||
184 | ret = true; | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | private float ComputeLinksetMass() | ||
192 | { | ||
193 | float mass = m_linksetRoot.MassRaw; | ||
194 | foreach (BSPrim bp in m_children) | ||
195 | { | ||
196 | mass += bp.MassRaw; | ||
197 | } | ||
198 | return mass; | ||
199 | } | ||
200 | |||
201 | private OMV.Vector3 ComputeLinksetCenterOfMass() | ||
202 | { | ||
203 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; | ||
204 | float totalMass = m_linksetRoot.MassRaw; | ||
205 | |||
206 | foreach (BSPrim bp in m_children) | ||
207 | { | ||
208 | com += bp.Position * bp.MassRaw; | ||
209 | totalMass += bp.MassRaw; | ||
210 | } | ||
211 | com /= totalMass; | ||
212 | |||
213 | return com; | ||
214 | } | ||
215 | |||
216 | private OMV.Vector3 ComputeLinksetGeometricCenter() | ||
217 | { | ||
218 | OMV.Vector3 com = m_linksetRoot.Position; | ||
219 | |||
220 | foreach (BSPrim bp in m_children) | ||
221 | { | ||
222 | com += bp.Position * bp.MassRaw; | ||
223 | } | ||
224 | com /= m_children.Count + 1; | ||
225 | |||
226 | return com; | ||
227 | } | ||
228 | |||
229 | // I am the root of a linkset and a new child is being added | ||
230 | public void AddChildToLinkset(BSPrim pchild) | ||
231 | { | ||
232 | BSPrim child = pchild; | ||
233 | if (!HasChild(child)) | ||
234 | { | ||
235 | m_children.Add(child); | ||
236 | |||
237 | m_scene.TaintedObject(delegate() | ||
238 | { | ||
239 | DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); | ||
240 | DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); | ||
241 | PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child | ||
242 | }); | ||
243 | } | ||
244 | return; | ||
245 | } | ||
246 | |||
247 | // I am the root of a linkset and one of my children is being removed. | ||
248 | // Safe to call even if the child is not really in my linkset. | ||
249 | public void RemoveChildFromLinkset(BSPrim pchild) | ||
250 | { | ||
251 | BSPrim child = pchild; | ||
252 | |||
253 | if (m_children.Remove(child)) | ||
254 | { | ||
255 | m_scene.TaintedObject(delegate() | ||
256 | { | ||
257 | DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); | ||
258 | DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); | ||
259 | |||
260 | if (m_children.Count == 0) | ||
261 | { | ||
262 | // if the linkset is empty, make sure all linkages have been removed | ||
263 | PhysicallyUnlinkAllChildrenFromRoot(); | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | PhysicallyUnlinkAChildFromRoot(pchild); | ||
268 | } | ||
269 | }); | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | ||
274 | // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
275 | } | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
280 | // Called at taint time! | ||
281 | private void PhysicallyLinkAChildToRoot(BSPrim childPrim) | ||
282 | { | ||
283 | // Zero motion for children so they don't interpolate | ||
284 | childPrim.ZeroMotion(); | ||
285 | |||
286 | // relative position normalized to the root prim | ||
287 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation); | ||
288 | OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation; | ||
289 | |||
290 | // relative rotation of the child to the parent | ||
291 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
292 | |||
293 | // create a constraint that allows no freedom of movement between the two objects | ||
294 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
295 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
296 | DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); | ||
297 | BSConstraint constrain = m_scene.Constraints.CreateConstraint( | ||
298 | m_scene.World, m_linksetRoot.Body, childPrim.Body, | ||
299 | // childRelativePosition, | ||
300 | // childRelativeRotation, | ||
301 | OMV.Vector3.Zero, | ||
302 | OMV.Quaternion.Identity, | ||
303 | OMV.Vector3.Zero, | ||
304 | OMV.Quaternion.Identity | ||
305 | ); | ||
306 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
307 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
308 | |||
309 | // tweek the constraint to increase stability | ||
310 | constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset)); | ||
311 | constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor), | ||
312 | m_scene.Params.linkConstraintTransMotorMaxVel, | ||
313 | m_scene.Params.linkConstraintTransMotorMaxForce); | ||
314 | constrain.SetCFMAndERP(m_scene.Params.linkConstraintCFM, m_scene.Params.linkConstraintERP); | ||
315 | |||
316 | } | ||
317 | |||
318 | // Remove linkage between myself and a particular child | ||
319 | // Called at taint time! | ||
320 | private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim) | ||
321 | { | ||
322 | DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", | ||
323 | LogHeader, m_linksetRoot.LocalID, childPrim.LocalID); | ||
324 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); | ||
325 | // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID); | ||
326 | m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body); | ||
327 | } | ||
328 | |||
329 | // Remove linkage between myself and any possible children I might have | ||
330 | // Called at taint time! | ||
331 | private void PhysicallyUnlinkAllChildrenFromRoot() | ||
332 | { | ||
333 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | ||
334 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID); | ||
335 | m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body); | ||
336 | // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); | ||
337 | } | ||
338 | |||
339 | // Invoke the detailed logger and output something if it's enabled. | ||
340 | private void DebugLog(string msg, params Object[] args) | ||
341 | { | ||
342 | m_scene.Logger.DebugFormat(msg, args); | ||
343 | } | ||
344 | |||
345 | // Invoke the detailed logger and output something if it's enabled. | ||
346 | private void DetailLog(string msg, params Object[] args) | ||
347 | { | ||
348 | m_scene.PhysicsLogging.Write(msg, args); | ||
349 | } | ||
350 | |||
351 | } | ||
352 | } | ||