diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 113 |
1 files changed, 96 insertions, 17 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index bc9f9be..fe5b5e3 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -32,6 +32,31 @@ 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]"; |
@@ -44,6 +69,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 69 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 70 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 71 | { |
72 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 73 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 74 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 75 | { |
@@ -63,10 +89,10 @@ public sealed class BSLinksetCompound : BSLinkset | |||
63 | // InternalRefresh(requestor); | 89 | // InternalRefresh(requestor); |
64 | } | 90 | } |
65 | 91 | ||
92 | // Schedule a refresh to happen after all the other taint processing. | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 93 | private void InternalRefresh(BSPhysObject requestor) |
67 | { | 94 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 95 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); |
69 | // Queue to happen after all the other taint processing | ||
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 96 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() |
71 | { | 97 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 98 | if (IsRoot(requestor) && HasAnyChildren) |
@@ -108,7 +134,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
108 | { | 134 | { |
109 | // The non-physical children can come back to life. | 135 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 136 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 137 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. |
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 138 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); |
113 | ret = true; | 139 | ret = true; |
114 | } | 140 | } |
@@ -146,6 +172,10 @@ public sealed class BSLinksetCompound : BSLinkset | |||
146 | 172 | ||
147 | if (!IsRoot(child)) | 173 | if (!IsRoot(child)) |
148 | { | 174 | { |
175 | // Because it is a convenient time, recompute child world position and rotation based on | ||
176 | // its position in the linkset. | ||
177 | RecomputeChildWorldPosition(child, true); | ||
178 | |||
149 | // Cause the current shape to be freed and the new one to be built. | 179 | // Cause the current shape to be freed and the new one to be built. |
150 | InternalRefresh(LinksetRoot); | 180 | InternalRefresh(LinksetRoot); |
151 | ret = true; | 181 | ret = true; |
@@ -154,6 +184,42 @@ public sealed class BSLinksetCompound : BSLinkset | |||
154 | return ret; | 184 | return ret; |
155 | } | 185 | } |
156 | 186 | ||
187 | // When the linkset is built, the child shape is added | ||
188 | // to the compound shape relative to the root shape. The linkset then moves around but | ||
189 | // this does not move the actual child prim. The child prim's location must be recomputed | ||
190 | // based on the location of the root shape. | ||
191 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
192 | { | ||
193 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
194 | if (lci != null) | ||
195 | { | ||
196 | if (inTaintTime) | ||
197 | { | ||
198 | OMV.Vector3 oldPos = child.RawPosition; | ||
199 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
200 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
201 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
202 | child.LocalID, oldPos, lci, child.RawPosition); | ||
203 | } | ||
204 | else | ||
205 | { | ||
206 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
207 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
208 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
209 | } | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | // This happens when children have been added to the linkset but the linkset | ||
214 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
215 | // and then changing properties of the children (makePhysical, for instance) | ||
216 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
217 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
218 | // LogHeader, child.LocalID); | ||
219 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
220 | } | ||
221 | } | ||
222 | |||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 223 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
158 | // this routine will restore the removed constraints. | 224 | // this routine will restore the removed constraints. |
159 | // Called at taint-time!! | 225 | // Called at taint-time!! |
@@ -192,8 +258,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 258 | child.LocalID, child.PhysBody.ptr.ToString("X")); |
193 | 259 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 260 | // Cause the child's body to be rebuilt and thus restored to normal operation |
195 | // TODO: position and rotation must be restored because the child could have moved | 261 | RecomputeChildWorldPosition(child, false); |
196 | // based on the linkset. | ||
197 | child.ForceBodyShapeRebuild(false); | 262 | child.ForceBodyShapeRebuild(false); |
198 | 263 | ||
199 | if (!HasAnyChildren) | 264 | if (!HasAnyChildren) |
@@ -228,43 +293,57 @@ public sealed class BSLinksetCompound : BSLinkset | |||
228 | { | 293 | { |
229 | if (!IsRoot(cPrim)) | 294 | if (!IsRoot(cPrim)) |
230 | { | 295 | { |
231 | // Each child position and rotation is given relative to the root. | 296 | // Compute the displacement of the child from the root of the linkset. |
232 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 297 | // This info is saved in the child prim so the relationship does not |
233 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | 298 | // change over time and the new child position can be computed |
234 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | 299 | // when the linkset is being disassembled (the linkset may have moved). |
300 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
301 | if (lci == null) | ||
302 | { | ||
303 | // Each child position and rotation is given relative to the root. | ||
304 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
305 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
306 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
307 | |||
308 | // Save relative position for recomputing child's world position after moving linkset. | ||
309 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
310 | cPrim.LinksetInfo = lci; | ||
311 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
312 | } | ||
235 | 313 | ||
236 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 314 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", |
237 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 315 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); |
238 | 316 | ||
239 | if (cPrim.PhysShape.isNativeShape) | 317 | if (cPrim.PhysShape.isNativeShape) |
240 | { | 318 | { |
241 | // A native shape is turning into a null collision shape because native | 319 | // A native shape is turning into a hull collision shape because native |
242 | // shapes are not shared so we have to hullify it so it will be tracked | 320 | // shapes are not shared so we have to hullify it so it will be tracked |
243 | // and freed at the correct time. This also solves the scaling problem | 321 | // and freed at the correct time. This also solves the scaling problem |
244 | // (native shapes scaled but hull/meshes are assumed to not be). | 322 | // (native shapes scaled but hull/meshes are assumed to not be). |
323 | // TODO: decide of the native shape can just be used in the compound shape. | ||
324 | // Use call to CreateGeomNonSpecial(). | ||
245 | BulletShape saveShape = cPrim.PhysShape; | 325 | BulletShape saveShape = cPrim.PhysShape; |
246 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | 326 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape |
327 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
247 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | 328 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); |
248 | BulletShape newShape = cPrim.PhysShape; | 329 | BulletShape newShape = cPrim.PhysShape; |
249 | cPrim.PhysShape = saveShape; | 330 | cPrim.PhysShape = saveShape; |
250 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | 331 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos , lci.OffsetRot); |
251 | } | 332 | } |
252 | else | 333 | else |
253 | { | 334 | { |
254 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 335 | // For the shared shapes (meshes and hulls), just use the shape in the child. |
336 | // The reference count added here will be decremented when the compound shape | ||
337 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
255 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 338 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) |
256 | { | 339 | { |
257 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 340 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", |
258 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 341 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); |
259 | } | 342 | } |
260 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | 343 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos , lci.OffsetRot); |
261 | } | 344 | } |
262 | } | 345 | } |
263 | 346 | ||
264 | // TODO: need to phantomize the child prims left behind. | ||
265 | // Maybe just destroy the children bodies and shapes and have them rebuild on unlink. | ||
266 | // Selection/deselection might cause way too many build/destructions esp. for LARGE linksets. | ||
267 | |||
268 | return false; // 'false' says to move onto the next child in the list | 347 | return false; // 'false' says to move onto the next child in the list |
269 | }); | 348 | }); |
270 | 349 | ||