Example #1
0
    // Called to update/change the body and shape for an object.
    // The object has some shape and body on it. Here we decide if that is the correct shape
    //    for the current state of the object (static/dynamic/...).
    // If bodyCallback is not null, it is called if either the body or the shape are changed
    //    so dependencies (like constraints) can be removed before the physical object is dereferenced.
    // Return 'true' if either the body or the shape changed.
    // Called at taint-time.
    public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
    {
        m_physicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");

        bool ret = false;

        // This lock could probably be pushed down lower but building shouldn't take long
        lock (m_collectionActivityLock)
        {
            // Do we have the correct geometry for this type of object?
            // Updates prim.BSShape with information/pointers to shape.
            // Returns 'true' of BSShape is changed to a new shape.
            bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
            // If we had to select a new shape geometry for the object,
            //    rebuild the body around it.
            // Updates prim.BSBody with information/pointers to requested body
            // Returns 'true' if BSBody was changed.
            bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
            ret = newGeom || newBody;
        }
        DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
                                prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);

        return ret;
    }
        // Release the usage of a body.
        // Called when releasing use of a BSBody. BSShape is handled separately.
        // Called in taint time.
        public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback)
        {
            if (!body.HasPhysicalBody)
            {
                return;
            }

            lock (m_collectionActivityLock)
            {
                if (DDetail)
                {
                    DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
                }
                // If the caller needs to know the old body is going away, pass the event up.
                if (bodyCallback != null)
                {
                    bodyCallback(body, null);
                }

                // Removing an object not in the world is a NOOP
                m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body);

                // Zero any reference to the shape so it is not freed when the body is deleted.
                m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null);

                m_physicsScene.PE.DestroyObject(m_physicsScene.World, body);
            }
        }
        // Create a body object in Bullet,
        // Update prim.BSBody with the information about the new body if one is created.
        // Returns 'true if an object was actually created.
        // Called at taint-time.
        bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim,
                        PhysicalDestructionCallback bodyCallback)
        {
            bool ret = false;

            // the mesh, hull or native shape must have already been created in Bullet
            bool mustRebuild = !prim.PhysBody.HasPhysicalBody;

            // If there is an existing body, verify it's of an acceptable type.
            // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
            if (!mustRebuild)
            {
                CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
                if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY ||
                    !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
                {
                    // If the collisionObject is not the correct type for solidness, rebuild what's there
                    mustRebuild = true;
                    if (DDetail)
                    {
                        DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}",
                                  prim.LocalID, bodyType);
                    }
                }
            }

            if (mustRebuild || forceRebuild)
            {
                // Free any old body
                DereferenceBody(prim.PhysBody, bodyCallback);

                BulletBody aBody;
                if (prim.IsSolid)
                {
                    aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID,
                                                                prim.RawPosition, prim.RawOrientation);
                    if (DDetail)
                    {
                        DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
                    }
                }
                else
                {
                    aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID,
                                                                 prim.RawPosition, prim.RawOrientation);
                    if (DDetail)
                    {
                        DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
                    }
                }

                ReferenceBody(aBody);

                prim.PhysBody = aBody;

                ret = true;
            }
            return(ret);
        }
 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
 //     before replacing it.
 private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
 {
     if (prim.PhysShape.HasPhysicalShape)
     {
         if (shapeCallback != null)
         {
             shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
         }
         prim.PhysShape.Dereference(m_physicsScene);
     }
     prim.PhysShape = new BSShapeNull();
 }
        // Called to update/change the body and shape for an object.
        // The object has some shape and body on it. Here we decide if that is the correct shape
        //    for the current state of the object (static/dynamic/...).
        // If bodyCallback is not null, it is called if either the body or the shape are changed
        //    so dependencies (like constraints) can be removed before the physical object is dereferenced.
        // Return 'true' if either the body or the shape changed.
        // Called at taint-time.
        public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback)
        {
            bool ret = false;

            // This lock could probably be pushed down lower but building shouldn't take long
            lock (m_collectionActivityLock)
            {
                // Do we have the correct geometry for this type of object?
                // Updates prim.BSShape with information/pointers to shape.
                // Returns 'true' of BSShape is changed to a new shape.
                bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback);
                // If we had to select a new shape geometry for the object,
                //    rebuild the body around it.
                // Updates prim.BSBody with information/pointers to requested body
                // Returns 'true' if BSBody was changed.
                bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback);
                ret = newGeom || newBody;
            }
            DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}",
                      prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape);

            return(ret);
        }
        // return 'true' if the prim's shape was changed.
        private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
        {
            bool ret = false;

            // Note that if it's a native shape, the check for physical/non-physical is not
            //     made. Native shapes work in either case.
            if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
            {
                // Use a simple, single mesh convex hull shape if the object is simple enough
                BSShape potentialHull = null;

                PrimitiveBaseShape pbs = prim.BaseShape;
                // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
                if (BSParam.ShouldUseSingleConvexHullForPrims &&
                    pbs != null &&
                    !pbs.SculptEntry &&
                    PrimHasNoCuts(pbs)
                    )
                {
                    potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim);
                }
                // Use the GImpact shape if it is a prim that has some concaveness
                if (potentialHull == null &&
                    BSParam.ShouldUseGImpactShapeForPrims &&
                    pbs != null &&
                    !pbs.SculptEntry
                    )
                {
                    potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim);
                }
                // If not any of the simple cases, just make a hull
                if (potentialHull == null)
                {
                    potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
                }

                // If the current shape is not what is on the prim at the moment, time to change.
                if (!prim.PhysShape.HasPhysicalShape ||
                    potentialHull.ShapeType != prim.PhysShape.ShapeType ||
                    potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
                {
                    DereferenceExistingShape(prim, shapeCallback);
                    prim.PhysShape = potentialHull;
                    ret            = true;
                }
                else
                {
                    // The current shape on the prim is the correct one. We don't need the potential reference.
                    potentialHull.Dereference(m_physicsScene);
                }
                if (DDetail)
                {
                    DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
                }
            }
            else
            {
                // Non-physical objects should be just meshes.
                BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim);
                // If the current shape is not what is on the prim at the moment, time to change.
                if (!prim.PhysShape.HasPhysicalShape ||
                    potentialMesh.ShapeType != prim.PhysShape.ShapeType ||
                    potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
                {
                    DereferenceExistingShape(prim, shapeCallback);
                    prim.PhysShape = potentialMesh;
                    ret            = true;
                }
                else
                {
                    // We don't need this reference to the mesh that is already being using.
                    potentialMesh.Dereference(m_physicsScene);
                }
                if (DDetail)
                {
                    DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
                }
            }
            return(ret);
        }
        private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
        {
            bool ret                 = false;
            bool haveShape           = false;
            bool nativeShapePossible = true;
            PrimitiveBaseShape pbs   = prim.BaseShape;

            // Kludge to create the capsule for the avatar.
            // TDOD: Remove/redo this when BSShapeAvatar is working!!
            BSCharacter theChar = prim as BSCharacter;

            if (theChar != null)
            {
                DereferenceExistingShape(prim, shapeCallback);
                switch (BSParam.AvatarShape)
                {
                case AvatarShapeCapsule:
                    prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                                BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
                    ret       = true;
                    haveShape = true;
                    break;

                case AvatarShapeCube:
                    prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                                BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE);
                    ret       = true;
                    haveShape = true;
                    break;

                case AvatarShapeOvoid:
                    // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape
                    prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                                BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE);
                    ret       = true;
                    haveShape = true;
                    break;

                case AvatarShapeMesh:
                    break;

                default:
                    break;
                }
            }

            // If the prim attributes are simple, this could be a simple Bullet native shape
            // Native shapes work whether to object is static or physical.
            if (!haveShape &&
                nativeShapePossible &&
                pbs != null &&
                PrimHasNoCuts(pbs) &&
                (!pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim))
                )
            {
                // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
                OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
                if (prim.PhysShape.HasPhysicalShape)
                {
                    scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
                }

                if (DDetail)
                {
                    DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
                              prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);
                }

                // It doesn't look like Bullet scales native spheres so make sure the scales are all equal
                if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) &&
                    pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
                {
                    haveShape = true;
                    if (forceRebuild ||
                        prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE
                        )
                    {
                        DereferenceExistingShape(prim, shapeCallback);
                        prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                                    BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE);
                        ret = true;
                    }
                    if (DDetail)
                    {
                        DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}",
                                  prim.LocalID, forceRebuild, ret, prim.PhysShape);
                    }
                }
                // If we didn't make a sphere, maybe a box will work.
                if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
                {
                    haveShape = true;
                    if (forceRebuild ||
                        prim.Scale != scaleOfExistingShape ||
                        prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX
                        )
                    {
                        DereferenceExistingShape(prim, shapeCallback);
                        prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                                    BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);
                        ret = true;
                    }
                    if (DDetail)
                    {
                        DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}",
                                  prim.LocalID, forceRebuild, ret, prim.PhysShape);
                    }
                }
            }

            // If a simple shape is not happening, create a mesh and possibly a hull.
            if (!haveShape && pbs != null)
            {
                ret = CreateGeomMeshOrHull(prim, shapeCallback);
            }

            m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World);    // DEBUG DEBUG

            return(ret);
        }
        // Create a body object in Bullet,
        // Update prim.BSBody with the information about the new body if one is created.
        // Returns 'true if an object was actually created.
        // Called at taint-time.
        bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim,
            PhysicalDestructionCallback bodyCallback)
        {
            bool ret = false;

            // the mesh, hull or native shape must have already been created in Bullet
            bool mustRebuild = !prim.PhysBody.HasPhysicalBody;

            // If there is an existing body, verify it's of an acceptable type.
            // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
            if (!mustRebuild)
            {
                CollisionObjectTypes bodyType = (CollisionObjectTypes) PhysicsScene.PE.GetBodyType(prim.PhysBody);
                if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY ||
                    !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
                {
                    // If the collisionObject is not the correct type for solidness, rebuild what's there
                    mustRebuild = true;
                    if (DDetail)
                        DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}",
                            prim.LocalID, bodyType);
                }
            }

            if (mustRebuild || forceRebuild)
            {
                // Free any old body
                DereferenceBody(prim.PhysBody, bodyCallback);

                BulletBody aBody;
                if (prim.IsSolid)
                {
                    aBody = PhysicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID,
                        prim.RawPosition, prim.RawOrientation);
                    if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody);
                }
                else
                {
                    aBody = PhysicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID,
                        prim.RawPosition, prim.RawOrientation);
                    if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
                }

                ReferenceBody(aBody);

                prim.PhysBody = aBody;

                ret = true;
            }
            return ret;
        }
        // Release the usage of a body.
        // Called when releasing use of a BSBody. BSShape is handled separately.
        // Called in taint time.
        public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback)
        {
            if (!body.HasPhysicalBody)
                return;

            PhysicsScene.AssertInTaintTime("BSShapeCollection.DereferenceBody");

            lock (m_collectionActivityLock)
            {
                if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body);
                // If the caller needs to know the old body is going away, pass the event up.
                if (bodyCallback != null) bodyCallback(body, null);

                // Removing an object not in the world is a NOOP
                PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);

                // Zero any reference to the shape so it is not freed when the body is deleted.
                PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);

                PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
            }
        }
        // return 'true' if the prim's shape was changed.
        bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
        {
            bool ret = false;
            // Note that if it's a native shape, the check for physical/non-physical is not
            //     made. Native shapes work in either case.
            if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
            {
                // Use a simple, single mesh convex hull shape if the object is simple enough
                BSShape potentialHull = null;
                PrimitiveBaseShape pbs = prim.BaseShape;

                // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists)
                if (BSParam.ShouldUseSingleConvexHullForPrims && pbs != null && !pbs.SculptEntry && PrimHasNoCuts(pbs))
                {
                    potentialHull = BSShapeConvexHull.GetReference(PhysicsScene, false /* forceRebuild */, prim);
                }

                // use the GImpact shape if it is a prim that has some concaveness
                if (potentialHull == null && BSParam.ShouldUseGImpactShapeForPrims && pbs != null && !pbs.SculptEntry)
                {
                    potentialHull = BSShapeGImpact.GetReference(PhysicsScene, false /* forceRebuild */, prim);
                }

                // If not any of the simple cases, just make a hull
                if (potentialHull == null)
                {
                    potentialHull = BSShapeHull.GetReference(PhysicsScene, false /* forceRebuild */, prim);
                }

                // If the current shape is not what is on the prim at the moment, time to change.
                if (!prim.PhysShape.HasPhysicalShape || potentialHull.ShapeType != prim.PhysShape.ShapeType ||
                    potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
                {
                    DereferenceExistingShape(prim, shapeCallback);
                    prim.PhysShape = potentialHull;
                    ret = true;
                }
                else
                {
                    // The current shape on the prim is the correct one. We don't need the potential reference.
                    potentialHull.Dereference(PhysicsScene);
                }
                if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape);
            }
            else
            {
                // Non-physical objects should be just meshes.
                BSShape potentialMesh = BSShapeMesh.GetReference(PhysicsScene, false /* forceRebuld */, prim);

                // If the current shape is not what is on the prim at the moment, time to change.
                if (!prim.PhysShape.HasPhysicalShape || potentialMesh.ShapeType != prim.PhysShape.ShapeType ||
                    potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey)
                {
                    DereferenceExistingShape(prim, shapeCallback);
                    prim.PhysShape = potentialMesh;
                    ret = true;
                }
                else
                {
                    // We don't need this reference to the mesh that is already being using.
                    potentialMesh.Dereference(PhysicsScene);
                }
                if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape);
            }
            return ret;
        }
        bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
        {
            bool ret = false;
            bool haveShape = false;
            bool nativeShapePossible = true;
            PrimitiveBaseShape pbs = prim.BaseShape;

            // Kludge to create the capsule for the avatar.
            // TODO: Remove/redo this when BSShapeAvatar is working!!
            BSCharacter theChar = prim as BSCharacter;
            if (theChar != null)
            {
                DereferenceExistingShape(prim, shapeCallback);
                switch (BSParam.AvatarShape)
                {
                    case AvatarShapeCapsule:
                        prim.PhysShape = BSShapeNative.GetReference(PhysicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
                            FixedShapeKey.KEY_CAPSULE);
                        ret = true;
                        haveShape = true;
                        break;
                    case AvatarShapeCube:
                        prim.PhysShape = BSShapeNative.GetReference(PhysicsScene, prim, BSPhysicsShapeType.SHAPE_BOX,
                            FixedShapeKey.KEY_CAPSULE);
                        ret = true;
                        haveShape = true;
                        break;
                    case AvatarShapeOvoid:
                        // Saddly, Bullet doesn't scale spheres so this doen't work as an avatar shape
                        prim.PhysShape = BSShapeNative.GetReference(PhysicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE,
                            FixedShapeKey.KEY_CAPSULE);
                        ret = true;
                        haveShape = true;
                        break;
                    case AvatarShapeMesh:
                        break;
                    default:
                        break;
                }
            }

            // If the prim attributes are simple, this could be a simple Bullet native shape
            // Native shapes work whether to object is static or physical.
            if (!haveShape && nativeShapePossible && pbs != null && PrimHasNoCuts(pbs) &&
                (!pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)))
            {
                // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
                OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
                if (prim.PhysShape.HasPhysicalShape)
                    scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo);
                if (DDetail)
                    DetailLog(
                        "{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
                        prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType);

                // It doen't look like Bullet scales native spheres so make sure the scales are all equal
                if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) &&
                    pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
                {
                    haveShape = true;
                    if (forceRebuild || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE)
                    {
                        DereferenceExistingShape(prim, shapeCallback);
                        prim.PhysShape = BSShapeNative.GetReference(PhysicsScene, prim, BSPhysicsShapeType.SHAPE_SPHERE,
                            FixedShapeKey.KEY_SPHERE);
                        ret = true;
                    }
                    if (DDetail)
                        DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuild={2},shape={3}",
                            prim.LocalID, forceRebuild, ret, prim.PhysShape);
                }
                // If we didn't make a sphere, maybe a box will work.
                if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
                {
                    haveShape = true;
                    if (forceRebuild || prim.Scale != scaleOfExistingShape ||
                        prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX)
                    {
                        DereferenceExistingShape(prim, shapeCallback);
                        prim.PhysShape = BSShapeNative.GetReference(PhysicsScene, prim, BSPhysicsShapeType.SHAPE_BOX,
                            FixedShapeKey.KEY_BOX);
                        ret = true;
                    }
                    if (DDetail)
                        DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuild={2},shape={3}", prim.LocalID,
                            forceRebuild, ret, prim.PhysShape);
                }
            }

            // If a simple shape is not happening, create a mesh and possibly a hull.
            if (!haveShape && pbs != null)
            {
                ret = CreateGeomMeshOrHull(prim, shapeCallback);
            }

            return ret;
        }
 // If the existing prim's shape is to be replaced, remove the tie to the existing shape
 //     before replacing it.
 void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback)
 {
     if (prim.PhysShape.HasPhysicalShape)
     {
         if (shapeCallback != null)
             shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo);
         prim.PhysShape.Dereference(PhysicsScene);
     }
     prim.PhysShape = new BSShapeNull();
 }