diff options
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs')
-rwxr-xr-x | OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs new file mode 100755 index 0000000..953ddee --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OpenSim.Framework; | ||
32 | |||
33 | using OMV = OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Region.PhysicsModule.BulletS | ||
36 | { | ||
37 | |||
38 | public sealed class BSLinksetCompound : BSLinkset | ||
39 | { | ||
40 | #pragma warning disable 414 | ||
41 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | ||
42 | #pragma warning restore 414 | ||
43 | |||
44 | public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) | ||
45 | : base(scene, parent) | ||
46 | { | ||
47 | LinksetImpl = LinksetImplementation.Compound; | ||
48 | } | ||
49 | |||
50 | // ================================================================ | ||
51 | // Changing the physical property of the linkset only needs to change the root | ||
52 | public override void SetPhysicalFriction(float friction) | ||
53 | { | ||
54 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
55 | m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); | ||
56 | } | ||
57 | public override void SetPhysicalRestitution(float restitution) | ||
58 | { | ||
59 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
60 | m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); | ||
61 | } | ||
62 | public override void SetPhysicalGravity(OMV.Vector3 gravity) | ||
63 | { | ||
64 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
65 | m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); | ||
66 | } | ||
67 | public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) | ||
68 | { | ||
69 | OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); | ||
70 | LinksetRoot.Inertia = inertia * inertiaFactor; | ||
71 | m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); | ||
72 | m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); | ||
73 | } | ||
74 | public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) | ||
75 | { | ||
76 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
77 | m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
78 | } | ||
79 | public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) | ||
80 | { | ||
81 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
82 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
83 | } | ||
84 | public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) | ||
85 | { | ||
86 | if (LinksetRoot.PhysBody.HasPhysicalBody) | ||
87 | m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); | ||
88 | } | ||
89 | // ================================================================ | ||
90 | |||
91 | // When physical properties are changed the linkset needs to recalculate | ||
92 | // its internal properties. | ||
93 | public override void Refresh(BSPrimLinkable requestor) | ||
94 | { | ||
95 | // Something changed so do the rebuilding thing | ||
96 | ScheduleRebuild(requestor); | ||
97 | base.Refresh(requestor); | ||
98 | } | ||
99 | |||
100 | // Schedule a refresh to happen after all the other taint processing. | ||
101 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
102 | { | ||
103 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | ||
104 | // 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. | ||
106 | lock (m_linksetActivityLock) | ||
107 | { | ||
108 | if (!RebuildScheduled && !Rebuilding && HasAnyChildren) | ||
109 | { | ||
110 | InternalScheduleRebuild(requestor); | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | |||
115 | // Must be called with m_linksetActivityLock or race conditions will haunt you. | ||
116 | private void InternalScheduleRebuild(BSPrimLinkable requestor) | ||
117 | { | ||
118 | DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}", | ||
119 | requestor.LocalID, Rebuilding, HasAnyChildren); | ||
120 | RebuildScheduled = true; | ||
121 | m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() | ||
122 | { | ||
123 | if (HasAnyChildren) | ||
124 | { | ||
125 | if (this.AllPartsComplete) | ||
126 | { | ||
127 | RecomputeLinksetCompound(); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete", | ||
132 | requestor.LocalID); | ||
133 | InternalScheduleRebuild(requestor); | ||
134 | } | ||
135 | } | ||
136 | RebuildScheduled = false; | ||
137 | }); | ||
138 | } | ||
139 | |||
140 | // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. | ||
141 | // Only the state of the passed object can be modified. The rest of the linkset | ||
142 | // has not yet been fully constructed. | ||
143 | // Return 'true' if any properties updated on the passed object. | ||
144 | // Called at taint-time! | ||
145 | public override bool MakeDynamic(BSPrimLinkable child) | ||
146 | { | ||
147 | bool ret = false; | ||
148 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
149 | if (IsRoot(child)) | ||
150 | { | ||
151 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
152 | Refresh(LinksetRoot); | ||
153 | } | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | // The object is going static (non-physical). We do not do anything for static linksets. | ||
158 | // Return 'true' if any properties updated on the passed object. | ||
159 | // Called at taint-time! | ||
160 | public override bool MakeStatic(BSPrimLinkable child) | ||
161 | { | ||
162 | bool ret = false; | ||
163 | |||
164 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
165 | child.ClearDisplacement(); | ||
166 | if (IsRoot(child)) | ||
167 | { | ||
168 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
169 | Refresh(LinksetRoot); | ||
170 | } | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. | ||
175 | // Called at taint-time. | ||
176 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) | ||
177 | { | ||
178 | if (!LinksetRoot.IsPhysicallyActive) | ||
179 | { | ||
180 | // No reason to do this physical stuff for static linksets. | ||
181 | DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); | ||
182 | return; | ||
183 | } | ||
184 | |||
185 | // The user moving a child around requires the rebuilding of the linkset compound shape | ||
186 | // One problem is this happens when a border is crossed -- the simulator implementation | ||
187 | // stores the position into the group which causes the move of the object | ||
188 | // but it also means all the child positions get updated. | ||
189 | // What would cause an unnecessary rebuild so we make sure the linkset is in a | ||
190 | // region before bothering to do a rebuild. | ||
191 | if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) | ||
192 | { | ||
193 | // If a child of the linkset is updating only the position or rotation, that can be done | ||
194 | // without rebuilding the linkset. | ||
195 | // If a handle for the child can be fetch, we update the child here. If a rebuild was | ||
196 | // scheduled by someone else, the rebuild will just replace this setting. | ||
197 | |||
198 | bool updatedChild = false; | ||
199 | // Anything other than updating position or orientation usually means a physical update | ||
200 | // and that is caused by us updating the object. | ||
201 | if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) | ||
202 | { | ||
203 | // Find the physical instance of the child | ||
204 | if (!RebuildScheduled // if rebuilding, let the rebuild do it | ||
205 | && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change | ||
206 | && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned | ||
207 | && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) | ||
208 | { | ||
209 | // It is possible that the linkset is still under construction and the child is not yet | ||
210 | // inserted into the compound shape. A rebuild of the linkset in a pre-step action will | ||
211 | // build the whole thing with the new position or rotation. | ||
212 | // The index must be checked because Bullet references the child array but does no validity | ||
213 | // checking of the child index passed. | ||
214 | int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); | ||
215 | if (updated.LinksetChildIndex < numLinksetChildren) | ||
216 | { | ||
217 | BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); | ||
218 | if (linksetChildShape.HasPhysicalShape) | ||
219 | { | ||
220 | // Found the child shape within the compound shape | ||
221 | m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, | ||
222 | updated.RawPosition - LinksetRoot.RawPosition, | ||
223 | updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), | ||
224 | true /* shouldRecalculateLocalAabb */); | ||
225 | updatedChild = true; | ||
226 | DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", | ||
227 | updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); | ||
228 | } | ||
229 | else // DEBUG DEBUG | ||
230 | { // DEBUG DEBUG | ||
231 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", | ||
232 | updated.LocalID, linksetChildShape); | ||
233 | } // DEBUG DEBUG | ||
234 | } | ||
235 | else // DEBUG DEBUG | ||
236 | { // DEBUG DEBUG | ||
237 | // the child is not yet in the compound shape. This is non-fatal. | ||
238 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", | ||
239 | updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); | ||
240 | } // DEBUG DEBUG | ||
241 | } | ||
242 | else // DEBUG DEBUG | ||
243 | { // DEBUG DEBUG | ||
244 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); | ||
245 | } // DEBUG DEBUG | ||
246 | |||
247 | if (!updatedChild) | ||
248 | { | ||
249 | // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. | ||
250 | // Note: there are several ways through this code that will not update the child if | ||
251 | // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since | ||
252 | // there will already be a rebuild scheduled. | ||
253 | DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", | ||
254 | updated.LocalID, whichUpdated); | ||
255 | Refresh(updated); | ||
256 | } | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | // Routine called when rebuilding the body of some member of the linkset. | ||
262 | // If one of the bodies is being changed, the linkset needs rebuilding. | ||
263 | // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. | ||
264 | // Returns 'true' of something was actually removed and would need restoring | ||
265 | // Called at taint-time!! | ||
266 | public override bool RemoveDependencies(BSPrimLinkable child) | ||
267 | { | ||
268 | bool ret = false; | ||
269 | |||
270 | DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", | ||
271 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); | ||
272 | |||
273 | Refresh(child); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | // ================================================================ | ||
279 | |||
280 | // Add a new child to the linkset. | ||
281 | // Called while LinkActivity is locked. | ||
282 | protected override void AddChildToLinkset(BSPrimLinkable child) | ||
283 | { | ||
284 | if (!HasChild(child)) | ||
285 | { | ||
286 | m_children.Add(child, new BSLinkInfo(child)); | ||
287 | |||
288 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
289 | |||
290 | // Rebuild the compound shape with the new child shape included | ||
291 | Refresh(child); | ||
292 | } | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | // Remove the specified child from the linkset. | ||
297 | // Safe to call even if the child is not really in the linkset. | ||
298 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
299 | { | ||
300 | child.ClearDisplacement(); | ||
301 | |||
302 | if (m_children.Remove(child)) | ||
303 | { | ||
304 | DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
305 | child.LocalID, | ||
306 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, | ||
307 | child.LocalID, child.PhysBody.AddrString); | ||
308 | |||
309 | // Cause the child's body to be rebuilt and thus restored to normal operation | ||
310 | child.ForceBodyShapeRebuild(inTaintTime); | ||
311 | |||
312 | if (!HasAnyChildren) | ||
313 | { | ||
314 | // The linkset is now empty. The root needs rebuilding. | ||
315 | LinksetRoot.ForceBodyShapeRebuild(inTaintTime); | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | // Rebuild the compound shape with the child removed | ||
320 | Refresh(LinksetRoot); | ||
321 | } | ||
322 | } | ||
323 | return; | ||
324 | } | ||
325 | |||
326 | // Called before the simulation step to make sure the compound based linkset | ||
327 | // is all initialized. | ||
328 | // Constraint linksets are rebuilt every time. | ||
329 | // Note that this works for rebuilding just the root after a linkset is taken apart. | ||
330 | // Called at taint time!! | ||
331 | private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape | ||
332 | private void RecomputeLinksetCompound() | ||
333 | { | ||
334 | try | ||
335 | { | ||
336 | Rebuilding = true; | ||
337 | |||
338 | // No matter what is being done, force the root prim's PhysBody and PhysShape to get set | ||
339 | // to what they should be as if the root was not in a linkset. | ||
340 | // Not that bad since we only get into this routine if there are children in the linkset and | ||
341 | // something has been updated/changed. | ||
342 | // Have to do the rebuild before checking for physical because this might be a linkset | ||
343 | // being destructed and going non-physical. | ||
344 | LinksetRoot.ForceBodyShapeRebuild(true); | ||
345 | |||
346 | // There is no reason to build all this physical stuff for a non-physical or empty linkset. | ||
347 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) | ||
348 | { | ||
349 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); | ||
350 | return; // Note the 'finally' clause at the botton which will get executed. | ||
351 | } | ||
352 | |||
353 | // Get a new compound shape to build the linkset shape in. | ||
354 | BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); | ||
355 | |||
356 | // Compute a displacement for each component so it is relative to the center-of-mass. | ||
357 | // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass | ||
358 | OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); | ||
359 | |||
360 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); | ||
361 | OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; | ||
362 | |||
363 | // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass | ||
364 | OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; | ||
365 | if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) | ||
366 | { | ||
367 | // Zero everything if center-of-mass displacement is not being done. | ||
368 | centerDisplacementV = OMV.Vector3.Zero; | ||
369 | LinksetRoot.ClearDisplacement(); | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | // The actual center-of-mass could have been set by the user. | ||
374 | centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); | ||
375 | } | ||
376 | |||
377 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", | ||
378 | LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); | ||
379 | |||
380 | // Add the shapes of all the components of the linkset | ||
381 | int memberIndex = 1; | ||
382 | ForEachMember((cPrim) => | ||
383 | { | ||
384 | if (IsRoot(cPrim)) | ||
385 | { | ||
386 | // Root shape is always index zero. | ||
387 | cPrim.LinksetChildIndex = 0; | ||
388 | } | ||
389 | else | ||
390 | { | ||
391 | cPrim.LinksetChildIndex = memberIndex; | ||
392 | memberIndex++; | ||
393 | } | ||
394 | |||
395 | // Get a reference to the shape of the child for adding of that shape to the linkset compound shape | ||
396 | BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); | ||
397 | |||
398 | // Offset the child shape from the center-of-mass and rotate it to root relative. | ||
399 | OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; | ||
400 | OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; | ||
401 | |||
402 | // Add the child shape to the compound shape being built | ||
403 | if (childShape.physShapeInfo.HasPhysicalShape) | ||
404 | { | ||
405 | m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); | ||
406 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", | ||
407 | LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); | ||
408 | |||
409 | // Since we are borrowing the shape of the child, disable the origional child body | ||
410 | if (!IsRoot(cPrim)) | ||
411 | { | ||
412 | m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); | ||
413 | m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); | ||
414 | // We don't want collisions from the old linkset children. | ||
415 | m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
416 | cPrim.PhysBody.collisionType = CollisionType.LinksetChild; | ||
417 | } | ||
418 | } | ||
419 | else | ||
420 | { | ||
421 | // The linkset must be in an intermediate state where all the children have not yet | ||
422 | // been constructed. This sometimes happens on startup when everything is getting | ||
423 | // built and some shapes have to wait for assets to be read in. | ||
424 | // Just skip this linkset for the moment and cause the shape to be rebuilt next tick. | ||
425 | // One problem might be that the shape is broken somehow and it never becomes completely | ||
426 | // available. This might cause the rebuild to happen over and over. | ||
427 | InternalScheduleRebuild(LinksetRoot); | ||
428 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}", | ||
429 | LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); | ||
430 | // Output an annoying warning. It should only happen once but if it keeps coming out, | ||
431 | // the user knows there is something wrong and will report it. | ||
432 | m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader); | ||
433 | m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}", | ||
434 | LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape); | ||
435 | |||
436 | // This causes the loop to bail on building the rest of this linkset. | ||
437 | // The rebuild operation will fix it up next tick or declare the object unbuildable. | ||
438 | return true; | ||
439 | } | ||
440 | |||
441 | return false; // 'false' says to move onto the next child in the list | ||
442 | }); | ||
443 | |||
444 | // Replace the root shape with the built compound shape. | ||
445 | // Object removed and added to world to get collision cache rebuilt for new shape. | ||
446 | LinksetRoot.PhysShape.Dereference(m_physicsScene); | ||
447 | LinksetRoot.PhysShape = linksetShape; | ||
448 | m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
449 | m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); | ||
450 | m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); | ||
451 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", | ||
452 | LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); | ||
453 | |||
454 | // With all of the linkset packed into the root prim, it has the mass of everyone. | ||
455 | LinksetMass = ComputeLinksetMass(); | ||
456 | LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); | ||
457 | |||
458 | if (UseBulletSimRootOffsetHack) | ||
459 | { | ||
460 | // Enable the physical position updator to return the position and rotation of the root shape. | ||
461 | // This enables a feature in the C++ code to return the world coordinates of the first shape in the | ||
462 | // compound shape. This aleviates the need to offset the returned physical position by the | ||
463 | // center-of-mass offset. | ||
464 | // TODO: either debug this feature or remove it. | ||
465 | m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); | ||
466 | } | ||
467 | } | ||
468 | finally | ||
469 | { | ||
470 | Rebuilding = false; | ||
471 | } | ||
472 | |||
473 | // See that the Aabb surrounds the new shape | ||
474 | m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); | ||
475 | } | ||
476 | } | ||
477 | } \ No newline at end of file | ||