diff options
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs')
-rwxr-xr-x | OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs new file mode 100755 index 0000000..87eba33 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs | |||
@@ -0,0 +1,503 @@ | |||
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 | |||
36 | public abstract class BSLinkset | ||
37 | { | ||
38 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | ||
39 | |||
40 | public enum LinksetImplementation | ||
41 | { | ||
42 | Constraint = 0, // linkset tied together with constraints | ||
43 | Compound = 1, // linkset tied together as a compound object | ||
44 | Manual = 2 // linkset tied together manually (code moves all the pieces) | ||
45 | } | ||
46 | // Create the correct type of linkset for this child | ||
47 | public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) | ||
48 | { | ||
49 | BSLinkset ret = null; | ||
50 | |||
51 | switch (parent.LinksetType) | ||
52 | { | ||
53 | case LinksetImplementation.Constraint: | ||
54 | ret = new BSLinksetConstraints(physScene, parent); | ||
55 | break; | ||
56 | case LinksetImplementation.Compound: | ||
57 | ret = new BSLinksetCompound(physScene, parent); | ||
58 | break; | ||
59 | case LinksetImplementation.Manual: | ||
60 | // ret = new BSLinksetManual(physScene, parent); | ||
61 | break; | ||
62 | default: | ||
63 | ret = new BSLinksetCompound(physScene, parent); | ||
64 | break; | ||
65 | } | ||
66 | if (ret == null) | ||
67 | { | ||
68 | physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); | ||
69 | } | ||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | public class BSLinkInfo | ||
74 | { | ||
75 | public BSPrimLinkable member; | ||
76 | public BSLinkInfo(BSPrimLinkable pMember) | ||
77 | { | ||
78 | member = pMember; | ||
79 | } | ||
80 | public virtual void ResetLink() { } | ||
81 | public virtual void SetLinkParameters(BSConstraint constrain) { } | ||
82 | // Returns 'true' if physical property updates from the child should be reported to the simulator | ||
83 | public virtual bool ShouldUpdateChildProperties() { return false; } | ||
84 | } | ||
85 | |||
86 | public LinksetImplementation LinksetImpl { get; protected set; } | ||
87 | |||
88 | public BSPrimLinkable LinksetRoot { get; protected set; } | ||
89 | |||
90 | protected BSScene m_physicsScene { get; private set; } | ||
91 | |||
92 | static int m_nextLinksetID = 1; | ||
93 | public int LinksetID { get; private set; } | ||
94 | |||
95 | // The children under the root in this linkset. | ||
96 | // protected HashSet<BSPrimLinkable> m_children; | ||
97 | protected Dictionary<BSPrimLinkable, BSLinkInfo> m_children; | ||
98 | |||
99 | // We lock the diddling of linkset classes to prevent any badness. | ||
100 | // This locks the modification of the instances of this class. Changes | ||
101 | // to the physical representation is done via the tainting mechenism. | ||
102 | protected object m_linksetActivityLock = new Object(); | ||
103 | |||
104 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | ||
105 | public float LinksetMass { get; protected set; } | ||
106 | |||
107 | public virtual bool LinksetIsColliding { get { return false; } } | ||
108 | |||
109 | public OMV.Vector3 CenterOfMass | ||
110 | { | ||
111 | get { return ComputeLinksetCenterOfMass(); } | ||
112 | } | ||
113 | |||
114 | public OMV.Vector3 GeometricCenter | ||
115 | { | ||
116 | get { return ComputeLinksetGeometricCenter(); } | ||
117 | } | ||
118 | |||
119 | protected BSLinkset(BSScene scene, BSPrimLinkable parent) | ||
120 | { | ||
121 | // A simple linkset of one (no children) | ||
122 | LinksetID = m_nextLinksetID++; | ||
123 | // We create LOTS of linksets. | ||
124 | if (m_nextLinksetID <= 0) | ||
125 | m_nextLinksetID = 1; | ||
126 | m_physicsScene = scene; | ||
127 | LinksetRoot = parent; | ||
128 | m_children = new Dictionary<BSPrimLinkable, BSLinkInfo>(); | ||
129 | LinksetMass = parent.RawMass; | ||
130 | Rebuilding = false; | ||
131 | RebuildScheduled = false; | ||
132 | |||
133 | parent.ClearDisplacement(); | ||
134 | } | ||
135 | |||
136 | // Link to a linkset where the child knows the parent. | ||
137 | // Parent changing should not happen so do some sanity checking. | ||
138 | // We return the parent's linkset so the child can track its membership. | ||
139 | // Called at runtime. | ||
140 | public BSLinkset AddMeToLinkset(BSPrimLinkable child) | ||
141 | { | ||
142 | lock (m_linksetActivityLock) | ||
143 | { | ||
144 | // Don't add the root to its own linkset | ||
145 | if (!IsRoot(child)) | ||
146 | AddChildToLinkset(child); | ||
147 | LinksetMass = ComputeLinksetMass(); | ||
148 | } | ||
149 | return this; | ||
150 | } | ||
151 | |||
152 | // Remove a child from a linkset. | ||
153 | // Returns a new linkset for the child which is a linkset of one (just the | ||
154 | // orphened child). | ||
155 | // Called at runtime. | ||
156 | public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
157 | { | ||
158 | lock (m_linksetActivityLock) | ||
159 | { | ||
160 | if (IsRoot(child)) | ||
161 | { | ||
162 | // Cannot remove the root from a linkset. | ||
163 | return this; | ||
164 | } | ||
165 | RemoveChildFromLinkset(child, inTaintTime); | ||
166 | LinksetMass = ComputeLinksetMass(); | ||
167 | } | ||
168 | |||
169 | // The child is down to a linkset of just itself | ||
170 | return BSLinkset.Factory(m_physicsScene, child); | ||
171 | } | ||
172 | |||
173 | // Return 'true' if the passed object is the root object of this linkset | ||
174 | public bool IsRoot(BSPrimLinkable requestor) | ||
175 | { | ||
176 | return (requestor.LocalID == LinksetRoot.LocalID); | ||
177 | } | ||
178 | |||
179 | public int NumberOfChildren { get { return m_children.Count; } } | ||
180 | |||
181 | // Return 'true' if this linkset has any children (more than the root member) | ||
182 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } | ||
183 | |||
184 | // Return 'true' if this child is in this linkset | ||
185 | public bool HasChild(BSPrimLinkable child) | ||
186 | { | ||
187 | bool ret = false; | ||
188 | lock (m_linksetActivityLock) | ||
189 | { | ||
190 | ret = m_children.ContainsKey(child); | ||
191 | } | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | // Perform an action on each member of the linkset including root prim. | ||
196 | // Depends on the action on whether this should be done at taint time. | ||
197 | public delegate bool ForEachMemberAction(BSPrimLinkable obj); | ||
198 | public virtual bool ForEachMember(ForEachMemberAction action) | ||
199 | { | ||
200 | bool ret = false; | ||
201 | lock (m_linksetActivityLock) | ||
202 | { | ||
203 | action(LinksetRoot); | ||
204 | foreach (BSPrimLinkable po in m_children.Keys) | ||
205 | { | ||
206 | if (action(po)) | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) | ||
214 | { | ||
215 | bool ret = false; | ||
216 | BSLinkInfo found = null; | ||
217 | lock (m_linksetActivityLock) | ||
218 | { | ||
219 | ret = m_children.TryGetValue(child, out found); | ||
220 | } | ||
221 | foundInfo = found; | ||
222 | return ret; | ||
223 | } | ||
224 | // Perform an action on each member of the linkset including root prim. | ||
225 | // Depends on the action on whether this should be done at taint time. | ||
226 | public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); | ||
227 | public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) | ||
228 | { | ||
229 | bool ret = false; | ||
230 | lock (m_linksetActivityLock) | ||
231 | { | ||
232 | foreach (BSLinkInfo po in m_children.Values) | ||
233 | { | ||
234 | if (action(po)) | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | // Check the type of the link and return 'true' if the link is flexible and the | ||
242 | // updates from the child should be sent to the simulator so things change. | ||
243 | public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) | ||
244 | { | ||
245 | bool ret = false; | ||
246 | |||
247 | BSLinkInfo linkInfo; | ||
248 | if (m_children.TryGetValue(child, out linkInfo)) | ||
249 | { | ||
250 | ret = linkInfo.ShouldUpdateChildProperties(); | ||
251 | } | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | // Called after a simulation step to post a collision with this object. | ||
257 | // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have | ||
258 | // anything to add for the collision and it should be passed through normal processing. | ||
259 | // Default processing for a linkset. | ||
260 | public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, | ||
261 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) | ||
262 | { | ||
263 | bool ret = false; | ||
264 | |||
265 | // prims in the same linkset cannot collide with each other | ||
266 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; | ||
267 | if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) | ||
268 | { | ||
269 | // By returning 'true', we tell the caller the collision has been 'handled' so it won't | ||
270 | // do anything about this collision and thus, effectivily, ignoring the collision. | ||
271 | ret = true; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | // Not a collision between members of the linkset. Must be a real collision. | ||
276 | // So the linkset root can know if there is a collision anywhere in the linkset. | ||
277 | LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; | ||
278 | } | ||
279 | |||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | // I am the root of a linkset and a new child is being added | ||
284 | // Called while LinkActivity is locked. | ||
285 | protected abstract void AddChildToLinkset(BSPrimLinkable child); | ||
286 | |||
287 | // I am the root of a linkset and one of my children is being removed. | ||
288 | // Safe to call even if the child is not really in my linkset. | ||
289 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); | ||
290 | |||
291 | // When physical properties are changed the linkset needs to recalculate | ||
292 | // its internal properties. | ||
293 | // May be called at runtime or taint-time. | ||
294 | public virtual void Refresh(BSPrimLinkable requestor) | ||
295 | { | ||
296 | LinksetMass = ComputeLinksetMass(); | ||
297 | } | ||
298 | |||
299 | // Flag denoting the linkset is in the process of being rebuilt. | ||
300 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
301 | // Because of potential update calls that could want to schedule another rebuild. | ||
302 | protected bool Rebuilding { get; set; } | ||
303 | |||
304 | // Flag saying a linkset rebuild has been scheduled. | ||
305 | // This is turned on when the rebuild is requested and turned off when | ||
306 | // the rebuild is complete. Used to limit modifications to the | ||
307 | // linkset parameters while the linkset is in an intermediate state. | ||
308 | // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object | ||
309 | public bool RebuildScheduled { get; protected set; } | ||
310 | |||
311 | // The object is going dynamic (physical). Do any setup necessary | ||
312 | // for a dynamic linkset. | ||
313 | // Only the state of the passed object can be modified. The rest of the linkset | ||
314 | // has not yet been fully constructed. | ||
315 | // Return 'true' if any properties updated on the passed object. | ||
316 | // Called at taint-time! | ||
317 | public abstract bool MakeDynamic(BSPrimLinkable child); | ||
318 | |||
319 | public virtual bool AllPartsComplete | ||
320 | { | ||
321 | get { | ||
322 | bool ret = true; | ||
323 | this.ForEachMember((member) => | ||
324 | { | ||
325 | if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting) | ||
326 | { | ||
327 | ret = false; | ||
328 | return true; // exit loop | ||
329 | } | ||
330 | return false; // continue loop | ||
331 | }); | ||
332 | return ret; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | // The object is going static (non-physical). Do any setup necessary | ||
337 | // for a static linkset. | ||
338 | // Return 'true' if any properties updated on the passed object. | ||
339 | // Called at taint-time! | ||
340 | public abstract bool MakeStatic(BSPrimLinkable child); | ||
341 | |||
342 | // Called when a parameter update comes from the physics engine for any object | ||
343 | // of the linkset is received. | ||
344 | // Passed flag is update came from physics engine (true) or the user (false). | ||
345 | // Called at taint-time!! | ||
346 | public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); | ||
347 | |||
348 | // Routine used when rebuilding the body of the root of the linkset | ||
349 | // Destroy all the constraints have have been made to root. | ||
350 | // This is called when the root body is changing. | ||
351 | // Returns 'true' of something was actually removed and would need restoring | ||
352 | // Called at taint-time!! | ||
353 | public abstract bool RemoveDependencies(BSPrimLinkable child); | ||
354 | |||
355 | // ================================================================ | ||
356 | // Some physical setting happen to all members of the linkset | ||
357 | public virtual void SetPhysicalFriction(float friction) | ||
358 | { | ||
359 | ForEachMember((member) => | ||
360 | { | ||
361 | if (member.PhysBody.HasPhysicalBody) | ||
362 | m_physicsScene.PE.SetFriction(member.PhysBody, friction); | ||
363 | return false; // 'false' says to continue looping | ||
364 | } | ||
365 | ); | ||
366 | } | ||
367 | public virtual void SetPhysicalRestitution(float restitution) | ||
368 | { | ||
369 | ForEachMember((member) => | ||
370 | { | ||
371 | if (member.PhysBody.HasPhysicalBody) | ||
372 | m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); | ||
373 | return false; // 'false' says to continue looping | ||
374 | } | ||
375 | ); | ||
376 | } | ||
377 | public virtual void SetPhysicalGravity(OMV.Vector3 gravity) | ||
378 | { | ||
379 | ForEachMember((member) => | ||
380 | { | ||
381 | if (member.PhysBody.HasPhysicalBody) | ||
382 | m_physicsScene.PE.SetGravity(member.PhysBody, gravity); | ||
383 | return false; // 'false' says to continue looping | ||
384 | } | ||
385 | ); | ||
386 | } | ||
387 | public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) | ||
388 | { | ||
389 | ForEachMember((member) => | ||
390 | { | ||
391 | if (member.PhysBody.HasPhysicalBody) | ||
392 | { | ||
393 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); | ||
394 | member.Inertia = inertia * inertiaFactor; | ||
395 | m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); | ||
396 | m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); | ||
397 | DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); | ||
398 | |||
399 | } | ||
400 | return false; // 'false' says to continue looping | ||
401 | } | ||
402 | ); | ||
403 | } | ||
404 | public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) | ||
405 | { | ||
406 | ForEachMember((member) => | ||
407 | { | ||
408 | if (member.PhysBody.HasPhysicalBody) | ||
409 | m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); | ||
410 | return false; // 'false' says to continue looping | ||
411 | } | ||
412 | ); | ||
413 | } | ||
414 | public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) | ||
415 | { | ||
416 | ForEachMember((member) => | ||
417 | { | ||
418 | if (member.PhysBody.HasPhysicalBody) | ||
419 | m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); | ||
420 | return false; // 'false' says to continue looping | ||
421 | } | ||
422 | ); | ||
423 | } | ||
424 | public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
425 | { | ||
426 | ForEachMember((member) => | ||
427 | { | ||
428 | if (member.PhysBody.HasPhysicalBody) | ||
429 | m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); | ||
430 | return false; // 'false' says to continue looping | ||
431 | } | ||
432 | ); | ||
433 | } | ||
434 | // ================================================================ | ||
435 | protected virtual float ComputeLinksetMass() | ||
436 | { | ||
437 | float mass = LinksetRoot.RawMass; | ||
438 | if (HasAnyChildren) | ||
439 | { | ||
440 | lock (m_linksetActivityLock) | ||
441 | { | ||
442 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
443 | { | ||
444 | mass += bp.RawMass; | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | return mass; | ||
449 | } | ||
450 | |||
451 | // Computes linkset's center of mass in world coordinates. | ||
452 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() | ||
453 | { | ||
454 | OMV.Vector3 com; | ||
455 | lock (m_linksetActivityLock) | ||
456 | { | ||
457 | com = LinksetRoot.Position * LinksetRoot.RawMass; | ||
458 | float totalMass = LinksetRoot.RawMass; | ||
459 | |||
460 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
461 | { | ||
462 | com += bp.Position * bp.RawMass; | ||
463 | totalMass += bp.RawMass; | ||
464 | } | ||
465 | if (totalMass != 0f) | ||
466 | com /= totalMass; | ||
467 | } | ||
468 | |||
469 | return com; | ||
470 | } | ||
471 | |||
472 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() | ||
473 | { | ||
474 | OMV.Vector3 com; | ||
475 | lock (m_linksetActivityLock) | ||
476 | { | ||
477 | com = LinksetRoot.Position; | ||
478 | |||
479 | foreach (BSPrimLinkable bp in m_children.Keys) | ||
480 | { | ||
481 | com += bp.Position; | ||
482 | } | ||
483 | com /= (m_children.Count + 1); | ||
484 | } | ||
485 | |||
486 | return com; | ||
487 | } | ||
488 | |||
489 | #region Extension | ||
490 | public virtual object Extension(string pFunct, params object[] pParams) | ||
491 | { | ||
492 | return null; | ||
493 | } | ||
494 | #endregion // Extension | ||
495 | |||
496 | // Invoke the detailed logger and output something if it's enabled. | ||
497 | protected void DetailLog(string msg, params Object[] args) | ||
498 | { | ||
499 | if (m_physicsScene.PhysicsLogging.Enabled) | ||
500 | m_physicsScene.DetailLog(msg, args); | ||
501 | } | ||
502 | } | ||
503 | } | ||