예제 #1
0
 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_velocityMotor = null;
     m_walkingUpStairs = 0;
     m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
 }
예제 #2
0
 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
     LockAxisConstraint = null;
     HaveRegisteredForBeforeStepCallback = false;
 }
예제 #3
0
 public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
 {
     m_physicsScene = physicsScene;
     m_controllingPrim = pObj;
     ActorName = actorName;
     Enabled = true;
 }
예제 #4
0
        // Get a reference to a physical shape. Create if it doesn't exist
        public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
        {
            BSShape ret = null;

            if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
            {
            // an avatar capsule is close to a native shape (it is not shared)
            ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
                                        FixedShapeKey.KEY_CAPSULE);
            physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
            }

            // Compound shapes are handled special as they are rebuilt from scratch.
            // This isn't too great a hardship since most of the child shapes will have already been created.
            if (ret == null  && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
            {
            // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
            ret = BSShapeCompound.GetReference(prim);
            physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
            }

            // Avatars have their own unique shape
            if (ret == null  && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
            {
            // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
            ret = BSShapeAvatar.GetReference(prim);
            physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
            }

            if (ret == null)
            ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);

            return ret;
        }
예제 #5
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;
    }
예제 #6
0
    public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
        : base(physicsScene, pObj, actorName)
    {
        m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
        LockAxisConstraint = null;

        // we place our constraint just before the simulation step to make sure the linkset is complete
        m_physicsScene.BeforeStep += PhysicsScene_BeforeStep;
    }
예제 #7
0
 // For compound implimented linksets, if there are children, use compound shape for the root.
 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
 { 
     // Returning 'unknown' means we don't have a preference.
     BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
     if (IsRoot(requestor) && HasAnyChildren)
     {
         ret = BSPhysicsShapeType.SHAPE_COMPOUND;
     }
     // DetailLog("{0},BSLinksetCompound.PreferredPhysicalShape,call,shape={1}", LinksetRoot.LocalID, ret);
     return ret;
 }
예제 #8
0
 public BSLinkset(BSScene scene, BSPhysObject parent)
 {
     // A simple linkset of one (no children)
     LinksetID = m_nextLinksetID++;
     // We create LOTS of linksets.
     if (m_nextLinksetID <= 0)
         m_nextLinksetID = 1;
     PhysicsScene = scene;
     LinksetRoot = parent;
     m_children = new List<BSPhysObject>();
     m_taintChildren = new List<BSPhysObject>();
     m_mass = parent.MassRaw;
 }
    // When physical properties are changed the linkset needs to recalculate
    //   its internal properties.
    // This is queued in the 'post taint' queue so the
    //   refresh will happen once after all the other taints are applied.
    public override void Refresh(BSPhysObject requestor)
    {
        base.Refresh(requestor);

        if (HasAnyChildren && IsRoot(requestor))
        {
            // Queue to happen after all the other taint processing
            PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
                {
                    if (HasAnyChildren && IsRoot(requestor))
                        RecomputeLinksetConstraints();
                });
        }
    }
예제 #10
0
파일: BSLinkset.cs 프로젝트: CCIR/opensim
    // private static string LogHeader = "[BULLETSIM LINKSET]";

    // Create the correct type of linkset for this child
    public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
    {
        BSLinkset ret = null;
        /*
        if (parent.IsPhysical)
            ret = new BSLinksetConstraints(physScene, parent);
        else
            ret = new BSLinksetManual(physScene, parent);
         */

        // at the moment, there is only one
        ret = new BSLinksetConstraints(physScene, parent);

        return ret;
    }
예제 #11
0
    // When physical properties are changed the linkset needs to recalculate
    //   its internal properties.
    // May be called at runtime or taint-time (just pass the appropriate flag).
    public override void Refresh(BSPhysObject requestor, bool inTaintTime)
    {
        // If there are no children or not root, I am not the one that recomputes the constraints
        if (!HasAnyChildren || !IsRoot(requestor))
            return;

        BSScene.TaintCallback refreshOperation = delegate()
            {
                RecomputeLinksetConstraintVariables();
                DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}",
                                LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
            };
        if (inTaintTime)
            refreshOperation();
        else
            PhysicsScene.TaintedObject("BSLinkSet.Refresh", refreshOperation);
    }
