diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 393 |
1 files changed, 153 insertions, 240 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index e05562a..8f12189 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,103 +35,78 @@ using OMV = OpenMetaverse; | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | 37 | ||
38 | // When a child is linked, the relationship position of the child to the parent | 38 | public sealed class BSLinksetCompound : BSLinkset |
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | 39 | { |
43 | public int Index; | 40 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
44 | public OMV.Vector3 OffsetFromRoot; | 41 | |
45 | public OMV.Vector3 OffsetFromCenterOfMass; | 42 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) |
46 | public OMV.Quaternion OffsetRot; | 43 | : base(scene, parent) |
47 | public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) | ||
48 | { | 44 | { |
49 | Index = indx; | 45 | LinksetImpl = LinksetImplementation.Compound; |
50 | OffsetFromRoot = p; | ||
51 | OffsetFromCenterOfMass = p; | ||
52 | OffsetRot = r; | ||
53 | } | 46 | } |
54 | // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) | 47 | |
55 | public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) | 48 | // ================================================================ |
49 | // Changing the physical property of the linkset only needs to change the root | ||
50 | public override void SetPhysicalFriction(float friction) | ||
56 | { | 51 | { |
57 | // Each child position and rotation is given relative to the center-of-mass. | 52 | if (LinksetRoot.PhysBody.HasPhysicalBody) |
58 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); | 53 | m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); |
59 | OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; | ||
60 | OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; | ||
61 | OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; | ||
62 | |||
63 | // Save relative position for recomputing child's world position after moving linkset. | ||
64 | Index = indx; | ||
65 | OffsetFromRoot = displacementFromRoot; | ||
66 | OffsetFromCenterOfMass = displacementFromCOM; | ||
67 | OffsetRot = displacementRot; | ||
68 | } | 54 | } |
69 | public override void Clear() | 55 | public override void SetPhysicalRestitution(float restitution) |
70 | { | 56 | { |
71 | Index = 0; | 57 | if (LinksetRoot.PhysBody.HasPhysicalBody) |
72 | OffsetFromRoot = OMV.Vector3.Zero; | 58 | m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); |
73 | OffsetFromCenterOfMass = OMV.Vector3.Zero; | ||
74 | OffsetRot = OMV.Quaternion.Identity; | ||
75 | } | 59 | } |
76 | public override string ToString() | 60 | public override void SetPhysicalGravity(OMV.Vector3 gravity) |
77 | { | 61 | { |
78 | StringBuilder buff = new StringBuilder(); | 62 | if (LinksetRoot.PhysBody.HasPhysicalBody) |
79 | buff.Append("<i="); | 63 | m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); |
80 | buff.Append(Index.ToString()); | ||
81 | buff.Append(",p="); | ||
82 | buff.Append(OffsetFromRoot.ToString()); | ||
83 | buff.Append(",m="); | ||
84 | buff.Append(OffsetFromCenterOfMass.ToString()); | ||
85 | buff.Append(",r="); | ||
86 | buff.Append(OffsetRot.ToString()); | ||
87 | buff.Append(">"); | ||
88 | return buff.ToString(); | ||
89 | } | 64 | } |
90 | }; | 65 | public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) |
91 | |||
92 | public sealed class BSLinksetCompound : BSLinkset | ||
93 | { | ||
94 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
95 | |||
96 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) | ||
97 | : base(scene, parent) | ||
98 | { | 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); | ||
99 | } | 71 | } |
100 | 72 | public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) | |
101 | // For compound implimented linksets, if there are children, use compound shape for the root. | 73 | { |
102 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPrimLinkable requestor) | 74 | if (LinksetRoot.PhysBody.HasPhysicalBody) |
103 | { | 75 | m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); |
104 | // Returning 'unknown' means we don't have a preference. | 76 | } |
105 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 77 | public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) |
106 | if (IsRoot(requestor) && HasAnyChildren) | 78 | { |
107 | { | 79 | if (LinksetRoot.PhysBody.HasPhysicalBody) |
108 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | 80 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); |
109 | } | ||
110 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
111 | return ret; | ||
112 | } | 81 | } |
82 | public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
83 | { | ||
84 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
85 | m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
86 | } | ||
87 | // ================================================================ | ||
113 | 88 | ||
114 | // When physical properties are changed the linkset needs to recalculate | 89 | // When physical properties are changed the linkset needs to recalculate |
115 | // its internal properties. | 90 | // its internal properties. |
116 | public override void Refresh(BSPrimLinkable requestor) | 91 | public override void Refresh(BSPrimLinkable requestor) |
117 | { | 92 | { |
118 | base.Refresh(requestor); | ||
119 | |||
120 | // Something changed so do the rebuilding thing | 93 | // Something changed so do the rebuilding thing |
121 | // ScheduleRebuild(); | 94 | ScheduleRebuild(requestor); |
95 | base.Refresh(requestor); | ||
122 | } | 96 | } |
123 | 97 | ||
124 | // Schedule a refresh to happen after all the other taint processing. | 98 | // Schedule a refresh to happen after all the other taint processing. |
125 | private void ScheduleRebuild(BSPrimLinkable requestor) | 99 | private void ScheduleRebuild(BSPrimLinkable requestor) |
126 | { | 100 | { |
127 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | 101 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
128 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | 102 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
103 | |||
129 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | 104 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
130 | // If already rebuilding, don't request another rebuild. | 105 | // If already rebuilding, don't request another rebuild. |
131 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | 106 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. |
132 | if (!Rebuilding && HasAnyChildren) | 107 | if (!Rebuilding && HasAnyChildren) |
133 | { | 108 | { |
134 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 109 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
135 | { | 110 | { |
136 | if (HasAnyChildren) | 111 | if (HasAnyChildren) |
137 | RecomputeLinksetCompound(); | 112 | RecomputeLinksetCompound(); |
@@ -151,47 +126,24 @@ public sealed class BSLinksetCompound : BSLinkset | |||
151 | if (IsRoot(child)) | 126 | if (IsRoot(child)) |
152 | { | 127 | { |
153 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 128 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
154 | ScheduleRebuild(LinksetRoot); | 129 | Refresh(LinksetRoot); |
155 | } | ||
156 | else | ||
157 | { | ||
158 | // The origional prims are removed from the world as the shape of the root compound | ||
159 | // shape takes over. | ||
160 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
161 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
162 | // We don't want collisions from the old linkset children. | ||
163 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
164 | |||
165 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
166 | |||
167 | ret = true; | ||
168 | } | 130 | } |
169 | return ret; | 131 | return ret; |
170 | } | 132 | } |
171 | 133 | ||
172 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 134 | // The object is going static (non-physical). We do not do anything for static linksets. |
173 | // Return 'true' if any properties updated on the passed object. | 135 | // Return 'true' if any properties updated on the passed object. |
174 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
175 | // world if it is a static linkset. | ||
176 | // Called at taint-time! | 136 | // Called at taint-time! |
177 | public override bool MakeStatic(BSPrimLinkable child) | 137 | public override bool MakeStatic(BSPrimLinkable child) |
178 | { | 138 | { |
179 | bool ret = false; | 139 | bool ret = false; |
140 | |||
180 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 141 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
142 | child.ClearDisplacement(); | ||
181 | if (IsRoot(child)) | 143 | if (IsRoot(child)) |
182 | { | 144 | { |
183 | ScheduleRebuild(LinksetRoot); | 145 | // Schedule a rebuild to verify that the root shape is set to the real shape. |
184 | } | 146 | Refresh(LinksetRoot); |
185 | else | ||
186 | { | ||
187 | // The non-physical children can come back to life. | ||
188 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
189 | |||
190 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
191 | |||
192 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
193 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
194 | ret = true; | ||
195 | } | 147 | } |
196 | return ret; | 148 | return ret; |
197 | } | 149 | } |
@@ -200,13 +152,20 @@ public sealed class BSLinksetCompound : BSLinkset | |||
200 | // Called at taint-time. | 152 | // Called at taint-time. |
201 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | 153 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) |
202 | { | 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 | |||
203 | // The user moving a child around requires the rebuilding of the linkset compound shape | 162 | // The user moving a child around requires the rebuilding of the linkset compound shape |
204 | // One problem is this happens when a border is crossed -- the simulator implementation | 163 | // One problem is this happens when a border is crossed -- the simulator implementation |
205 | // stores the position into the group which causes the move of the object | 164 | // stores the position into the group which causes the move of the object |
206 | // but it also means all the child positions get updated. | 165 | // but it also means all the child positions get updated. |
207 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | 166 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
208 | // region before bothering to do a rebuild. | 167 | // region before bothering to do a rebuild. |
209 | if (!IsRoot(updated) && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | 168 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
210 | { | 169 | { |
211 | // If a child of the linkset is updating only the position or rotation, that can be done | 170 | // If a child of the linkset is updating only the position or rotation, that can be done |
212 | // without rebuilding the linkset. | 171 | // without rebuilding the linkset. |
@@ -218,22 +177,22 @@ public sealed class BSLinksetCompound : BSLinkset | |||
218 | // and that is caused by us updating the object. | 177 | // and that is caused by us updating the object. |
219 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | 178 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) |
220 | { | 179 | { |
221 | // Find the physical instance of the child | 180 | // Find the physical instance of the child |
222 | if (LinksetRoot.PhysShape.HasPhysicalShape && PhysicsScene.PE.IsCompound(LinksetRoot.PhysShape)) | 181 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) |
223 | { | 182 | { |
224 | // It is possible that the linkset is still under construction and the child is not yet | 183 | // It is possible that the linkset is still under construction and the child is not yet |
225 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | 184 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will |
226 | // build the whole thing with the new position or rotation. | 185 | // build the whole thing with the new position or rotation. |
227 | // The index must be checked because Bullet references the child array but does no validity | 186 | // The index must be checked because Bullet references the child array but does no validity |
228 | // checking of the child index passed. | 187 | // checking of the child index passed. |
229 | int numLinksetChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape); | 188 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); |
230 | if (updated.LinksetChildIndex < numLinksetChildren) | 189 | if (updated.LinksetChildIndex < numLinksetChildren) |
231 | { | 190 | { |
232 | BulletShape linksetChildShape = PhysicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape, updated.LinksetChildIndex); | 191 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); |
233 | if (linksetChildShape.HasPhysicalShape) | 192 | if (linksetChildShape.HasPhysicalShape) |
234 | { | 193 | { |
235 | // Found the child shape within the compound shape | 194 | // Found the child shape within the compound shape |
236 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, updated.LinksetChildIndex, | 195 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, |
237 | updated.RawPosition - LinksetRoot.RawPosition, | 196 | updated.RawPosition - LinksetRoot.RawPosition, |
238 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | 197 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), |
239 | true /* shouldRecalculateLocalAabb */); | 198 | true /* shouldRecalculateLocalAabb */); |
@@ -267,83 +226,29 @@ public sealed class BSLinksetCompound : BSLinkset | |||
267 | // there will already be a rebuild scheduled. | 226 | // there will already be a rebuild scheduled. |
268 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | 227 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", |
269 | updated.LocalID, whichUpdated); | 228 | updated.LocalID, whichUpdated); |
270 | updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. | 229 | Refresh(updated); |
271 | ScheduleRebuild(updated); | ||
272 | } | 230 | } |
273 | } | 231 | } |
274 | } | 232 | } |
275 | } | 233 | } |
276 | 234 | ||
277 | // Routine called when rebuilding the body of some member of the linkset. | 235 | // Routine called when rebuilding the body of some member of the linkset. |
278 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | 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. | ||
279 | // Returns 'true' of something was actually removed and would need restoring | 238 | // Returns 'true' of something was actually removed and would need restoring |
280 | // Called at taint-time!! | 239 | // Called at taint-time!! |
281 | public override bool RemoveBodyDependencies(BSPrimLinkable child) | 240 | public override bool RemoveDependencies(BSPrimLinkable child) |
282 | { | 241 | { |
283 | bool ret = false; | 242 | bool ret = false; |
284 | 243 | ||
285 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 244 | DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
286 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | 245 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
287 | 246 | ||
288 | if (!IsRoot(child)) | 247 | Refresh(child); |
289 | { | ||
290 | // Because it is a convenient time, recompute child world position and rotation based on | ||
291 | // its position in the linkset. | ||
292 | RecomputeChildWorldPosition(child, true /* inTaintTime */); | ||
293 | child.LinksetInfo = null; | ||
294 | } | ||
295 | |||
296 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
297 | // the linkset is being rebuilt. | ||
298 | // InternalRefresh(LinksetRoot); | ||
299 | 248 | ||
300 | return ret; | 249 | return ret; |
301 | } | 250 | } |
302 | 251 | ||
303 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
304 | // root shape. The linkset then moves around but this does not move the actual child | ||
305 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
306 | private void RecomputeChildWorldPosition(BSPrimLinkable child, bool inTaintTime) | ||
307 | { | ||
308 | // For the moment (20130201), disable this computation (converting the child physical addr back to | ||
309 | // a region address) until we have a good handle on center-of-mass offsets and what the physics | ||
310 | // engine moving a child actually means. | ||
311 | // The simulator keeps track of where children should be as the linkset moves. Setting | ||
312 | // the pos/rot here does not effect that knowledge as there is no good way for the | ||
313 | // physics engine to send the simulator an update for a child. | ||
314 | |||
315 | /* | ||
316 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
317 | if (lci != null) | ||
318 | { | ||
319 | if (inTaintTime) | ||
320 | { | ||
321 | OMV.Vector3 oldPos = child.RawPosition; | ||
322 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
323 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
324 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
325 | child.LocalID, oldPos, lci, child.RawPosition); | ||
326 | } | ||
327 | else | ||
328 | { | ||
329 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
330 | child.Position = LinksetRoot.RawPosition + lci.OffsetFromRoot; | ||
331 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
332 | } | ||
333 | } | ||
334 | else | ||
335 | { | ||
336 | // This happens when children have been added to the linkset but the linkset | ||
337 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
338 | // and then changing properties of the children (makePhysical, for instance) | ||
339 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
340 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
341 | // LogHeader, child.LocalID); | ||
342 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
343 | } | ||
344 | */ | ||
345 | } | ||
346 | |||
347 | // ================================================================ | 252 | // ================================================================ |
348 | 253 | ||
349 | // Add a new child to the linkset. | 254 | // Add a new child to the linkset. |
@@ -352,19 +257,19 @@ public sealed class BSLinksetCompound : BSLinkset | |||
352 | { | 257 | { |
353 | if (!HasChild(child)) | 258 | if (!HasChild(child)) |
354 | { | 259 | { |
355 | m_children.Add(child); | 260 | m_children.Add(child, new BSLinkInfo(child)); |
356 | 261 | ||
357 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 262 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
358 | 263 | ||
359 | // Rebuild the compound shape with the new child shape included | 264 | // Rebuild the compound shape with the new child shape included |
360 | ScheduleRebuild(child); | 265 | Refresh(child); |
361 | } | 266 | } |
362 | return; | 267 | return; |
363 | } | 268 | } |
364 | 269 | ||
365 | // Remove the specified child from the linkset. | 270 | // Remove the specified child from the linkset. |
366 | // Safe to call even if the child is not really in the linkset. | 271 | // Safe to call even if the child is not really in the linkset. |
367 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) | 272 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) |
368 | { | 273 | { |
369 | child.ClearDisplacement(); | 274 | child.ClearDisplacement(); |
370 | 275 | ||
@@ -376,19 +281,17 @@ public sealed class BSLinksetCompound : BSLinkset | |||
376 | child.LocalID, child.PhysBody.AddrString); | 281 | child.LocalID, child.PhysBody.AddrString); |
377 | 282 | ||
378 | // Cause the child's body to be rebuilt and thus restored to normal operation | 283 | // Cause the child's body to be rebuilt and thus restored to normal operation |
379 | RecomputeChildWorldPosition(child, false); | 284 | child.ForceBodyShapeRebuild(inTaintTime); |
380 | child.LinksetInfo = null; | ||
381 | child.ForceBodyShapeRebuild(false); | ||
382 | 285 | ||
383 | if (!HasAnyChildren) | 286 | if (!HasAnyChildren) |
384 | { | 287 | { |
385 | // The linkset is now empty. The root needs rebuilding. | 288 | // The linkset is now empty. The root needs rebuilding. |
386 | LinksetRoot.ForceBodyShapeRebuild(false); | 289 | LinksetRoot.ForceBodyShapeRebuild(inTaintTime); |
387 | } | 290 | } |
388 | else | 291 | else |
389 | { | 292 | { |
390 | // Rebuild the compound shape with the child removed | 293 | // Rebuild the compound shape with the child removed |
391 | ScheduleRebuild(LinksetRoot); | 294 | Refresh(LinksetRoot); |
392 | } | 295 | } |
393 | } | 296 | } |
394 | return; | 297 | return; |
@@ -399,108 +302,118 @@ public sealed class BSLinksetCompound : BSLinkset | |||
399 | // Constraint linksets are rebuilt every time. | 302 | // Constraint linksets are rebuilt every time. |
400 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 303 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
401 | // Called at taint time!! | 304 | // Called at taint time!! |
402 | private bool disableCOM = true; // DEBUG DEBUG: disable until we get this debugged | 305 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape |
403 | private void RecomputeLinksetCompound() | 306 | private void RecomputeLinksetCompound() |
404 | { | 307 | { |
405 | try | 308 | try |
406 | { | 309 | { |
407 | // Suppress rebuilding while rebuilding. (We know rebuilding is on only one thread.) | ||
408 | Rebuilding = true; | 310 | Rebuilding = true; |
409 | 311 | ||
410 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 312 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set |
411 | LinksetRoot.ForceBodyShapeRebuild(true /* inTaintTime */); | 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); | ||
412 | 319 | ||
413 | // The center of mass for the linkset is the geometric center of the group. | 320 | // There is no reason to build all this physical stuff for a non-physical or empty linkset. |
414 | // Compute a displacement for each component so it is relative to the center-of-mass. | 321 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) |
415 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
416 | OMV.Vector3 centerOfMassW = LinksetRoot.RawPosition; | ||
417 | if (!disableCOM) // DEBUG DEBUG | ||
418 | { | 322 | { |
419 | // Compute a center-of-mass in world coordinates. | 323 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); |
420 | centerOfMassW = ComputeLinksetCenterOfMass(); | 324 | return; // Note the 'finally' clause at the botton which will get executed. |
421 | } | 325 | } |
422 | 326 | ||
423 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 327 | // Get a new compound shape to build the linkset shape in. |
424 | 328 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | |
425 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
426 | OMV.Vector3 centerDisplacement = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
427 | LinksetRoot.SetEffectiveCenterOfMassW(centerDisplacement); | ||
428 | 329 | ||
429 | // This causes the physical position of the root prim to be offset to accomodate for the displacements | 330 | // Compute a displacement for each component so it is relative to the center-of-mass. |
430 | LinksetRoot.ForcePosition = LinksetRoot.RawPosition; | 331 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass |
332 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); | ||
431 | 333 | ||
432 | // Update the local transform for the root child shape so it is offset from the <0,0,0> which is COM | 334 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); |
433 | PhysicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape, 0 /* childIndex */, | 335 | OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; |
434 | -centerDisplacement, | ||
435 | OMV.Quaternion.Identity, // LinksetRoot.RawOrientation, | ||
436 | false /* shouldRecalculateLocalAabb (is done later after linkset built) */); | ||
437 | 336 | ||
438 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,com={1},rootPos={2},centerDisp={3}", | 337 | // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass |
439 | LinksetRoot.LocalID, centerOfMassW, LinksetRoot.RawPosition, centerDisplacement); | 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 | } | ||
440 | 350 | ||
441 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 351 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", |
442 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 352 | LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); |
443 | 353 | ||
444 | // Add a shape for each of the other children in the linkset | 354 | // Add the shapes of all the components of the linkset |
445 | int memberIndex = 1; | 355 | int memberIndex = 1; |
446 | ForEachMember(delegate(BSPrimLinkable cPrim) | 356 | ForEachMember((cPrim) => |
447 | { | 357 | { |
448 | if (IsRoot(cPrim)) | 358 | if (IsRoot(cPrim)) |
449 | { | 359 | { |
360 | // Root shape is always index zero. | ||
450 | cPrim.LinksetChildIndex = 0; | 361 | cPrim.LinksetChildIndex = 0; |
451 | } | 362 | } |
452 | else | 363 | else |
453 | { | 364 | { |
454 | cPrim.LinksetChildIndex = memberIndex; | 365 | cPrim.LinksetChildIndex = memberIndex; |
366 | memberIndex++; | ||
367 | } | ||
455 | 368 | ||
456 | if (cPrim.PhysShape.isNativeShape) | 369 | // Get a reference to the shape of the child for adding of that shape to the linkset compound shape |
457 | { | 370 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); |
458 | // A native shape is turned into a hull collision shape because native | ||
459 | // shapes are not shared so we have to hullify it so it will be tracked | ||
460 | // and freed at the correct time. This also solves the scaling problem | ||
461 | // (native shapes scale but hull/meshes are assumed to not be). | ||
462 | // TODO: decide of the native shape can just be used in the compound shape. | ||
463 | // Use call to CreateGeomNonSpecial(). | ||
464 | BulletShape saveShape = cPrim.PhysShape; | ||
465 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
466 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
467 | BulletShape newShape = cPrim.PhysShape; | ||
468 | cPrim.PhysShape = saveShape; | ||
469 | |||
470 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
471 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
472 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
473 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
474 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, newShape, offsetPos, offsetRot); | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
479 | // The reference count added here will be decremented when the compound shape | ||
480 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
481 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
482 | { | ||
483 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
484 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
485 | } | ||
486 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacement; | ||
487 | OMV.Quaternion offsetRot = cPrim.RawOrientation * invRootOrientation; | ||
488 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
489 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addNonNative,indx={1},rShape={2},cShape={3},offPos={4},offRot={5}", | ||
490 | LinksetRoot.LocalID, memberIndex, LinksetRoot.PhysShape, cPrim.PhysShape, offsetPos, offsetRot); | ||
491 | 371 | ||
492 | } | 372 | // Offset the child shape from the center-of-mass and rotate it to vehicle relative. |
493 | memberIndex++; | 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; | ||
494 | } | 389 | } |
390 | |||
495 | return false; // 'false' says to move onto the next child in the list | 391 | return false; // 'false' says to move onto the next child in the list |
496 | }); | 392 | }); |
497 | 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 | |||
498 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 404 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
499 | LinksetMass = ComputeLinksetMass(); | 405 | LinksetMass = ComputeLinksetMass(); |
500 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 406 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
501 | 407 | ||
502 | // Enable the physical position updator to return the position and rotation of the root shape | 408 | if (UseBulletSimRootOffsetHack) |
503 | PhysicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | 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 | } | ||
504 | } | 417 | } |
505 | finally | 418 | finally |
506 | { | 419 | { |
@@ -508,7 +421,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
508 | } | 421 | } |
509 | 422 | ||
510 | // See that the Aabb surrounds the new shape | 423 | // See that the Aabb surrounds the new shape |
511 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | 424 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); |
512 | } | 425 | } |
513 | } | 426 | } |
514 | } \ No newline at end of file | 427 | } \ No newline at end of file |