aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs72
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs24
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs85
3 files changed, 120 insertions, 61 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index 8b97ebb..adf4aff 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -34,7 +34,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35public sealed class BSLinksetCompound : BSLinkset 35public sealed class BSLinksetCompound : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 38
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 39 public BSLinksetCompound(BSScene scene, BSPhysObject parent)
40 { 40 {
@@ -59,6 +59,12 @@ public sealed class BSLinksetCompound : BSLinkset
59 // refresh will happen once after all the other taints are applied. 59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 60 public override void Refresh(BSPhysObject requestor)
61 { 61 {
62 // External request for Refresh (from BSPrim) is not necessary
63 // InternalRefresh(requestor);
64 }
65
66 private void InternalRefresh(BSPhysObject requestor)
67 {
62 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID);
63 // Queue to happen after all the other taint processing 69 // Queue to happen after all the other taint processing
64 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate()
@@ -135,13 +141,13 @@ public sealed class BSLinksetCompound : BSLinkset
135 { 141 {
136 bool ret = false; 142 bool ret = false;
137 143
138 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2},isRoot={3}", 144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
139 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child));
140 146
141 if (!IsRoot(child)) 147 if (!IsRoot(child))
142 { 148 {
143 // Cause the current shape to be freed and the new one to be built. 149 // Cause the current shape to be freed and the new one to be built.
144 Refresh(LinksetRoot); 150 InternalRefresh(LinksetRoot);
145 ret = true; 151 ret = true;
146 } 152 }
147 153
@@ -169,7 +175,7 @@ public sealed class BSLinksetCompound : BSLinkset
169 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
170 176
171 // Cause constraints and assorted properties to be recomputed before the next simulation step. 177 // Cause constraints and assorted properties to be recomputed before the next simulation step.
172 Refresh(LinksetRoot); 178 InternalRefresh(LinksetRoot);
173 } 179 }
174 return; 180 return;
175 } 181 }
@@ -196,34 +202,68 @@ public sealed class BSLinksetCompound : BSLinkset
196 else 202 else
197 { 203 {
198 // Schedule a rebuild of the linkset before the next simulation tick. 204 // Schedule a rebuild of the linkset before the next simulation tick.
199 Refresh(LinksetRoot); 205 InternalRefresh(LinksetRoot);
200 } 206 }
201 } 207 }
202 return; 208 return;
203 } 209 }
204 210
205 211 // Called before the simulation step to make sure the compound based linkset
206 // Call each of the constraints that make up this linkset and recompute the
207 // various transforms and variables. Create constraints of not created yet.
208 // Called before the simulation step to make sure the constraint based linkset
209 // is all initialized. 212 // is all initialized.
213 // Constraint linksets are rebuilt every time.
214 // Note that this works for rebuilding just the root after a linkset is taken apart.
210 // Called at taint time!! 215 // Called at taint time!!
211 private void RecomputeLinksetCompound() 216 private void RecomputeLinksetCompound()
212 { 217 {
213 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},numChildren={2}", 218 // Cause the root shape to be rebuilt as a compound object with just the root in it
214 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), NumberOfChildren);
215
216 LinksetRoot.ForceBodyShapeRebuild(true); 219 LinksetRoot.ForceBodyShapeRebuild(true);
217 220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 ForEachMember(delegate(BSPhysObject cPrim)
225 {
226 if (!IsRoot(cPrim))
227 {
228 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
229 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
230 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
231
232 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
233 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot);
234
235 if (cPrim.PhysShape.isNativeShape)
236 {
237 // Native shapes are not shared so we need to create a new one.
238 // A mesh or hull is created because scale is not available on a native shape.
239 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?)
240 BulletShape saveShape = cPrim.PhysShape;
241 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
242 BulletShape newShape = cPrim.PhysShape;
243 cPrim.PhysShape = saveShape;
244 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
245 }
246 else
247 {
248 // For the shared shapes (meshes and hulls) just use the shape in the child
249 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
250 {
251 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
252 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
253 }
254 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
255 }
256 }
257 return false;
258 });
259
260
218 float linksetMass = LinksetMass; 261 float linksetMass = LinksetMass;
219 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 262 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
220 263
221 // DEBUG: see of inter-linkset collisions are causing problems 264 // DEBUG: see of inter-linkset collisions are causing problems
222 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 265 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
223 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 266 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
224 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,end,rBody={1},linksetMass={2}",
225 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass);
226
227 267
228 } 268 }
229} 269}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 13aa860..de35359 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -116,6 +116,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
116 // True if initialized and ready to do simulation steps 116 // True if initialized and ready to do simulation steps
117 private bool m_initialized = false; 117 private bool m_initialized = false;
118 118
119 // Flag which is true when processing taints.
120 // Not guaranteed to be correct all the time (don't depend on this) but good for debugging.
121 public bool InTaintTime { get; private set; }
122
119 // Pinned memory used to pass step information between managed and unmanaged 123 // Pinned memory used to pass step information between managed and unmanaged
120 private int m_maxCollisionsPerFrame; 124 private int m_maxCollisionsPerFrame;
121 private CollisionDesc[] m_collisionArray; 125 private CollisionDesc[] m_collisionArray;
@@ -270,6 +274,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
270 TerrainManager = new BSTerrainManager(this); 274 TerrainManager = new BSTerrainManager(this);
271 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 275 TerrainManager.CreateInitialGroundPlaneAndTerrain();
272 276
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
278
279 InTaintTime = false;
273 m_initialized = true; 280 m_initialized = true;
274 } 281 }
275 282
@@ -707,8 +714,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 // here just before the physics engine is called to step the simulation. 714 // here just before the physics engine is called to step the simulation.
708 public void ProcessTaints() 715 public void ProcessTaints()
709 { 716 {
717 InTaintTime = true;
710 ProcessRegularTaints(); 718 ProcessRegularTaints();
711 ProcessPostTaintTaints(); 719 ProcessPostTaintTaints();
720 InTaintTime = false;
712 } 721 }
713 722
714 private void ProcessRegularTaints() 723 private void ProcessRegularTaints()
@@ -851,6 +860,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
851 } 860 }
852 } 861 }
853 862
863 public bool AssertInTaintTime(string whereFrom)
864 {
865 if (!InTaintTime)
866 {
867 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
868 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
869 Util.PrintCallStack();
870 }
871 return InTaintTime;
872 }
873
854 #endregion // Taints 874 #endregion // Taints
855 875
856 #region Vehicles 876 #region Vehicles
@@ -1214,8 +1234,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1214 (s) => { return s.m_params[0].numberOfSolverIterations; }, 1234 (s) => { return s.m_params[0].numberOfSolverIterations; },
1215 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ), 1235 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1216 1236
1217 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound)", 1237 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1218 (float)BSLinkset.LinksetImplementation.Constraint, 1238 (float)BSLinkset.LinksetImplementation.Compound,
1219 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); }, 1239 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1220 (s) => { return s.m_params[0].linksetImplementation; }, 1240 (s) => { return s.m_params[0].linksetImplementation; },
1221 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ), 1241 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 107befe..662b19d 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -92,6 +92,8 @@ public sealed class BSShapeCollection : IDisposable
92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 92 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim,
93 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 93 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
94 { 94 {
95 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
96
95 bool ret = false; 97 bool ret = false;
96 98
97 // This lock could probably be pushed down lower but building shouldn't take long 99 // This lock could probably be pushed down lower but building shouldn't take long
@@ -121,7 +123,7 @@ public sealed class BSShapeCollection : IDisposable
121 { 123 {
122 lock (m_collectionActivityLock) 124 lock (m_collectionActivityLock)
123 { 125 {
124 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody", body.ID, body); 126 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
125 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 127 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
126 { 128 {
127 if (!BulletSimAPI.IsInWorld2(body.ptr)) 129 if (!BulletSimAPI.IsInWorld2(body.ptr))
@@ -165,7 +167,7 @@ public sealed class BSShapeCollection : IDisposable
165 // Meshes and hulls for the same shape have the same hash key. 167 // Meshes and hulls for the same shape have the same hash key.
166 // NOTE that native shapes are not added to the mesh list or removed. 168 // NOTE that native shapes are not added to the mesh list or removed.
167 // Returns 'true' if this is the initial reference to the shape. Otherwise reused. 169 // Returns 'true' if this is the initial reference to the shape. Otherwise reused.
168 private bool ReferenceShape(BulletShape shape) 170 public bool ReferenceShape(BulletShape shape)
169 { 171 {
170 bool ret = false; 172 bool ret = false;
171 switch (shape.type) 173 switch (shape.type)
@@ -276,8 +278,8 @@ public sealed class BSShapeCollection : IDisposable
276 if (shapeCallback != null) shapeCallback(shape); 278 if (shapeCallback != null) shapeCallback(shape);
277 meshDesc.lastReferenced = System.DateTime.Now; 279 meshDesc.lastReferenced = System.DateTime.Now;
278 Meshes[shape.shapeKey] = meshDesc; 280 Meshes[shape.shapeKey] = meshDesc;
279 DetailLog("{0},BSShapeCollection.DereferenceMesh,key={1},refCnt={2}", 281 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
280 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 282 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
281 283
282 } 284 }
283 } 285 }
@@ -297,8 +299,8 @@ public sealed class BSShapeCollection : IDisposable
297 299
298 hullDesc.lastReferenced = System.DateTime.Now; 300 hullDesc.lastReferenced = System.DateTime.Now;
299 Hulls[shape.shapeKey] = hullDesc; 301 Hulls[shape.shapeKey] = hullDesc;
300 DetailLog("{0},BSShapeCollection.DereferenceHull,key={1},refCnt={2}", 302 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
301 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 303 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
302 } 304 }
303 } 305 }
304 306
@@ -319,8 +321,11 @@ public sealed class BSShapeCollection : IDisposable
319 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 321 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X"));
320 return; 322 return;
321 } 323 }
324
322 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 325 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr);
323 for (int ii = 0; ii < numChildren; ii++) 326 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
327
328 for (int ii = numChildren - 1; ii >= 0; ii--)
324 { 329 {
325 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 330 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii);
326 DereferenceAnonCollisionShape(childShape); 331 DereferenceAnonCollisionShape(childShape);
@@ -343,6 +348,7 @@ public sealed class BSShapeCollection : IDisposable
343 shapeInfo.isNativeShape = true; 348 shapeInfo.isNativeShape = true;
344 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 349 shapeInfo.type = ShapeData.PhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
345 } 350 }
351 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
346 352
347 DereferenceShape(shapeInfo, true, null); 353 DereferenceShape(shapeInfo, true, null);
348 } 354 }
@@ -440,23 +446,32 @@ public sealed class BSShapeCollection : IDisposable
440 } 446 }
441 447
442 // If a simple shape is not happening, create a mesh and possibly a hull. 448 // If a simple shape is not happening, create a mesh and possibly a hull.
449 if (!haveShape && pbs != null)
450 {
451 ret = CreateGeomMeshOrHull(prim, shapeCallback);
452 }
453
454 return ret;
455 }
456
457 public bool CreateGeomMeshOrHull(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
458 {
459
460 bool ret = false;
443 // Note that if it's a native shape, the check for physical/non-physical is not 461 // Note that if it's a native shape, the check for physical/non-physical is not
444 // made. Native shapes work in either case. 462 // made. Native shapes work in either case.
445 if (!haveShape && pbs != null) 463 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
446 { 464 {
447 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 465 // Update prim.BSShape to reference a hull of this shape.
448 { 466 ret = GetReferenceToHull(prim,shapeCallback);
449 // Update prim.BSShape to reference a hull of this shape. 467 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
450 ret = GetReferenceToHull(prim,shapeCallback); 468 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
451 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 469 }
452 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 470 else
453 } 471 {
454 else 472 ret = GetReferenceToMesh(prim, shapeCallback);
455 { 473 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
456 ret = GetReferenceToMesh(prim, shapeCallback); 474 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
457 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
458 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
459 }
460 } 475 }
461 return ret; 476 return ret;
462 } 477 }
@@ -743,32 +758,16 @@ public sealed class BSShapeCollection : IDisposable
743 // This shouldn't be to bad since most of the parts will be meshes that had been built previously. 758 // This shouldn't be to bad since most of the parts will be meshes that had been built previously.
744 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 759 private bool GetReferenceToCompoundShape(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
745 { 760 {
761 // Remove reference to the old shape
762 // Don't need to do this as the shape is freed when we create the new root shape below.
763 // DereferenceShape(prim.PhysShape, true, shapeCallback);
764
746 BulletShape cShape = new BulletShape( 765 BulletShape cShape = new BulletShape(
747 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr), ShapeData.PhysicsShapeType.SHAPE_COMPOUND); 766 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr), ShapeData.PhysicsShapeType.SHAPE_COMPOUND);
748 767
749 // The prim's linkset is the source of the children. 768 // Create the shape for the root prim and add it to the compound shape
750 // TODO: there is too much knowledge here about the internals of linksets and too much
751 // dependency on the relationship of compound shapes and linksets (what if we want to use
752 // compound shapes for something else?). Think through this and clean up so the
753 // appropriate knowledge is used at the correct software levels.
754
755 // Recreate the geometry of the root prim (might have been a linkset root in the past)
756 CreateGeomNonSpecial(true, prim, null); 769 CreateGeomNonSpecial(true, prim, null);
757 770 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity);
758 BSPhysObject rootPrim = prim.Linkset.LinksetRoot;
759
760 prim.Linkset.ForEachMember(delegate(BSPhysObject cPrim)
761 {
762 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(rootPrim.RawOrientation);
763 OMV.Vector3 displacementPos = (cPrim.RawPosition - rootPrim.RawPosition) * invRootOrientation;
764 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
765
766 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
767 prim.LocalID, cPrim.LocalID, cPrim.PhysShape.ptr.ToString("X"), displacementPos, displacementRot);
768
769 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
770 return false;
771 });
772 771
773 prim.PhysShape = cShape; 772 prim.PhysShape = cShape;
774 773