예제 #12
0
    // Create the correct type of linkset for this child
    public static BSLinkset Factory(BSScene physScene, BSPhysObject parent)
    {
        BSLinkset ret = null;

        switch ((int)BSParam.LinksetImplementation)
        {
            case (int)LinksetImplementation.Constraint:
                ret = new BSLinksetConstraints(physScene, parent);
                break;
            case (int)LinksetImplementation.Compound:
                ret = new BSLinksetCompound(physScene, parent);
                break;
            case (int)LinksetImplementation.Manual:
                // ret = new BSLinksetManual(physScene, parent);
                break;
            default:
                ret = new BSLinksetCompound(physScene, parent);
                break;
        }
        return ret;
    }
예제 #13
0
 // Forcefully removing a child from a linkset.
 // This is not being called by the child so we have to make sure the child doesn't think
 //    it's still connected to the linkset.
 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
 //    also has to be updated (like pointer to prim's parent).
 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
 {
     pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
     RemoveChildFromLinkset(pchild);
 }
예제 #14
0
 // Return 'true' if this child is in this linkset
 public bool HasChild(BSPhysObject child)
 {
     bool ret = false;
     lock (m_linksetActivityLock)
     {
         foreach (BSPhysObject bp in m_children)
         {
             if (child.LocalID == bp.LocalID)
             {
                 ret = true;
                 break;
             }
         }
     }
     return ret;
 }
예제 #15
0
    // When physical properties are changed the linkset needs to recalculate
    //   its internal properties.
    // Called at runtime.
    public void Refresh(BSPhysObject requestor)
    {
        // If there are no children, there can't be any constraints to recompute
        if (!HasAnyChildren)
            return;

        // Only the root does the recomputation
        if (IsRoot(requestor))
        {
            PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
            {
                RecomputeLinksetConstraintVariables();
            });
        }
    }
예제 #16
0
 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
     LockAxisConstraint = null;
 }
예제 #17
0
    // Remove a child from a linkset.
    // Returns a new linkset for the child which is a linkset of one (just the
    //    orphened child).
    // Called at runtime.
    public BSLinkset RemoveMeFromLinkset(BSPhysObject child)
    {
        lock (m_linksetActivityLock)
        {
            if (IsRoot(child))
            {
                // Cannot remove the root from a linkset.
                return this;
            }

            RemoveChildFromLinkset(child);
        }

        // The child is down to a linkset of just itself
        return new BSLinkset(PhysicsScene, child);
    }
예제 #18
0
    public override bool Collide(uint collidingWith, BSPhysObject collidee,
                    OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
    {
        // prims in the same linkset cannot collide with each other
        BSPrimLinkable convCollidee = collidee as BSPrimLinkable;
        if (convCollidee != null && (this.Linkset.LinksetID == convCollidee.Linkset.LinksetID))
        {
            return false;
        }

        // TODO: handle collisions of other objects with with children of linkset.
        //    This is a problem for LinksetCompound since the children are packed into the root.

        return base.Collide(collidingWith, collidee, contactPoint, contactNormal, pentrationDepth);
    }
예제 #19
0
 public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_torqueMotor = null;
     m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
 }
예제 #20
0
 public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_targetMotor = null;
     m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
 }
예제 #21
0
 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
 {
     return(GetBodyAndShape(forceRebuild, sim, prim, null, null));
 }
예제 #22
0
 // Forcefully removing a child from a linkset.
 // This is not being called by the child so we have to make sure the child doesn't think
 //    it's still connected to the linkset.
 // Normal OpenSimulator operation will never do this because other SceneObjectPart information
 //    also has to be updated (like pointer to prim's parent).
 private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
 {
     pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
     RemoveChildFromLinkset(pchild);
 }
