diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | 308 |
1 files changed, 308 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..a1027ee --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -0,0 +1,308 @@ | |||
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 Mass | ||
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 | // Undo all the physical linking and rebuild the physical linkset. | ||
121 | public bool RefreshLinkset(BSPrim requestor) | ||
122 | { | ||
123 | return true; | ||
124 | } | ||
125 | |||
126 | |||
127 | // Return 'true' if the passed object is the root object of this linkset | ||
128 | public bool IsRoot(BSPrim requestor) | ||
129 | { | ||
130 | return (requestor.LocalID == m_linksetRoot.LocalID); | ||
131 | } | ||
132 | |||
133 | // Return 'true' if this linkset has any children (more than the root member) | ||
134 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | ||
135 | |||
136 | // Return 'true' if this child is in this linkset | ||
137 | public bool HasChild(BSPrim child) | ||
138 | { | ||
139 | bool ret = false; | ||
140 | foreach (BSPrim bp in m_children) | ||
141 | { | ||
142 | if (child.LocalID == bp.LocalID) | ||
143 | { | ||
144 | ret = true; | ||
145 | break; | ||
146 | } | ||
147 | } | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | private float ComputeLinksetMass() | ||
152 | { | ||
153 | float mass = m_linksetRoot.Mass; | ||
154 | foreach (BSPrim bp in m_children) | ||
155 | { | ||
156 | mass += bp.Mass; | ||
157 | } | ||
158 | return mass; | ||
159 | } | ||
160 | |||
161 | private OMV.Vector3 ComputeLinksetCenterOfMass() | ||
162 | { | ||
163 | OMV.Vector3 com = m_linksetRoot.Position * m_linksetRoot.MassRaw; | ||
164 | float totalMass = m_linksetRoot.MassRaw; | ||
165 | |||
166 | foreach (BSPrim bp in m_children) | ||
167 | { | ||
168 | com += bp.Position * bp.MassRaw; | ||
169 | totalMass += bp.MassRaw; | ||
170 | } | ||
171 | com /= totalMass; | ||
172 | |||
173 | return com; | ||
174 | } | ||
175 | |||
176 | private OMV.Vector3 ComputeLinksetGeometricCenter() | ||
177 | { | ||
178 | OMV.Vector3 com = m_linksetRoot.Position; | ||
179 | |||
180 | foreach (BSPrim bp in m_children) | ||
181 | { | ||
182 | com += bp.Position * bp.MassRaw; | ||
183 | } | ||
184 | com /= m_children.Count + 1; | ||
185 | |||
186 | return com; | ||
187 | } | ||
188 | |||
189 | // I am the root of a linkset and a new child is being added | ||
190 | public void AddChildToLinkset(BSPrim pchild) | ||
191 | { | ||
192 | BSPrim child = pchild; | ||
193 | if (!HasChild(child)) | ||
194 | { | ||
195 | m_children.Add(child); | ||
196 | |||
197 | m_scene.TaintedObject(delegate() | ||
198 | { | ||
199 | DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID); | ||
200 | DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); | ||
201 | PhysicallyLinkAChildToRoot(pchild); // build the physical binding between me and the child | ||
202 | }); | ||
203 | } | ||
204 | return; | ||
205 | } | ||
206 | |||
207 | // I am the root of a linkset and one of my children is being removed. | ||
208 | // Safe to call even if the child is not really in my linkset. | ||
209 | public void RemoveChildFromLinkset(BSPrim pchild) | ||
210 | { | ||
211 | BSPrim child = pchild; | ||
212 | |||
213 | if (m_children.Remove(child)) | ||
214 | { | ||
215 | m_scene.TaintedObject(delegate() | ||
216 | { | ||
217 | DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); | ||
218 | DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID); | ||
219 | |||
220 | if (m_children.Count == 0) | ||
221 | { | ||
222 | // if the linkset is empty, make sure all linkages have been removed | ||
223 | PhysicallyUnlinkAllChildrenFromRoot(); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | PhysicallyUnlinkAChildFromRoot(pchild); | ||
228 | } | ||
229 | }); | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | // This will happen if we remove the root of the linkset first. Non-fatal occurance. | ||
234 | // m_scene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
235 | } | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
240 | // Called at taint time! | ||
241 | private void PhysicallyLinkAChildToRoot(BSPrim childPrim) | ||
242 | { | ||
243 | // Zero motion for children so they don't interpolate | ||
244 | childPrim.ZeroMotion(); | ||
245 | |||
246 | // relative position normalized to the root prim | ||
247 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation); | ||
248 | OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation; | ||
249 | |||
250 | // relative rotation of the child to the parent | ||
251 | OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation; | ||
252 | |||
253 | // create a constraint that allows no freedom of movement between the two objects | ||
254 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
255 | // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID); | ||
256 | DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); | ||
257 | BSConstraint constrain = m_scene.Constraints.CreateConstraint( | ||
258 | m_scene.World, m_linksetRoot.Body, childPrim.Body, | ||
259 | childRelativePosition, | ||
260 | childRelativeRotation, | ||
261 | OMV.Vector3.Zero, | ||
262 | OMV.Quaternion.Identity); | ||
263 | constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
264 | constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); | ||
265 | |||
266 | // tweek the constraint to increase stability | ||
267 | constrain.UseFrameOffset(m_scene.BoolNumeric(m_scene.Params.linkConstraintUseFrameOffset)); | ||
268 | constrain.TranslationalLimitMotor(m_scene.BoolNumeric(m_scene.Params.linkConstraintEnableTransMotor), | ||
269 | m_scene.Params.linkConstraintTransMotorMaxVel, | ||
270 | m_scene.Params.linkConstraintTransMotorMaxForce); | ||
271 | |||
272 | } | ||
273 | |||
274 | // Remove linkage between myself and a particular child | ||
275 | // Called at taint time! | ||
276 | private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim) | ||
277 | { | ||
278 | DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", | ||
279 | LogHeader, m_linksetRoot.LocalID, childPrim.LocalID); | ||
280 | DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID); | ||
281 | // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID); | ||
282 | m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body); | ||
283 | } | ||
284 | |||
285 | // Remove linkage between myself and any possible children I might have | ||
286 | // Called at taint time! | ||
287 | private void PhysicallyUnlinkAllChildrenFromRoot() | ||
288 | { | ||
289 | // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader); | ||
290 | DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID); | ||
291 | m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body); | ||
292 | // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID); | ||
293 | } | ||
294 | |||
295 | // Invoke the detailed logger and output something if it's enabled. | ||
296 | private void DebugLog(string msg, params Object[] args) | ||
297 | { | ||
298 | m_scene.Logger.DebugFormat(msg, args); | ||
299 | } | ||
300 | |||
301 | // Invoke the detailed logger and output something if it's enabled. | ||
302 | private void DetailLog(string msg, params Object[] args) | ||
303 | { | ||
304 | m_scene.PhysicsLogging.Write(msg, args); | ||
305 | } | ||
306 | |||
307 | } | ||
308 | } | ||