opensim – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | eva | 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 | |||
132 | parent.ClearDisplacement(); |
||
133 | } |
||
134 | |||
135 | // Link to a linkset where the child knows the parent. |
||
136 | // Parent changing should not happen so do some sanity checking. |
||
137 | // We return the parent's linkset so the child can track its membership. |
||
138 | // Called at runtime. |
||
139 | public BSLinkset AddMeToLinkset(BSPrimLinkable child) |
||
140 | { |
||
141 | lock (m_linksetActivityLock) |
||
142 | { |
||
143 | // Don't add the root to its own linkset |
||
144 | if (!IsRoot(child)) |
||
145 | AddChildToLinkset(child); |
||
146 | LinksetMass = ComputeLinksetMass(); |
||
147 | } |
||
148 | return this; |
||
149 | } |
||
150 | |||
151 | // Remove a child from a linkset. |
||
152 | // Returns a new linkset for the child which is a linkset of one (just the |
||
153 | // orphened child). |
||
154 | // Called at runtime. |
||
155 | public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) |
||
156 | { |
||
157 | lock (m_linksetActivityLock) |
||
158 | { |
||
159 | if (IsRoot(child)) |
||
160 | { |
||
161 | // Cannot remove the root from a linkset. |
||
162 | return this; |
||
163 | } |
||
164 | RemoveChildFromLinkset(child, inTaintTime); |
||
165 | LinksetMass = ComputeLinksetMass(); |
||
166 | } |
||
167 | |||
168 | // The child is down to a linkset of just itself |
||
169 | return BSLinkset.Factory(m_physicsScene, child); |
||
170 | } |
||
171 | |||
172 | // Return 'true' if the passed object is the root object of this linkset |
||
173 | public bool IsRoot(BSPrimLinkable requestor) |
||
174 | { |
||
175 | return (requestor.LocalID == LinksetRoot.LocalID); |
||
176 | } |
||
177 | |||
178 | public int NumberOfChildren { get { return m_children.Count; } } |
||
179 | |||
180 | // Return 'true' if this linkset has any children (more than the root member) |
||
181 | public bool HasAnyChildren { get { return (m_children.Count > 0); } } |
||
182 | |||
183 | // Return 'true' if this child is in this linkset |
||
184 | public bool HasChild(BSPrimLinkable child) |
||
185 | { |
||
186 | bool ret = false; |
||
187 | lock (m_linksetActivityLock) |
||
188 | { |
||
189 | ret = m_children.ContainsKey(child); |
||
190 | } |
||
191 | return ret; |
||
192 | } |
||
193 | |||
194 | // Perform an action on each member of the linkset including root prim. |
||
195 | // Depends on the action on whether this should be done at taint time. |
||
196 | public delegate bool ForEachMemberAction(BSPrimLinkable obj); |
||
197 | public virtual bool ForEachMember(ForEachMemberAction action) |
||
198 | { |
||
199 | bool ret = false; |
||
200 | lock (m_linksetActivityLock) |
||
201 | { |
||
202 | action(LinksetRoot); |
||
203 | foreach (BSPrimLinkable po in m_children.Keys) |
||
204 | { |
||
205 | if (action(po)) |
||
206 | break; |
||
207 | } |
||
208 | } |
||
209 | return ret; |
||
210 | } |
||
211 | |||
212 | public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) |
||
213 | { |
||
214 | bool ret = false; |
||
215 | BSLinkInfo found = null; |
||
216 | lock (m_linksetActivityLock) |
||
217 | { |
||
218 | ret = m_children.TryGetValue(child, out found); |
||
219 | } |
||
220 | foundInfo = found; |
||
221 | return ret; |
||
222 | } |
||
223 | // Perform an action on each member of the linkset including root prim. |
||
224 | // Depends on the action on whether this should be done at taint time. |
||
225 | public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); |
||
226 | public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) |
||
227 | { |
||
228 | bool ret = false; |
||
229 | lock (m_linksetActivityLock) |
||
230 | { |
||
231 | foreach (BSLinkInfo po in m_children.Values) |
||
232 | { |
||
233 | if (action(po)) |
||
234 | break; |
||
235 | } |
||
236 | } |
||
237 | return ret; |
||
238 | } |
||
239 | |||
240 | // Check the type of the link and return 'true' if the link is flexible and the |
||
241 | // updates from the child should be sent to the simulator so things change. |
||
242 | public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) |
||
243 | { |
||
244 | bool ret = false; |
||
245 | |||
246 | BSLinkInfo linkInfo; |
||
247 | if (m_children.TryGetValue(child, out linkInfo)) |
||
248 | { |
||
249 | ret = linkInfo.ShouldUpdateChildProperties(); |
||
250 | } |
||
251 | |||
252 | return ret; |
||
253 | } |
||
254 | |||
255 | // Called after a simulation step to post a collision with this object. |
||
256 | // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have |
||
257 | // anything to add for the collision and it should be passed through normal processing. |
||
258 | // Default processing for a linkset. |
||
259 | public virtual bool HandleCollide(uint collidingWith, BSPhysObject collidee, |
||
260 | OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) |
||
261 | { |
||
262 | bool ret = false; |
||
263 | |||
264 | // prims in the same linkset cannot collide with each other |
||
265 | BSPrimLinkable convCollidee = collidee as BSPrimLinkable; |
||
266 | if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) |
||
267 | { |
||
268 | // By returning 'true', we tell the caller the collision has been 'handled' so it won't |
||
269 | // do anything about this collision and thus, effectivily, ignoring the collision. |
||
270 | ret = true; |
||
271 | } |
||
272 | else |
||
273 | { |
||
274 | // Not a collision between members of the linkset. Must be a real collision. |
||
275 | // So the linkset root can know if there is a collision anywhere in the linkset. |
||
276 | LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; |
||
277 | } |
||
278 | |||
279 | return ret; |
||
280 | } |
||
281 | |||
282 | // I am the root of a linkset and a new child is being added |
||
283 | // Called while LinkActivity is locked. |
||
284 | protected abstract void AddChildToLinkset(BSPrimLinkable child); |
||
285 | |||
286 | // I am the root of a linkset and one of my children is being removed. |
||
287 | // Safe to call even if the child is not really in my linkset. |
||
288 | protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); |
||
289 | |||
290 | // When physical properties are changed the linkset needs to recalculate |
||
291 | // its internal properties. |
||
292 | // May be called at runtime or taint-time. |
||
293 | public virtual void Refresh(BSPrimLinkable requestor) |
||
294 | { |
||
295 | LinksetMass = ComputeLinksetMass(); |
||
296 | } |
||
297 | |||
298 | // Flag denoting the linkset is in the process of being rebuilt. |
||
299 | // Used to know not the schedule a rebuild in the middle of a rebuild. |
||
300 | protected bool Rebuilding { get; set; } |
||
301 | |||
302 | // The object is going dynamic (physical). Do any setup necessary |
||
303 | // for a dynamic linkset. |
||
304 | // Only the state of the passed object can be modified. The rest of the linkset |
||
305 | // has not yet been fully constructed. |
||
306 | // Return 'true' if any properties updated on the passed object. |
||
307 | // Called at taint-time! |
||
308 | public abstract bool MakeDynamic(BSPrimLinkable child); |
||
309 | |||
310 | // The object is going static (non-physical). Do any setup necessary |
||
311 | // for a static linkset. |
||
312 | // Return 'true' if any properties updated on the passed object. |
||
313 | // Called at taint-time! |
||
314 | public abstract bool MakeStatic(BSPrimLinkable child); |
||
315 | |||
316 | // Called when a parameter update comes from the physics engine for any object |
||
317 | // of the linkset is received. |
||
318 | // Passed flag is update came from physics engine (true) or the user (false). |
||
319 | // Called at taint-time!! |
||
320 | public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); |
||
321 | |||
322 | // Routine used when rebuilding the body of the root of the linkset |
||
323 | // Destroy all the constraints have have been made to root. |
||
324 | // This is called when the root body is changing. |
||
325 | // Returns 'true' of something was actually removed and would need restoring |
||
326 | // Called at taint-time!! |
||
327 | public abstract bool RemoveDependencies(BSPrimLinkable child); |
||
328 | |||
329 | // ================================================================ |
||
330 | // Some physical setting happen to all members of the linkset |
||
331 | public virtual void SetPhysicalFriction(float friction) |
||
332 | { |
||
333 | ForEachMember((member) => |
||
334 | { |
||
335 | if (member.PhysBody.HasPhysicalBody) |
||
336 | m_physicsScene.PE.SetFriction(member.PhysBody, friction); |
||
337 | return false; // 'false' says to continue looping |
||
338 | } |
||
339 | ); |
||
340 | } |
||
341 | public virtual void SetPhysicalRestitution(float restitution) |
||
342 | { |
||
343 | ForEachMember((member) => |
||
344 | { |
||
345 | if (member.PhysBody.HasPhysicalBody) |
||
346 | m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); |
||
347 | return false; // 'false' says to continue looping |
||
348 | } |
||
349 | ); |
||
350 | } |
||
351 | public virtual void SetPhysicalGravity(OMV.Vector3 gravity) |
||
352 | { |
||
353 | ForEachMember((member) => |
||
354 | { |
||
355 | if (member.PhysBody.HasPhysicalBody) |
||
356 | m_physicsScene.PE.SetGravity(member.PhysBody, gravity); |
||
357 | return false; // 'false' says to continue looping |
||
358 | } |
||
359 | ); |
||
360 | } |
||
361 | public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) |
||
362 | { |
||
363 | ForEachMember((member) => |
||
364 | { |
||
365 | if (member.PhysBody.HasPhysicalBody) |
||
366 | { |
||
367 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); |
||
368 | member.Inertia = inertia * inertiaFactor; |
||
369 | m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); |
||
370 | m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); |
||
371 | DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); |
||
372 | |||
373 | } |
||
374 | return false; // 'false' says to continue looping |
||
375 | } |
||
376 | ); |
||
377 | } |
||
378 | public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) |
||
379 | { |
||
380 | ForEachMember((member) => |
||
381 | { |
||
382 | if (member.PhysBody.HasPhysicalBody) |
||
383 | m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); |
||
384 | return false; // 'false' says to continue looping |
||
385 | } |
||
386 | ); |
||
387 | } |
||
388 | public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) |
||
389 | { |
||
390 | ForEachMember((member) => |
||
391 | { |
||
392 | if (member.PhysBody.HasPhysicalBody) |
||
393 | m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); |
||
394 | return false; // 'false' says to continue looping |
||
395 | } |
||
396 | ); |
||
397 | } |
||
398 | public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) |
||
399 | { |
||
400 | ForEachMember((member) => |
||
401 | { |
||
402 | if (member.PhysBody.HasPhysicalBody) |
||
403 | m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); |
||
404 | return false; // 'false' says to continue looping |
||
405 | } |
||
406 | ); |
||
407 | } |
||
408 | // ================================================================ |
||
409 | protected virtual float ComputeLinksetMass() |
||
410 | { |
||
411 | float mass = LinksetRoot.RawMass; |
||
412 | if (HasAnyChildren) |
||
413 | { |
||
414 | lock (m_linksetActivityLock) |
||
415 | { |
||
416 | foreach (BSPrimLinkable bp in m_children.Keys) |
||
417 | { |
||
418 | mass += bp.RawMass; |
||
419 | } |
||
420 | } |
||
421 | } |
||
422 | return mass; |
||
423 | } |
||
424 | |||
425 | // Computes linkset's center of mass in world coordinates. |
||
426 | protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() |
||
427 | { |
||
428 | OMV.Vector3 com; |
||
429 | lock (m_linksetActivityLock) |
||
430 | { |
||
431 | com = LinksetRoot.Position * LinksetRoot.RawMass; |
||
432 | float totalMass = LinksetRoot.RawMass; |
||
433 | |||
434 | foreach (BSPrimLinkable bp in m_children.Keys) |
||
435 | { |
||
436 | com += bp.Position * bp.RawMass; |
||
437 | totalMass += bp.RawMass; |
||
438 | } |
||
439 | if (totalMass != 0f) |
||
440 | com /= totalMass; |
||
441 | } |
||
442 | |||
443 | return com; |
||
444 | } |
||
445 | |||
446 | protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() |
||
447 | { |
||
448 | OMV.Vector3 com; |
||
449 | lock (m_linksetActivityLock) |
||
450 | { |
||
451 | com = LinksetRoot.Position; |
||
452 | |||
453 | foreach (BSPrimLinkable bp in m_children.Keys) |
||
454 | { |
||
455 | com += bp.Position; |
||
456 | } |
||
457 | com /= (m_children.Count + 1); |
||
458 | } |
||
459 | |||
460 | return com; |
||
461 | } |
||
462 | |||
463 | #region Extension |
||
464 | public virtual object Extension(string pFunct, params object[] pParams) |
||
465 | { |
||
466 | return null; |
||
467 | } |
||
468 | #endregion // Extension |
||
469 | |||
470 | // Invoke the detailed logger and output something if it's enabled. |
||
471 | protected void DetailLog(string msg, params Object[] args) |
||
472 | { |
||
473 | if (m_physicsScene.PhysicsLogging.Enabled) |
||
474 | m_physicsScene.DetailLog(msg, args); |
||
475 | } |
||
476 | } |
||
477 | } |