예제 #23
0
        // Create a constraint between me (root of linkset) and the passed prim (the child).
        // Called at taint time!
        private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
                                                BSPhysObject childPrim, BulletBody childBody)
        {
            // Zero motion for children so they don't interpolate
            childPrim.ZeroMotion();

            // Relative position normalized to the root prim
            // Essentually a vector pointing from center of rootPrim to center of childPrim
            OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;

            // real world coordinate of midpoint between the two objects
            OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);

            DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
                      rootPrim.LocalID,
                      rootPrim.LocalID, rootBody.ptr.ToString("X"),
                      childPrim.LocalID, childBody.ptr.ToString("X"),
                      rootPrim.Position, childPrim.Position, midPoint);

            // create a constraint that allows no freedom of movement between the two objects
            // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818

            // There is great subtlty in these paramters. Notice the check for a ptr of zero.
            // We pass the BulletBody structure into the taint in order to capture the pointer
            //     of the body at the time of constraint creation. This doesn't work for the very first
            //     construction because there is no body yet. The body
            //     is constructed later at taint time. Thus we use the body address at time of the
            //     taint creation but, if it is zero, use what's in the prim at the moment.
            //     There is a possible race condition since shape can change without a taint call
            //     (like changing to a mesh that is already constructed). The fix for that would be
            //     to only change BSShape at taint time thus syncronizing these operations at
            //     the cost of efficiency and lag.
            BS6DofConstraint constrain = new BS6DofConstraint(
                PhysicsScene.World,
                rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
                childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
                midPoint,
                true,
                true
                );

            /* NOTE: below is an attempt to build constraint with full frame computation, etc.
             *     Using the midpoint is easier since it lets the Bullet code manipulate the transforms
             *     of the objects.
             * Code left as a warning to future programmers.
             * // ==================================================================================
             * // relative position normalized to the root prim
             * OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
             * OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
             *
             * // relative rotation of the child to the parent
             * OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
             * OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);
             *
             * // create a constraint that allows no freedom of movement between the two objects
             * // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
             * DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
             * BS6DofConstraint constrain = new BS6DofConstraint(
             *              PhysicsScene.World, rootPrim.Body, childPrim.Body,
             *              OMV.Vector3.Zero,
             *              OMV.Quaternion.Inverse(rootPrim.Orientation),
             *              OMV.Vector3.Zero,
             *              OMV.Quaternion.Inverse(childPrim.Orientation),
             *              // A point half way between the parent and child
             *              // childRelativePosition/2,
             *              // childRelativeRotation,
             *              // childRelativePosition/2,
             *              // inverseChildRelativeRotation,
             *              true,
             *              true
             *              );
             * // ==================================================================================
             */

            PhysicsScene.Constraints.AddConstraint(constrain);

            // zero linear and angular limits makes the objects unable to move in relation to each other
            constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
            constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);

            // tweek the constraint to increase stability
            constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
            constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
                                              PhysicsScene.Params.linkConstraintTransMotorMaxVel,
                                              PhysicsScene.Params.linkConstraintTransMotorMaxForce);
            constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
            if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
            {
                constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
            }

            RecomputeLinksetConstraintVariables();
        }
예제 #24
0
 // The object is going static (non-physical). Do any setup necessary
 //     for a static linkset.
 // Return 'true' if any properties updated on the passed object.
 // Called at taint-time!
 public bool MakeStatic(BSPhysObject child)
 {
     // What is done for each object in BSPrim is what we want.
     return(false);
 }
예제 #25
0
 // Return 'true' if the passed object is the root object of this linkset
 public bool IsRoot(BSPhysObject requestor)
 {
     return(requestor.LocalID == LinksetRoot.LocalID);
 }
예제 #26
0
 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_velocityMotor = null;
     m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
 }
예제 #27
0
 public static BSShape GetReference(BSPhysObject prim) 
 { 
     return new BSShapeNull();
 }
