diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 238 |
1 files changed, 175 insertions, 63 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 1f7c398..2189468 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -32,18 +32,43 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | |||
36 | // When a child is linked, the relationship position of the child to the parent | ||
37 | // is remembered so the child's world position can be recomputed when it is | ||
38 | // removed from the linkset. | ||
39 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
40 | { | ||
41 | public OMV.Vector3 OffsetPos; | ||
42 | public OMV.Quaternion OffsetRot; | ||
43 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | ||
44 | { | ||
45 | OffsetPos = p; | ||
46 | OffsetRot = r; | ||
47 | } | ||
48 | public override string ToString() | ||
49 | { | ||
50 | StringBuilder buff = new StringBuilder(); | ||
51 | buff.Append("<p="); | ||
52 | buff.Append(OffsetPos.ToString()); | ||
53 | buff.Append(",r="); | ||
54 | buff.Append(OffsetRot.ToString()); | ||
55 | buff.Append(">"); | ||
56 | return buff.ToString(); | ||
57 | } | ||
58 | }; | ||
59 | |||
35 | public sealed class BSLinksetCompound : BSLinkset | 60 | public sealed class BSLinksetCompound : BSLinkset |
36 | { | 61 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 62 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
38 | 63 | ||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | 64 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 65 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 66 | } |
43 | 67 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 68 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 69 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 70 | { |
71 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 72 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 73 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 74 | { |
@@ -55,23 +80,27 @@ public sealed class BSLinksetCompound : BSLinkset | |||
55 | 80 | ||
56 | // When physical properties are changed the linkset needs to recalculate | 81 | // When physical properties are changed the linkset needs to recalculate |
57 | // its internal properties. | 82 | // its internal properties. |
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | 83 | public override void Refresh(BSPhysObject requestor) |
61 | { | 84 | { |
62 | // External request for Refresh (from BSPrim) doesn't need to do anything | 85 | // External request for Refresh (from BSPrim) doesn't need to do anything |
63 | // InternalRefresh(requestor); | 86 | // InternalRefresh(requestor); |
64 | } | 87 | } |
65 | 88 | ||
89 | // Schedule a refresh to happen after all the other taint processing. | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 90 | private void InternalRefresh(BSPhysObject requestor) |
67 | { | 91 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 92 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1},rebuilding={2}", |
69 | // Queue to happen after all the other taint processing | 93 | LinksetRoot.LocalID, requestor.LocalID, Rebuilding); |
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 94 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
95 | // If already rebuilding, don't request another rebuild. | ||
96 | if (!Rebuilding) | ||
71 | { | 97 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 98 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() |
73 | RecomputeLinksetCompound(); | 99 | { |
74 | }); | 100 | if (IsRoot(requestor) && HasAnyChildren) |
101 | RecomputeLinksetCompound(); | ||
102 | }); | ||
103 | } | ||
75 | } | 104 | } |
76 | 105 | ||
77 | // The object is going dynamic (physical). Do any setup necessary | 106 | // The object is going dynamic (physical). Do any setup necessary |
@@ -84,12 +113,24 @@ public sealed class BSLinksetCompound : BSLinkset | |||
84 | { | 113 | { |
85 | bool ret = false; | 114 | bool ret = false; |
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 115 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
87 | if (!IsRoot(child)) | 116 | if (IsRoot(child)) |
117 | { | ||
118 | // The root is going dynamic. Make sure mass is properly set. | ||
119 | m_mass = ComputeLinksetMass(); | ||
120 | if (HasAnyChildren) | ||
121 | InternalRefresh(LinksetRoot); | ||
122 | } | ||
123 | else | ||
88 | { | 124 | { |
89 | // The origional prims are removed from the world as the shape of the root compound | 125 | // The origional prims are removed from the world as the shape of the root compound |
90 | // shape takes over. | 126 | // shape takes over. |
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 127 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 128 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
129 | // We don't want collisions from the old linkset children. | ||
130 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
131 | |||
132 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
133 | |||
93 | ret = true; | 134 | ret = true; |
94 | } | 135 | } |
95 | return ret; | 136 | return ret; |
@@ -104,11 +145,19 @@ public sealed class BSLinksetCompound : BSLinkset | |||
104 | { | 145 | { |
105 | bool ret = false; | 146 | bool ret = false; |
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 147 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
107 | if (!IsRoot(child)) | 148 | if (IsRoot(child)) |
149 | { | ||
150 | if (HasAnyChildren) | ||
151 | InternalRefresh(LinksetRoot); | ||
152 | } | ||
153 | else | ||
108 | { | 154 | { |
109 | // The non-physical children can come back to life. | 155 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 156 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 157 | |
158 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
159 | |||
160 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 161 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); |
113 | ret = true; | 162 | ret = true; |
114 | } | 163 | } |
@@ -146,20 +195,58 @@ public sealed class BSLinksetCompound : BSLinkset | |||
146 | 195 | ||
147 | if (!IsRoot(child)) | 196 | if (!IsRoot(child)) |
148 | { | 197 | { |
149 | // Cause the current shape to be freed and the new one to be built. | 198 | // Because it is a convenient time, recompute child world position and rotation based on |
150 | InternalRefresh(LinksetRoot); | 199 | // its position in the linkset. |
151 | ret = true; | 200 | RecomputeChildWorldPosition(child, true); |
152 | } | 201 | } |
153 | 202 | ||
203 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
204 | // the linkset is being rebuilt. | ||
205 | // InternalRefresh(LinksetRoot); | ||
206 | |||
154 | return ret; | 207 | return ret; |
155 | } | 208 | } |
156 | 209 | ||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 210 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
158 | // this routine will restore the removed constraints. | 211 | // this routine will restore the removed constraints. |
159 | // Called at taint-time!! | 212 | // Called at taint-time!! |
160 | public override void RestoreBodyDependencies(BSPrim child) | 213 | public override void RestoreBodyDependencies(BSPrim child) |
161 | { | 214 | { |
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | 215 | } |
216 | |||
217 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
218 | // root shape. The linkset then moves around but this does not move the actual child | ||
219 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
220 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
221 | { | ||
222 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
223 | if (lci != null) | ||
224 | { | ||
225 | if (inTaintTime) | ||
226 | { | ||
227 | OMV.Vector3 oldPos = child.RawPosition; | ||
228 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
229 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
230 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
231 | child.LocalID, oldPos, lci, child.RawPosition); | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
236 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
237 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
238 | } | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | // This happens when children have been added to the linkset but the linkset | ||
243 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
244 | // and then changing properties of the children (makePhysical, for instance) | ||
245 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
246 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
247 | // LogHeader, child.LocalID); | ||
248 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
249 | } | ||
163 | } | 250 | } |
164 | 251 | ||
165 | // ================================================================ | 252 | // ================================================================ |
@@ -181,7 +268,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
181 | } | 268 | } |
182 | 269 | ||
183 | // Remove the specified child from the linkset. | 270 | // Remove the specified child from the linkset. |
184 | // Safe to call even if the child is not really in my linkset. | 271 | // Safe to call even if the child is not really in the linkset. |
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 272 | protected override void RemoveChildFromLinkset(BSPhysObject child) |
186 | { | 273 | { |
187 | if (m_children.Remove(child)) | 274 | if (m_children.Remove(child)) |
@@ -192,6 +279,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 279 | child.LocalID, child.PhysBody.ptr.ToString("X")); |
193 | 280 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 281 | // Cause the child's body to be rebuilt and thus restored to normal operation |
282 | RecomputeChildWorldPosition(child, false); | ||
195 | child.ForceBodyShapeRebuild(false); | 283 | child.ForceBodyShapeRebuild(false); |
196 | 284 | ||
197 | if (!HasAnyChildren) | 285 | if (!HasAnyChildren) |
@@ -215,59 +303,83 @@ public sealed class BSLinksetCompound : BSLinkset | |||
215 | // Called at taint time!! | 303 | // Called at taint time!! |
216 | private void RecomputeLinksetCompound() | 304 | private void RecomputeLinksetCompound() |
217 | { | 305 | { |
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 306 | try |
219 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
220 | |||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | ||
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | ||
223 | |||
224 | // Add a shape for each of the other children in the linkset | ||
225 | ForEachMember(delegate(BSPhysObject cPrim) | ||
226 | { | 307 | { |
227 | if (!IsRoot(cPrim)) | 308 | // Suppress rebuilding while rebuilding |
228 | { | 309 | Rebuilding = true; |
229 | // Each child position and rotation is given relative to the root. | ||
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
233 | 310 | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 311 | // Cause the root shape to be rebuilt as a compound object with just the root in it |
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 312 | LinksetRoot.ForceBodyShapeRebuild(true); |
236 | 313 | ||
237 | if (cPrim.PhysShape.isNativeShape) | 314 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", |
238 | { | 315 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); |
239 | // Native shapes are not shared so we need to create a new one. | 316 | |
240 | // A mesh or hull is created because scale is not available on a native shape. | 317 | // Add a shape for each of the other children in the linkset |
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | 318 | ForEachMember(delegate(BSPhysObject cPrim) |
242 | BulletShape saveShape = cPrim.PhysShape; | 319 | { |
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | 320 | if (!IsRoot(cPrim)) |
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
245 | BulletShape newShape = cPrim.PhysShape; | ||
246 | cPrim.PhysShape = saveShape; | ||
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | ||
248 | } | ||
249 | else | ||
250 | { | 321 | { |
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 322 | // Compute the displacement of the child from the root of the linkset. |
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 323 | // This info is saved in the child prim so the relationship does not |
324 | // change over time and the new child position can be computed | ||
325 | // when the linkset is being disassembled (the linkset may have moved). | ||
326 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
327 | if (lci == null) | ||
253 | { | 328 | { |
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 329 | // Each child position and rotation is given relative to the root. |
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 330 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); |
331 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
332 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
333 | |||
334 | // Save relative position for recomputing child's world position after moving linkset. | ||
335 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
336 | cPrim.LinksetInfo = lci; | ||
337 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
256 | } | 338 | } |
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | ||
259 | } | ||
260 | 339 | ||
261 | // TODO: need to phantomize the child prims left behind. | 340 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", |
262 | // Maybe just destroy the children bodies and shapes and have them rebuild on unlink. | 341 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); |
263 | // Selection/deselection might cause way too many build/destructions esp. for LARGE linksets. | ||
264 | 342 | ||
265 | return false; // 'false' says to move onto the next child in the list | 343 | if (cPrim.PhysShape.isNativeShape) |
266 | }); | 344 | { |
345 | // A native shape is turning into a hull collision shape because native | ||
346 | // shapes are not shared so we have to hullify it so it will be tracked | ||
347 | // and freed at the correct time. This also solves the scaling problem | ||
348 | // (native shapes scaled but hull/meshes are assumed to not be). | ||
349 | // TODO: decide of the native shape can just be used in the compound shape. | ||
350 | // Use call to CreateGeomNonSpecial(). | ||
351 | BulletShape saveShape = cPrim.PhysShape; | ||
352 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
353 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
354 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
355 | BulletShape newShape = cPrim.PhysShape; | ||
356 | cPrim.PhysShape = saveShape; | ||
357 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
362 | // The reference count added here will be decremented when the compound shape | ||
363 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
364 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
365 | { | ||
366 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
367 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
368 | } | ||
369 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
370 | } | ||
371 | } | ||
372 | return false; // 'false' says to move onto the next child in the list | ||
373 | }); | ||
267 | 374 | ||
268 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 375 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
269 | float linksetMass = LinksetMass; | 376 | float linksetMass = LinksetMass; |
270 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 377 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); |
378 | } | ||
379 | finally | ||
380 | { | ||
381 | Rebuilding = false; | ||
382 | } | ||
271 | 383 | ||
272 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | 384 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); |
273 | 385 | ||