diff options
author | Robert Adams | 2013-05-08 06:02:12 -0700 |
---|---|---|
committer | Robert Adams | 2013-05-08 06:02:12 -0700 |
commit | eb0687f5af127ad6195b95965ce31346f2bc0a24 (patch) | |
tree | 8888b8d4c45874c646da0b475d09bd051b33e1cc /OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |
parent | Add regression test for inventory item give, reject and subsequent trash fold... (diff) | |
download | opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.zip opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.gz opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.bz2 opensim-SC_OLD-eb0687f5af127ad6195b95965ce31346f2bc0a24.tar.xz |
vh: update BulletSim (OpenSim/Region/Physics/BulletSPlugin
and DLL/SO) to ac6dcd35fb77f118fc6c3d72cb029591306c7e99
(Mon May 6 21:10:02 2013 -0400) on top of 0.7.5-postfixes.
Diffstat (limited to '')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | 386 |
1 files changed, 211 insertions, 175 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index bd03d31..350a5d1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -35,59 +35,74 @@ using OMV = OpenMetaverse; | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
36 | { | 36 | { |
37 | 37 | ||
38 | /* | ||
38 | // When a child is linked, the relationship position of the child to the parent | 39 | // When a child is linked, the relationship position of the child to the parent |
39 | // is remembered so the child's world position can be recomputed when it is | 40 | // is remembered so the child's world position can be recomputed when it is |
40 | // removed from the linkset. | 41 | // removed from the linkset. |
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | 42 | sealed class BSLinksetCompoundInfo : BSLinksetInfo |
42 | { | 43 | { |
43 | public OMV.Vector3 OffsetPos; | 44 | public int Index; |
45 | public OMV.Vector3 OffsetFromRoot; | ||
46 | public OMV.Vector3 OffsetFromCenterOfMass; | ||
44 | public OMV.Quaternion OffsetRot; | 47 | public OMV.Quaternion OffsetRot; |
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | 48 | public BSLinksetCompoundInfo(int indx, OMV.Vector3 p, OMV.Quaternion r) |
46 | { | 49 | { |
47 | OffsetPos = p; | 50 | Index = indx; |
51 | OffsetFromRoot = p; | ||
52 | OffsetFromCenterOfMass = p; | ||
48 | OffsetRot = r; | 53 | OffsetRot = r; |
49 | } | 54 | } |
55 | // 'centerDisplacement' is the distance from the root the the center-of-mass (Bullet 'zero' of the shape) | ||
56 | public BSLinksetCompoundInfo(int indx, BSPrimLinkable root, BSPrimLinkable child, OMV.Vector3 centerDisplacement) | ||
57 | { | ||
58 | // Each child position and rotation is given relative to the center-of-mass. | ||
59 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(root.RawOrientation); | ||
60 | OMV.Vector3 displacementFromRoot = (child.RawPosition - root.RawPosition) * invRootOrientation; | ||
61 | OMV.Vector3 displacementFromCOM = displacementFromRoot - centerDisplacement; | ||
62 | OMV.Quaternion displacementRot = child.RawOrientation * invRootOrientation; | ||
63 | |||
64 | // Save relative position for recomputing child's world position after moving linkset. | ||
65 | Index = indx; | ||
66 | OffsetFromRoot = displacementFromRoot; | ||
67 | OffsetFromCenterOfMass = displacementFromCOM; | ||
68 | OffsetRot = displacementRot; | ||
69 | } | ||
50 | public override void Clear() | 70 | public override void Clear() |
51 | { | 71 | { |
52 | OffsetPos = OMV.Vector3.Zero; | 72 | Index = 0; |
73 | OffsetFromRoot = OMV.Vector3.Zero; | ||
74 | OffsetFromCenterOfMass = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | 75 | OffsetRot = OMV.Quaternion.Identity; |
54 | } | 76 | } |
55 | public override string ToString() | 77 | public override string ToString() |
56 | { | 78 | { |
57 | StringBuilder buff = new StringBuilder(); | 79 | StringBuilder buff = new StringBuilder(); |
58 | buff.Append("<p="); | 80 | buff.Append("<i="); |
59 | buff.Append(OffsetPos.ToString()); | 81 | buff.Append(Index.ToString()); |
82 | buff.Append(",p="); | ||
83 | buff.Append(OffsetFromRoot.ToString()); | ||
84 | buff.Append(",m="); | ||
85 | buff.Append(OffsetFromCenterOfMass.ToString()); | ||
60 | buff.Append(",r="); | 86 | buff.Append(",r="); |
61 | buff.Append(OffsetRot.ToString()); | 87 | buff.Append(OffsetRot.ToString()); |
62 | buff.Append(">"); | 88 | buff.Append(">"); |
63 | return buff.ToString(); | 89 | return buff.ToString(); |
64 | } | 90 | } |
65 | }; | 91 | }; |
92 | */ | ||
66 | 93 | ||
67 | public sealed class BSLinksetCompound : BSLinkset | 94 | public sealed class BSLinksetCompound : BSLinkset |
68 | { | 95 | { |
69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 96 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
70 | 97 | ||
71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) | 98 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) |
99 | : base(scene, parent) | ||
72 | { | 100 | { |
73 | } | 101 | } |
74 | 102 | ||
75 | // For compound implimented linksets, if there are children, use compound shape for the root. | ||
76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | ||
77 | { | ||
78 | // Returning 'unknown' means we don't have a preference. | ||
79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
80 | if (IsRoot(requestor) && HasAnyChildren) | ||
81 | { | ||
82 | ret = BSPhysicsShapeType.SHAPE_COMPOUND; | ||
83 | } | ||
84 | // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | // When physical properties are changed the linkset needs to recalculate | 103 | // When physical properties are changed the linkset needs to recalculate |
89 | // its internal properties. | 104 | // its internal properties. |
90 | public override void Refresh(BSPhysObject requestor) | 105 | public override void Refresh(BSPrimLinkable requestor) |
91 | { | 106 | { |
92 | base.Refresh(requestor); | 107 | base.Refresh(requestor); |
93 | 108 | ||
@@ -96,16 +111,16 @@ public sealed class BSLinksetCompound : BSLinkset | |||
96 | } | 111 | } |
97 | 112 | ||
98 | // Schedule a refresh to happen after all the other taint processing. | 113 | // Schedule a refresh to happen after all the other taint processing. |
99 | private void ScheduleRebuild(BSPhysObject requestor) | 114 | private void ScheduleRebuild(BSPrimLinkable requestor) |
100 | { | 115 | { |
101 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}", | 116 | DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", |
102 | requestor.LocalID, Rebuilding, HasAnyChildren); | 117 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); |
103 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | 118 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
104 | // If already rebuilding, don't request another rebuild. | 119 | // If already rebuilding, don't request another rebuild. |
105 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | 120 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. |
106 | if (!Rebuilding && HasAnyChildren) | 121 | if (!Rebuilding && HasAnyChildren) |
107 | { | 122 | { |
108 | PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | 123 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() |
109 | { | 124 | { |
110 | if (HasAnyChildren) | 125 | if (HasAnyChildren) |
111 | RecomputeLinksetCompound(); | 126 | RecomputeLinksetCompound(); |
@@ -118,7 +133,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
118 | // has not yet been fully constructed. | 133 | // has not yet been fully constructed. |
119 | // Return 'true' if any properties updated on the passed object. | 134 | // Return 'true' if any properties updated on the passed object. |
120 | // Called at taint-time! | 135 | // Called at taint-time! |
121 | public override bool MakeDynamic(BSPhysObject child) | 136 | public override bool MakeDynamic(BSPrimLinkable child) |
122 | { | 137 | { |
123 | bool ret = false; | 138 | bool ret = false; |
124 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 139 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
@@ -127,138 +142,131 @@ public sealed class BSLinksetCompound : BSLinkset | |||
127 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 142 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
128 | ScheduleRebuild(LinksetRoot); | 143 | ScheduleRebuild(LinksetRoot); |
129 | } | 144 | } |
130 | else | ||
131 | { | ||
132 | // The origional prims are removed from the world as the shape of the root compound | ||
133 | // shape takes over. | ||
134 | PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
135 | PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
136 | // We don't want collisions from the old linkset children. | ||
137 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
138 | |||
139 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
140 | |||
141 | ret = true; | ||
142 | } | ||
143 | return ret; | 145 | return ret; |
144 | } | 146 | } |
145 | 147 | ||
146 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | 148 | // The object is going static (non-physical). We do not do anything for static linksets. |
147 | // Return 'true' if any properties updated on the passed object. | 149 | // Return 'true' if any properties updated on the passed object. |
148 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
149 | // world if it is a static linkset. | ||
150 | // Called at taint-time! | 150 | // Called at taint-time! |
151 | public override bool MakeStatic(BSPhysObject child) | 151 | public override bool MakeStatic(BSPrimLinkable child) |
152 | { | 152 | { |
153 | bool ret = false; | 153 | bool ret = false; |
154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 154 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
155 | if (IsRoot(child)) | 155 | if (IsRoot(child)) |
156 | { | 156 | { |
157 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
157 | ScheduleRebuild(LinksetRoot); | 158 | ScheduleRebuild(LinksetRoot); |
158 | } | 159 | } |
159 | else | ||
160 | { | ||
161 | // The non-physical children can come back to life. | ||
162 | PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
163 | |||
164 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
165 | |||
166 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
167 | PhysicsScene.PE.Activate(child.PhysBody, false); | ||
168 | ret = true; | ||
169 | } | ||
170 | return ret; | 160 | return ret; |
171 | } | 161 | } |
172 | 162 | ||
173 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) | 163 | // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. |
164 | // Called at taint-time. | ||
165 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | ||
174 | { | 166 | { |
167 | if (!LinksetRoot.IsPhysicallyActive) | ||
168 | { | ||
169 | // No reason to do this physical stuff for static linksets. | ||
170 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
171 | return; | ||
172 | } | ||
173 | |||
175 | // The user moving a child around requires the rebuilding of the linkset compound shape | 174 | // The user moving a child around requires the rebuilding of the linkset compound shape |
176 | // One problem is this happens when a border is crossed -- the simulator implementation | 175 | // One problem is this happens when a border is crossed -- the simulator implementation |
177 | // is to store the position into the group which causes the move of the object | 176 | // stores the position into the group which causes the move of the object |
178 | // but it also means all the child positions get updated. | 177 | // but it also means all the child positions get updated. |
179 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | 178 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
180 | // region before bothering to do a rebuild. | 179 | // region before bothering to do a rebuild. |
181 | if (!IsRoot(updated) | 180 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
182 | && !physicalUpdate | ||
183 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
184 | { | 181 | { |
185 | updated.LinksetInfo = null; | 182 | // If a child of the linkset is updating only the position or rotation, that can be done |
186 | ScheduleRebuild(updated); | 183 | // without rebuilding the linkset. |
184 | // If a handle for the child can be fetch, we update the child here. If a rebuild was | ||
185 | // scheduled by someone else, the rebuild will just replace this setting. | ||
186 | |||
187 | bool updatedChild = false; | ||
188 | // Anything other than updating position or orientation usually means a physical update | ||
189 | // and that is caused by us updating the object. | ||
190 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | ||
191 | { | ||
192 | // Find the physical instance of the child | ||
193 | if (LinksetRoot.PhysShape.HasPhysicalShape && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) | ||
194 | { | ||
195 | // It is possible that the linkset is still under construction and the child is not yet | ||
196 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | ||
197 | // build the whole thing with the new position or rotation. | ||
198 | // The index must be checked because Bullet references the child array but does no validity | ||
199 | // checking of the child index passed. | ||
200 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); | ||
201 | if (updated.LinksetChildIndex < numLinksetChildren) | ||
202 | { | ||
203 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); | ||
204 | if (linksetChildShape.HasPhysicalShape) | ||
205 | { | ||
206 | // Found the child shape within the compound shape | ||
207 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, | ||
208 | updated.RawPosition - LinksetRoot.RawPosition, | ||
209 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | ||
210 | true /* shouldRecalculateLocalAabb */); | ||
211 | updatedChild = true; | ||
212 | DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", | ||
213 | updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); | ||
214 | } | ||
215 | else // DEBUG DEBUG | ||
216 | { // DEBUG DEBUG | ||
217 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", | ||
218 | updated.LocalID, linksetChildShape); | ||
219 | } // DEBUG DEBUG | ||
220 | } | ||
221 | else // DEBUG DEBUG | ||
222 | { // DEBUG DEBUG | ||
223 | // the child is not yet in the compound shape. This is non-fatal. | ||
224 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", | ||
225 | updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); | ||
226 | } // DEBUG DEBUG | ||
227 | } | ||
228 | else // DEBUG DEBUG | ||
229 | { // DEBUG DEBUG | ||
230 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); | ||
231 | } // DEBUG DEBUG | ||
232 | |||
233 | if (!updatedChild) | ||
234 | { | ||
235 | // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. | ||
236 | // Note: there are several ways through this code that will not update the child if | ||
237 | // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since | ||
238 | // there will already be a rebuild scheduled. | ||
239 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | ||
240 | updated.LocalID, whichUpdated); | ||
241 | updated.LinksetInfo = null; // setting to 'null' causes relative position to be recomputed. | ||
242 | ScheduleRebuild(updated); | ||
243 | } | ||
244 | } | ||
187 | } | 245 | } |
188 | } | 246 | } |
189 | 247 | ||
190 | // Routine called when rebuilding the body of some member of the linkset. | 248 | // Routine called when rebuilding the body of some member of the linkset. |
191 | // Since we don't keep in world relationships, do nothing unless it's a child changing. | 249 | // If one of the bodies is being changed, the linkset needs rebuilding. |
250 | // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. | ||
192 | // Returns 'true' of something was actually removed and would need restoring | 251 | // Returns 'true' of something was actually removed and would need restoring |
193 | // Called at taint-time!! | 252 | // Called at taint-time!! |
194 | public override bool RemoveBodyDependencies(BSPrim child) | 253 | public override bool RemoveDependencies(BSPrimLinkable child) |
195 | { | 254 | { |
196 | bool ret = false; | 255 | bool ret = false; |
197 | 256 | ||
198 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | 257 | DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", |
199 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child)); | 258 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); |
200 | 259 | ||
201 | if (!IsRoot(child)) | 260 | ScheduleRebuild(child); |
202 | { | ||
203 | // Because it is a convenient time, recompute child world position and rotation based on | ||
204 | // its position in the linkset. | ||
205 | RecomputeChildWorldPosition(child, true); | ||
206 | } | ||
207 | |||
208 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
209 | // the linkset is being rebuilt. | ||
210 | // InternalRefresh(LinksetRoot); | ||
211 | 261 | ||
212 | return ret; | 262 | return ret; |
213 | } | 263 | } |
214 | 264 | ||
215 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | ||
216 | // this routine will restore the removed constraints. | ||
217 | // Called at taint-time!! | ||
218 | public override void RestoreBodyDependencies(BSPrim child) | ||
219 | { | ||
220 | } | ||
221 | |||
222 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
223 | // root shape. The linkset then moves around but this does not move the actual child | ||
224 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
225 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
226 | { | ||
227 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
228 | if (lci != null) | ||
229 | { | ||
230 | if (inTaintTime) | ||
231 | { | ||
232 | OMV.Vector3 oldPos = child.RawPosition; | ||
233 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
234 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
235 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
236 | child.LocalID, oldPos, lci, child.RawPosition); | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
241 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
242 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
243 | } | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | // This happens when children have been added to the linkset but the linkset | ||
248 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
249 | // and then changing properties of the children (makePhysical, for instance) | ||
250 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
251 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
252 | // LogHeader, child.LocalID); | ||
253 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | // ================================================================ | 265 | // ================================================================ |
258 | 266 | ||
259 | // Add a new child to the linkset. | 267 | // Add a new child to the linkset. |
260 | // Called while LinkActivity is locked. | 268 | // Called while LinkActivity is locked. |
261 | protected override void AddChildToLinkset(BSPhysObject child) | 269 | protected override void AddChildToLinkset(BSPrimLinkable child) |
262 | { | 270 | { |
263 | if (!HasChild(child)) | 271 | if (!HasChild(child)) |
264 | { | 272 | { |
@@ -274,8 +282,10 @@ public sealed class BSLinksetCompound : BSLinkset | |||
274 | 282 | ||
275 | // Remove the specified child from the linkset. | 283 | // Remove the specified child from the linkset. |
276 | // Safe to call even if the child is not really in the linkset. | 284 | // Safe to call even if the child is not really in the linkset. |
277 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 285 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) |
278 | { | 286 | { |
287 | child.ClearDisplacement(); | ||
288 | |||
279 | if (m_children.Remove(child)) | 289 | if (m_children.Remove(child)) |
280 | { | 290 | { |
281 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | 291 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", |
@@ -284,7 +294,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
284 | child.LocalID, child.PhysBody.AddrString); | 294 | child.LocalID, child.PhysBody.AddrString); |
285 | 295 | ||
286 | // Cause the child's body to be rebuilt and thus restored to normal operation | 296 | // Cause the child's body to be rebuilt and thus restored to normal operation |
287 | RecomputeChildWorldPosition(child, false); | 297 | child.LinksetInfo = null; |
288 | child.ForceBodyShapeRebuild(false); | 298 | child.ForceBodyShapeRebuild(false); |
289 | 299 | ||
290 | if (!HasAnyChildren) | 300 | if (!HasAnyChildren) |
@@ -295,7 +305,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
295 | else | 305 | else |
296 | { | 306 | { |
297 | // Rebuild the compound shape with the child removed | 307 | // Rebuild the compound shape with the child removed |
298 | ScheduleRebuild(child); | 308 | ScheduleRebuild(LinksetRoot); |
299 | } | 309 | } |
300 | } | 310 | } |
301 | return; | 311 | return; |
@@ -306,87 +316,113 @@ public sealed class BSLinksetCompound : BSLinkset | |||
306 | // Constraint linksets are rebuilt every time. | 316 | // Constraint linksets are rebuilt every time. |
307 | // Note that this works for rebuilding just the root after a linkset is taken apart. | 317 | // Note that this works for rebuilding just the root after a linkset is taken apart. |
308 | // Called at taint time!! | 318 | // Called at taint time!! |
319 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape | ||
320 | private bool disableCOM = true; // For basic linkset debugging, turn off the center-of-mass setting | ||
309 | private void RecomputeLinksetCompound() | 321 | private void RecomputeLinksetCompound() |
310 | { | 322 | { |
311 | try | 323 | try |
312 | { | 324 | { |
313 | // Suppress rebuilding while rebuilding | ||
314 | Rebuilding = true; | 325 | Rebuilding = true; |
315 | 326 | ||
316 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 327 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set |
328 | // to what they should be as if the root was not in a linkset. | ||
329 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
330 | // something has been updated/changed. | ||
317 | LinksetRoot.ForceBodyShapeRebuild(true); | 331 | LinksetRoot.ForceBodyShapeRebuild(true); |
318 | 332 | ||
319 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 333 | // There is no reason to build all this physical stuff for a non-physical linkset. |
320 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 334 | if (!LinksetRoot.IsPhysicallyActive) |
335 | { | ||
336 | // Clean up any old linkset shape and make sure the root shape is set to the root object. | ||
337 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); | ||
338 | |||
339 | return; // Note the 'finally' clause at the botton which will get executed. | ||
340 | } | ||
341 | |||
342 | // Get a new compound shape to build the linkset shape in. | ||
343 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | ||
321 | 344 | ||
322 | // Add a shape for each of the other children in the linkset | 345 | // The center of mass for the linkset is the geometric center of the group. |
323 | ForEachMember(delegate(BSPhysObject cPrim) | 346 | // Compute a displacement for each component so it is relative to the center-of-mass. |
347 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
348 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); | ||
349 | |||
350 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); | ||
351 | |||
352 | // 'centerDisplacement' is the value to subtract from children to give physical offset position | ||
353 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
354 | if (UseBulletSimRootOffsetHack || disableCOM) | ||
324 | { | 355 | { |
356 | centerDisplacementV = OMV.Vector3.Zero; | ||
357 | LinksetRoot.ClearDisplacement(); | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
362 | } | ||
363 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", | ||
364 | LinksetRoot.LocalID, LinksetRoot.RawPosition, centerOfMassW, centerDisplacementV); | ||
365 | |||
366 | // Add the shapes of all the components of the linkset | ||
367 | int memberIndex = 1; | ||
368 | ForEachMember(delegate(BSPrimLinkable cPrim) | ||
369 | { | ||
370 | // Root shape is always index zero. | ||
371 | cPrim.LinksetChildIndex = IsRoot(cPrim) ? 0 : memberIndex; | ||
372 | |||
373 | // Get a reference to the shape of the child and add that shape to the linkset compound shape | ||
374 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); | ||
375 | OMV.Vector3 offsetPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation - centerDisplacementV; | ||
376 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
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, memberIndex, childShape, offsetPos, offsetRot); | ||
380 | |||
381 | // Since we are borrowing the shape of the child, disable the origional child body | ||
325 | if (!IsRoot(cPrim)) | 382 | if (!IsRoot(cPrim)) |
326 | { | 383 | { |
327 | // Compute the displacement of the child from the root of the linkset. | 384 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
328 | // This info is saved in the child prim so the relationship does not | 385 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); |
329 | // change over time and the new child position can be computed | 386 | // We don't want collisions from the old linkset children. |
330 | // when the linkset is being disassembled (the linkset may have moved). | 387 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); |
331 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | 388 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; |
332 | if (lci == null) | 389 | } |
333 | { | ||
334 | // Each child position and rotation is given relative to the root. | ||
335 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
336 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
337 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
338 | |||
339 | // Save relative position for recomputing child's world position after moving linkset. | ||
340 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
341 | cPrim.LinksetInfo = lci; | ||
342 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
343 | } | ||
344 | 390 | ||
345 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 391 | memberIndex++; |
346 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
347 | 392 | ||
348 | if (cPrim.PhysShape.isNativeShape) | ||
349 | { | ||
350 | // A native shape is turning into a hull collision shape because native | ||
351 | // shapes are not shared so we have to hullify it so it will be tracked | ||
352 | // and freed at the correct time. This also solves the scaling problem | ||
353 | // (native shapes scaled but hull/meshes are assumed to not be). | ||
354 | // TODO: decide of the native shape can just be used in the compound shape. | ||
355 | // Use call to CreateGeomNonSpecial(). | ||
356 | BulletShape saveShape = cPrim.PhysShape; | ||
357 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape | ||
358 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); | ||
359 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | ||
360 | BulletShape newShape = cPrim.PhysShape; | ||
361 | cPrim.PhysShape = saveShape; | ||
362 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot); | ||
363 | } | ||
364 | else | ||
365 | { | ||
366 | // For the shared shapes (meshes and hulls), just use the shape in the child. | ||
367 | // The reference count added here will be decremented when the compound shape | ||
368 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
369 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
370 | { | ||
371 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
372 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
373 | } | ||
374 | PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); | ||
375 | } | ||
376 | } | ||
377 | return false; // 'false' says to move onto the next child in the list | 393 | return false; // 'false' says to move onto the next child in the list |
378 | }); | 394 | }); |
379 | 395 | ||
396 | // Replace the root shape with the built compound shape. | ||
397 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
398 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
399 | LinksetRoot.PhysShape = linksetShape; | ||
400 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
401 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
402 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
403 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
404 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
405 | |||
380 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 406 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
381 | LinksetMass = ComputeLinksetMass(); | 407 | LinksetMass = ComputeLinksetMass(); |
382 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | 408 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); |
409 | |||
410 | if (UseBulletSimRootOffsetHack) | ||
411 | { | ||
412 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
413 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
414 | // compound shape. This eleviates the need to offset the returned physical position by the | ||
415 | // center-of-mass offset. | ||
416 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | ||
417 | } | ||
383 | } | 418 | } |
384 | finally | 419 | finally |
385 | { | 420 | { |
386 | Rebuilding = false; | 421 | Rebuilding = false; |
387 | } | 422 | } |
388 | 423 | ||
389 | PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape); | 424 | // See that the Aabb surrounds the new shape |
425 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); | ||
390 | } | 426 | } |
391 | } | 427 | } |
392 | } \ No newline at end of file | 428 | } \ No newline at end of file |