예제 #28
0
        // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
        public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
        {
            bool ret                 = false;
            bool haveShape           = false;
            bool nativeShapePossible = true;
            PrimitiveBaseShape pbs   = prim.BaseShape;

            // If the prim attributes are simple, this could be a simple Bullet native shape
            if (!haveShape &&
                pbs != null &&
                nativeShapePossible &&
                ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ||
                 (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 &&
                  pbs.ProfileHollow == 0 &&
                  pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 &&
                  pbs.PathBegin == 0 && pbs.PathEnd == 0 &&
                  pbs.PathTaperX == 0 && pbs.PathTaperY == 0 &&
                  pbs.PathScaleX == 100 && pbs.PathScaleY == 100 &&
                  pbs.PathShearX == 0 && pbs.PathShearY == 0)))
            {
                // 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);
                }

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

                // It doesn't look like Bullet scales 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.Scale != scaleOfExistingShape ||
                        prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
                        )
                    {
                        ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
                                                        FixedShapeKey.KEY_SPHERE, shapeCallback);
                        if (DDetail)
                        {
                            DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
                                      prim.LocalID, forceRebuild, prim.PhysShape);
                        }
                    }
                }
                if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight)
                {
                    haveShape = true;
                    if (forceRebuild ||
                        prim.Scale != scaleOfExistingShape ||
                        prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
                        )
                    {
                        ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_BOX,
                                                        FixedShapeKey.KEY_BOX, shapeCallback);
                        if (DDetail)
                        {
                            DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
                                      prim.LocalID, forceRebuild, 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);
        }
예제 #29
0
        // The creation of a mesh or hull can fail if an underlying asset is not available.
        // There are two cases: 1) the asset is not in the cache and it needs to be fetched;
        //     and 2) the asset cannot be converted (like failed decompression of JPEG2000s).
        //     The first case causes the asset to be fetched. The second case requires
        //     us to not loop forever.
        // Called after creating a physical mesh or hull. If the physical shape was created,
        //     just return.
        public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim)
        {
            // If the shape was successfully created, nothing more to do
            if (newShape.HasPhysicalShape)
            {
                return(newShape);
            }

            // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been
            //    fetched but we end up here again, the meshing of the asset must have failed.
            // Prevent trying to keep fetching the mesh by declaring failure.
            if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
            {
                prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
                physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. {1}, texture={2}",
                                               LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
                physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,objNam={1},tex={2}",
                                       prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
            }
            else
            {
                // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
                if (prim.BaseShape.SculptEntry &&
                    prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Failed &&
                    prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting &&
                    prim.BaseShape.SculptTexture != OMV.UUID.Zero
                    )
                {
                    physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}",
                                           prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
                    // Multiple requestors will know we're waiting for this asset
                    prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;

                    BSPhysObject xprim = prim;
                    Util.FireAndForget(delegate
                    {
                        // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,inFireAndForget", xprim.LocalID);
                        RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod;
                        if (assetProvider != null)
                        {
                            BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
                            assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset)
                            {
                                // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID);
                                bool assetFound    = false;
                                string mismatchIDs = String.Empty;  // DEBUG DEBUG
                                if (asset != null && yprim.BaseShape.SculptEntry)
                                {
                                    if (yprim.BaseShape.SculptTexture.ToString() == asset.ID)
                                    {
                                        yprim.BaseShape.SculptData = asset.Data;
                                        // This will cause the prim to see that the filler shape is not the right
                                        //    one and try again to build the object.
                                        // No race condition with the normal shape setting since the rebuild is at taint time.
                                        yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
                                        yprim.ForceBodyShapeRebuild(false /* inTaintTime */);
                                        assetFound = true;
                                    }
                                    else
                                    {
                                        mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID;
                                    }
                                }
                                if (!assetFound)
                                {
                                    yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
                                }
                                physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
                                                       yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs);
                            });
                        }
                        else
                        {
                            xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Failed;
                            physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}",
                                                            LogHeader, physicsScene.Name);
                        }
                    });
                }
                else
                {
                    if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Failed)
                    {
                        physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
                                                       LogHeader, prim.PhysObjectName, prim.BaseShape.SculptTexture);
                        physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,objNam={1},tex={2}",
                                               prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture);
                    }
                }
            }

            // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object.
            BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX);

            physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID);

            return(fillShape.physShapeInfo);
        }
