clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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 OpenSim.Framework;
32  
33 using OMV = OpenMetaverse;
34  
35 namespace OpenSim.Region.Physics.BulletSPlugin
36 {
37  
38 public sealed class BSLinksetCompound : BSLinkset
39 {
40 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
41  
42 public BSLinksetCompound(BSScene scene, BSPrimLinkable parent)
43 : base(scene, parent)
44 {
45 LinksetImpl = LinksetImplementation.Compound;
46 }
47  
48 // ================================================================
49 // Changing the physical property of the linkset only needs to change the root
50 public override void SetPhysicalFriction(float friction)
51 {
52 if (LinksetRoot.PhysBody.HasPhysicalBody)
53 m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction);
54 }
55 public override void SetPhysicalRestitution(float restitution)
56 {
57 if (LinksetRoot.PhysBody.HasPhysicalBody)
58 m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution);
59 }
60 public override void SetPhysicalGravity(OMV.Vector3 gravity)
61 {
62 if (LinksetRoot.PhysBody.HasPhysicalBody)
63 m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
64 }
65 public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
66 {
67 OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
68 LinksetRoot.Inertia = inertia * inertiaFactor;
69 m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
70 m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
71 }
72 public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
73 {
74 if (LinksetRoot.PhysBody.HasPhysicalBody)
75 m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
76 }
77 public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
78 {
79 if (LinksetRoot.PhysBody.HasPhysicalBody)
80 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
81 }
82 public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
83 {
84 if (LinksetRoot.PhysBody.HasPhysicalBody)
85 m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags);
86 }
87 // ================================================================
88  
89 // When physical properties are changed the linkset needs to recalculate
90 // its internal properties.
91 public override void Refresh(BSPrimLinkable requestor)
92 {
93 // Something changed so do the rebuilding thing
94 ScheduleRebuild(requestor);
95 base.Refresh(requestor);
96 }
97  
98 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPrimLinkable requestor)
100 {
101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}",
102 requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren));
103  
104 // When rebuilding, it is possible to set properties that would normally require a rebuild.
105 // If already rebuilding, don't request another rebuild.
106 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
107 if (!Rebuilding && HasAnyChildren)
108 {
109 m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
110 {
111 if (HasAnyChildren)
112 RecomputeLinksetCompound();
113 });
114 }
115 }
116  
117 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
118 // Only the state of the passed object can be modified. The rest of the linkset
119 // has not yet been fully constructed.
120 // Return 'true' if any properties updated on the passed object.
121 // Called at taint-time!
122 public override bool MakeDynamic(BSPrimLinkable child)
123 {
124 bool ret = false;
125 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
126 if (IsRoot(child))
127 {
128 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
129 Refresh(LinksetRoot);
130 }
131 return ret;
132 }
133  
134 // The object is going static (non-physical). We do not do anything for static linksets.
135 // Return 'true' if any properties updated on the passed object.
136 // Called at taint-time!
137 public override bool MakeStatic(BSPrimLinkable child)
138 {
139 bool ret = false;
140  
141 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
142 child.ClearDisplacement();
143 if (IsRoot(child))
144 {
145 // Schedule a rebuild to verify that the root shape is set to the real shape.
146 Refresh(LinksetRoot);
147 }
148 return ret;
149 }
150  
151 // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then.
152 // Called at taint-time.
153 public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated)
154 {
155 if (!LinksetRoot.IsPhysicallyActive)
156 {
157 // No reason to do this physical stuff for static linksets.
158 DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID);
159 return;
160 }
161  
162 // The user moving a child around requires the rebuilding of the linkset compound shape
163 // One problem is this happens when a border is crossed -- the simulator implementation
164 // stores the position into the group which causes the move of the object
165 // but it also means all the child positions get updated.
166 // What would cause an unnecessary rebuild so we make sure the linkset is in a
167 // region before bothering to do a rebuild.
168 if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
169 {
170 // If a child of the linkset is updating only the position or rotation, that can be done
171 // without rebuilding the linkset.
172 // If a handle for the child can be fetch, we update the child here. If a rebuild was
173 // scheduled by someone else, the rebuild will just replace this setting.
174  
175 bool updatedChild = false;
176 // Anything other than updating position or orientation usually means a physical update
177 // and that is caused by us updating the object.
178 if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0)
179 {
180 // Find the physical instance of the child
181 if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo))
182 {
183 // It is possible that the linkset is still under construction and the child is not yet
184 // inserted into the compound shape. A rebuild of the linkset in a pre-step action will
185 // build the whole thing with the new position or rotation.
186 // The index must be checked because Bullet references the child array but does no validity
187 // checking of the child index passed.
188 int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo);
189 if (updated.LinksetChildIndex < numLinksetChildren)
190 {
191 BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex);
192 if (linksetChildShape.HasPhysicalShape)
193 {
194 // Found the child shape within the compound shape
195 m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex,
196 updated.RawPosition - LinksetRoot.RawPosition,
197 updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation),
198 true /* shouldRecalculateLocalAabb */);
199 updatedChild = true;
200 DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}",
201 updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation);
202 }
203 else // DEBUG DEBUG
204 { // DEBUG DEBUG
205 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}",
206 updated.LocalID, linksetChildShape);
207 } // DEBUG DEBUG
208 }
209 else // DEBUG DEBUG
210 { // DEBUG DEBUG
211 // the child is not yet in the compound shape. This is non-fatal.
212 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}",
213 updated.LocalID, numLinksetChildren, updated.LinksetChildIndex);
214 } // DEBUG DEBUG
215 }
216 else // DEBUG DEBUG
217 { // DEBUG DEBUG
218 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID);
219 } // DEBUG DEBUG
220  
221 if (!updatedChild)
222 {
223 // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info.
224 // Note: there are several ways through this code that will not update the child if
225 // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since
226 // there will already be a rebuild scheduled.
227 DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}",
228 updated.LocalID, whichUpdated);
229 Refresh(updated);
230 }
231 }
232 }
233 }
234  
235 // Routine called when rebuilding the body of some member of the linkset.
236 // If one of the bodies is being changed, the linkset needs rebuilding.
237 // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated.
238 // Returns 'true' of something was actually removed and would need restoring
239 // Called at taint-time!!
240 public override bool RemoveDependencies(BSPrimLinkable child)
241 {
242 bool ret = false;
243  
244 DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
245 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child));
246  
247 Refresh(child);
248  
249 return ret;
250 }
251  
252 // ================================================================
253  
254 // Add a new child to the linkset.
255 // Called while LinkActivity is locked.
256 protected override void AddChildToLinkset(BSPrimLinkable child)
257 {
258 if (!HasChild(child))
259 {
260 m_children.Add(child, new BSLinkInfo(child));
261  
262 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
263  
264 // Rebuild the compound shape with the new child shape included
265 Refresh(child);
266 }
267 return;
268 }
269  
270 // Remove the specified child from the linkset.
271 // Safe to call even if the child is not really in the linkset.
272 protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime)
273 {
274 child.ClearDisplacement();
275  
276 if (m_children.Remove(child))
277 {
278 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
279 child.LocalID,
280 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
281 child.LocalID, child.PhysBody.AddrString);
282  
283 // Cause the child's body to be rebuilt and thus restored to normal operation
284 child.ForceBodyShapeRebuild(inTaintTime);
285  
286 if (!HasAnyChildren)
287 {
288 // The linkset is now empty. The root needs rebuilding.
289 LinksetRoot.ForceBodyShapeRebuild(inTaintTime);
290 }
291 else
292 {
293 // Rebuild the compound shape with the child removed
294 Refresh(LinksetRoot);
295 }
296 }
297 return;
298 }
299  
300 // Called before the simulation step to make sure the compound based linkset
301 // is all initialized.
302 // Constraint linksets are rebuilt every time.
303 // Note that this works for rebuilding just the root after a linkset is taken apart.
304 // Called at taint time!!
305 private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape
306 private void RecomputeLinksetCompound()
307 {
308 try
309 {
310 Rebuilding = true;
311  
312 // No matter what is being done, force the root prim's PhysBody and PhysShape to get set
313 // to what they should be as if the root was not in a linkset.
314 // Not that bad since we only get into this routine if there are children in the linkset and
315 // something has been updated/changed.
316 // Have to do the rebuild before checking for physical because this might be a linkset
317 // being destructed and going non-physical.
318 LinksetRoot.ForceBodyShapeRebuild(true);
319  
320 // There is no reason to build all this physical stuff for a non-physical or empty linkset.
321 if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren)
322 {
323 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID);
324 return; // Note the 'finally' clause at the botton which will get executed.
325 }
326  
327 // Get a new compound shape to build the linkset shape in.
328 BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene);
329  
330 // Compute a displacement for each component so it is relative to the center-of-mass.
331 // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass
332 OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass();
333  
334 OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation));
335 OMV.Vector3 origRootPosition = LinksetRoot.RawPosition;
336  
337 // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass
338 OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation;
339 if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass)
340 {
341 // Zero everything if center-of-mass displacement is not being done.
342 centerDisplacementV = OMV.Vector3.Zero;
343 LinksetRoot.ClearDisplacement();
344 }
345 else
346 {
347 // The actual center-of-mass could have been set by the user.
348 centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV);
349 }
350  
351 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}",
352 LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV);
353  
354 // Add the shapes of all the components of the linkset
355 int memberIndex = 1;
356 ForEachMember((cPrim) =>
357 {
358 if (IsRoot(cPrim))
359 {
360 // Root shape is always index zero.
361 cPrim.LinksetChildIndex = 0;
362 }
363 else
364 {
365 cPrim.LinksetChildIndex = memberIndex;
366 memberIndex++;
367 }
368  
369 // Get a reference to the shape of the child for adding of that shape to the linkset compound shape
370 BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim);
371  
372 // Offset the child shape from the center-of-mass and rotate it to vehicle relative.
373 OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV;
374 OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation;
375  
376 // Add the child shape to the compound shape being built
377 m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot);
378 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}",
379 LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot);
380  
381 // Since we are borrowing the shape of the child, disable the origional child body
382 if (!IsRoot(cPrim))
383 {
384 m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
385 m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION);
386 // We don't want collisions from the old linkset children.
387 m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
388 cPrim.PhysBody.collisionType = CollisionType.LinksetChild;
389 }
390  
391 return false; // 'false' says to move onto the next child in the list
392 });
393  
394 // Replace the root shape with the built compound shape.
395 // Object removed and added to world to get collision cache rebuilt for new shape.
396 LinksetRoot.PhysShape.Dereference(m_physicsScene);
397 LinksetRoot.PhysShape = linksetShape;
398 m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody);
399 m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo);
400 m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody);
401 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}",
402 LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape);
403  
404 // With all of the linkset packed into the root prim, it has the mass of everyone.
405 LinksetMass = ComputeLinksetMass();
406 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
407  
408 if (UseBulletSimRootOffsetHack)
409 {
410 // Enable the physical position updator to return the position and rotation of the root shape.
411 // This enables a feature in the C++ code to return the world coordinates of the first shape in the
412 // compound shape. This aleviates the need to offset the returned physical position by the
413 // center-of-mass offset.
414 // TODO: either debug this feature or remove it.
415 m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE);
416 }
417 }
418 finally
419 {
420 Rebuilding = false;
421 }
422  
423 // See that the Aabb surrounds the new shape
424 m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo);
425 }
426 }
427 }