예제 #30
0
    // Create a constraint between me (root of linkset) and the passed prim (the child).
    // Called at taint time!
    private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
                                    BSPhysObject childPrim, BulletBody childBody)
    {
        // Zero motion for children so they don't interpolate
        childPrim.ZeroMotion();

        // Relative position normalized to the root prim
        // Essentually a vector pointing from center of rootPrim to center of childPrim
        OMV.Vector3 childRelativePosition = childPrim.Position - rootPrim.Position;

        // real world coordinate of midpoint between the two objects
        OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);

        DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
                                        rootPrim.LocalID,
                                        rootPrim.LocalID, rootBody.ptr.ToString("X"),
                                        childPrim.LocalID, childBody.ptr.ToString("X"),
                                        rootPrim.Position, childPrim.Position, midPoint);

        // create a constraint that allows no freedom of movement between the two objects
        // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818

        // There is great subtlty in these paramters. Notice the check for a ptr of zero.
        // We pass the BulletBody structure into the taint in order to capture the pointer
        //     of the body at the time of constraint creation. This doesn't work for the very first
        //     construction because there is no body yet. The body
        //     is constructed later at taint time. Thus we use the body address at time of the
        //     taint creation but, if it is zero, use what's in the prim at the moment.
        //     There is a possible race condition since shape can change without a taint call
        //     (like changing to a mesh that is already constructed). The fix for that would be
        //     to only change BSShape at taint time thus syncronizing these operations at
        //     the cost of efficiency and lag.
        BS6DofConstraint constrain = new BS6DofConstraint(
                        PhysicsScene.World,
                        rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
                        childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
                        midPoint,
                        true,
                        true
                        );

        /* NOTE: below is an attempt to build constraint with full frame computation, etc.
         *     Using the midpoint is easier since it lets the Bullet code manipulate the transforms
         *     of the objects.
         * Code left as a warning to future programmers.
        // ==================================================================================
        // relative position normalized to the root prim
        OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
        OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;

        // relative rotation of the child to the parent
        OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
        OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation);

        // create a constraint that allows no freedom of movement between the two objects
        // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
        DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
        BS6DofConstraint constrain = new BS6DofConstraint(
                        PhysicsScene.World, rootPrim.Body, childPrim.Body,
                        OMV.Vector3.Zero,
                        OMV.Quaternion.Inverse(rootPrim.Orientation),
                        OMV.Vector3.Zero,
                        OMV.Quaternion.Inverse(childPrim.Orientation),
                        // A point half way between the parent and child
                        // childRelativePosition/2,
                        // childRelativeRotation,
                        // childRelativePosition/2,
                        // inverseChildRelativeRotation,
                        true,
                        true
                        );
        // ==================================================================================
        */

        PhysicsScene.Constraints.AddConstraint(constrain);

        // zero linear and angular limits makes the objects unable to move in relation to each other
        constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
        constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);

        // tweek the constraint to increase stability
        constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
        constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
                        PhysicsScene.Params.linkConstraintTransMotorMaxVel,
                        PhysicsScene.Params.linkConstraintTransMotorMaxForce);
        constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
        if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
        {
            constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
        }

        RecomputeLinksetConstraintVariables();
    }
예제 #31
0
    public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
                    OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
    {
        bool ret = false;

        // The following lines make IsColliding(), CollidingGround() and CollidingObj work
        CollidingStep = PhysScene.SimulationStep;
        if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
        {
            CollidingGroundStep = PhysScene.SimulationStep;
        }
        else
        {
            CollidingObjectStep = PhysScene.SimulationStep;
        }

        CollisionAccumulation++;

        // For movement tests, remember if we are colliding with an object that is moving.
        ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
        ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;

        // Make a collection of the collisions that happened the last simulation tick.
        // This is different than the collection created for sending up to the simulator as it is cleared every tick.
        if (CollisionsLastTickStep != PhysScene.SimulationStep)
        {
            CollisionsLastTick = new CollisionEventUpdate();
            CollisionsLastTickStep = PhysScene.SimulationStep;
        }
        CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));

        // If someone has subscribed for collision events log the collision so it will be reported up
        if (SubscribedEvents()) {
            lock (PhysScene.CollisionLock)
            {
                CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
            }
            DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
                            LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);

            ret = true;
        }
        return ret;
    }
예제 #32
0
 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
 {
 }
예제 #33
0
    // The simulation step is telling this object about a collision.
    // Return 'true' if a collision was processed and should be sent up.
    // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
    // Called at taint time from within the Step() function
    public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
                    OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
    {
        bool ret = false;

        // The following lines make IsColliding(), CollidingGround() and CollidingObj work
        CollidingStep = PhysicsScene.SimulationStep;
        if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
        {
            CollidingGroundStep = PhysicsScene.SimulationStep;
        }
        else
        {
            CollidingObjectStep = PhysicsScene.SimulationStep;
        }

        CollisionAccumulation++;

        // For movement tests, remember if we are colliding with an object that is moving.
        ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;

        // If someone has subscribed for collision events log the collision so it will be reported up
        if (SubscribedEvents()) {
            CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
            DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
                            LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);

            ret = true;
        }
        return ret;
    }
예제 #34
0
 public static BSShape GetShapeReferenceNonSpecial(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
 {
     return(null);
 }
예제 #35
0
 // Link to a linkset where the child knows the parent.
 // Parent changing should not happen so do some sanity checking.
 // We return the parent's linkset so the child can track its membership.
 // Called at runtime.
 public BSLinkset AddMeToLinkset(BSPhysObject child)
 {
     lock (m_linksetActivityLock)
     {
         // Don't add the root to its own linkset
         if (!IsRoot(child))
             AddChildToLinkset(child);
     }
     return this;
 }
        // 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);
        }
예제 #37
0
 // Return 'true' if the passed object is the root object of this linkset
 public bool IsRoot(BSPhysObject requestor)
 {
     return (requestor.LocalID == LinksetRoot.LocalID);
 }
예제 #38
0
        // Get a reference to a physical shape. Create if it doesn't exist
        public static BSShape GetShapeReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
        {
            BSShape ret = null;

            if (prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
            {
                // an avatar capsule is close to a native shape (it is not shared)
                ret = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_CAPSULE,
                                                 FixedShapeKey.KEY_CAPSULE);
                physicsScene.DetailLog("{0},BSShape.GetShapeReference,avatarCapsule,shape={1}", prim.LocalID, ret);
            }

            // Compound shapes are handled special as they are rebuilt from scratch.
            // This isn't too great a hardship since most of the child shapes will have already been created.
            if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
            {
                // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
                ret = BSShapeCompound.GetReference(prim);
                physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, ret);
            }

            // Avatars have their own unique shape
            if (ret == null && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_AVATAR)
            {
                // Getting a reference to a compound shape gets you the compound shape with the root prim shape added
                ret = BSShapeAvatar.GetReference(prim);
                physicsScene.DetailLog("{0},BSShapeCollection.CreateGeom,avatarShape,shape={1}", prim.LocalID, ret);
            }

            if (ret == null)
            {
                ret = GetShapeReferenceNonSpecial(physicsScene, forceRebuild, prim);
            }

            return(ret);
        }
예제 #39
0
 // The object is going static (non-physical). Do any setup necessary
 //     for a static linkset.
 // Return 'true' if any properties updated on the passed object.
 // Called at taint-time!
 public bool MakeStatic(BSPhysObject child)
 {
     // What is done for each object in BSPrim is what we want.
     return false;
 }
예제 #40
0
 // Get another reference to this shape.
 public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim);
예제 #41
0
    // I am the root of a linkset and a new child is being added
    // Called while LinkActivity is locked.
    private void AddChildToLinkset(BSPhysObject child)
    {
        if (!HasChild(child))
        {
            m_children.Add(child);

            BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
            BulletBody rootBodyx = LinksetRoot.BSBody;
            BSPhysObject childx = child;
            BulletBody childBodyx = child.BSBody;

            DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 
                            rootx.LocalID,
                            rootx.LocalID, rootBodyx.ptr.ToString("X"),
                            childx.LocalID, childBodyx.ptr.ToString("X"));

            PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
            {
                DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
                // build the physical binding between me and the child
                m_taintChildren.Add(childx);
                PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
            });
        }
        return;
    }
예제 #42
0
 public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim)
 {
     return(new BSShapeNull());
 }
예제 #43
0
    // I am the root of a linkset and one of my children is being removed.
    // Safe to call even if the child is not really in my linkset.
    private void RemoveChildFromLinkset(BSPhysObject child)
    {
        if (m_children.Remove(child))
        {
            BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
            BulletBody rootBodyx = LinksetRoot.BSBody;
            BSPhysObject childx = child;
            BulletBody childBodyx = child.BSBody;

            DetailLog("{0},RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 
                            childx.LocalID,
                            rootx.LocalID, rootBodyx.ptr.ToString("X"),
                            childx.LocalID, childBodyx.ptr.ToString("X"));

            PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
            {
                if (m_taintChildren.Contains(childx))
                    m_taintChildren.Remove(childx);

                PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
                RecomputeLinksetConstraintVariables();
            });

        }
        else
        {
            // This will happen if we remove the root of the linkset first. Non-fatal occurance.
            // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader);
        }
        return;
    }
예제 #44
0
 public static BSShape GetShapeReferenceNonNative(BSScene physicsScene, bool forceRebuild, BSPhysObject prim)
 {
     return null;
 }
예제 #45
0
    // Remove linkage between myself and a particular child
    // The root and child bodies are passed in because we need to remove the constraint between
    //      the bodies that were at unlink time.
    // Called at taint time!
    private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
                                                    BSPhysObject childPrim, BulletBody childBody)
    {
        DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
                            rootPrim.LocalID,
                            rootPrim.LocalID, rootBody.ptr.ToString("X"),
                            childPrim.LocalID, childBody.ptr.ToString("X"));

        // Find the constraint for this link and get rid of it from the overall collection and from my list
        PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);

        // Make the child refresh its location
        BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
    }
예제 #46
0
 public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
     LockAxisConstraint = null;
 }
예제 #47
0
    // The simulation step is telling this object about a collision.
    // Return 'true' if a collision was processed and should be sent up.
    // Called at taint time from within the Step() function
    public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
                    OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
    {
        bool ret = false;

        // The following lines make IsColliding(), CollidingGround() and CollidingObj work
        CollidingStep = PhysicsScene.SimulationStep;
        if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
        {
            CollidingGroundStep = PhysicsScene.SimulationStep;
        }
        else
        {
            CollidingObjectStep = PhysicsScene.SimulationStep;
        }

        // prims in the same linkset cannot collide with each other
        if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
        {
            return ret;
        }

        // if someone has subscribed for collision events....
        if (SubscribedEvents()) {
            CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
            DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}",
                            LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth);

            ret = true;
        }
        return ret;
    }
 public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
     : base(physicsScene, pObj, actorName)
 {
     m_forceMotor = null;
     m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
 }
예제 #49
0
 // Called by a BSPhysObject to note that it has changed properties and this information
 //    should be passed up to the simulator at the proper time.
 // Note: this is called by the BSPhysObject from invocation via DoPhysicsStep() above so
 //    this is is under UpdateLock.
 public void PostUpdate(BSPhysObject updatee)
 {
     ObjectsWithUpdates.Add(updatee);
 }
        // Create the geometry information in Bullet for later use.
        // The objects needs a hull if it's physical otherwise a mesh is enough.
        // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls,
        //     shared geometries will be used. If the parameters of the existing shape are the same
        //     as this request, the shape is not rebuilt.
        // Info in prim.BSShape is updated to the new shape.
        // Returns 'true' if the geometry was rebuilt.
        // Called at taint-time!
        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);
                prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim,
                                                            BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE);
                ret       = true;
                haveShape = true;
            }

            // 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);
            }

            return(ret);
        }