public BSShapeHull(BulletShape pShape) : base(pShape)
 {
 }
 // Loop through all the known hulls and return the description based on the physical address.
 public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull)
 {
     bool ret = false;
     BSShapeHull foundDesc = null;
     lock (Hulls)
     {
         foreach (BSShapeHull sh in Hulls.Values)
         {
             if (sh.physShapeInfo.ReferenceSame(pShape))
             {
                 foundDesc = sh;
                 ret = true;
                 break;
             }
         }
     }
     outHull = foundDesc;
     return ret;
 }
 public BSShapeNative(BulletShape pShape)
     : base(pShape)
 {
 }
 // Loop through all the known meshes and return the description based on the physical address.
 public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh)
 {
     bool ret = false;
     BSShapeMesh foundDesc = null;
     lock (Meshes)
     {
         foreach (BSShapeMesh sm in Meshes.Values)
         {
             if (sm.physShapeInfo.ReferenceSame(pShape))
             {
                 foundDesc = sm;
                 ret = true;
                 break;
             }
         }
     }
     outMesh = foundDesc;
     return ret;
 }
 public BSShapeConvexHull(BulletShape pShape) : base(pShape)
 {
 }
 public BSShape(BulletShape pShape)
 {
     referenceCount = 1;
     lastReferenced = DateTime.Now;
     physShapeInfo = pShape;
     shapeInfo = new ShapeInfoInfo();
 }
 public abstract bool IsSoftBody(BulletShape shape);
 public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound)
 {
     lock (CompoundShapes)
     {
         string addr = pShape.AddrString;
         return CompoundShapes.TryGetValue(addr, out outCompound);
     }
 }
 public abstract bool IsNonMoving(BulletShape shape);
 public abstract bool IsPolyhedral(BulletShape shape);
 public abstract bool IsNativeShape(BulletShape shape);
 public abstract bool IsInfinite(BulletShape shape);
 public abstract bool IsConvex2d(BulletShape shape);
 public abstract bool IsConcave(BulletShape shape);
 public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
        // Create terrain mesh from a heightmap.
        public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
            Vector3 minCoords, Vector3 maxCoords)
            : base(physicsScene, regionBase, id)
        {
            int indicesCount;
            int[] indices;
            int verticesCount;
            float[] vertices;

            m_savedHeightMap = initialMap;

            m_sizeX = (int)(maxCoords.X - minCoords.X);
            m_sizeY = (int)(maxCoords.Y - minCoords.Y);

            bool meshCreationSuccess = false;
            if (BSParam.TerrainMeshMagnification == 1)
            {
                // If a magnification of one, use the old routine that is tried and true.
                meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
                    initialMap, m_sizeX, m_sizeY, // input size
                    Vector3.Zero, // base for mesh
                    out indicesCount, out indices, out verticesCount, out vertices);
            }
            else
            {
                // Other magnifications use the newer routine
                meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
                    initialMap, m_sizeX, m_sizeY, // input size
                    BSParam.TerrainMeshMagnification,
                    physicsScene.TerrainManager.WorldMax,
                    Vector3.Zero, // base for mesh
                    out indicesCount, out indices, out verticesCount, out vertices);
            }
            if (!meshCreationSuccess)
            {
                // DISASTER!!
                PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}",
                    BSScene.DetailLogZero, ID);
                PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader,
                    TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshid,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
                BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);

            m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount,
                vertices);

            if (!m_terrainShape.HasPhysicalShape)
            {
                // DISASTER!!
                PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero,
                    ID);
                PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            Vector3 pos = regionBase;
            Quaternion rot = Quaternion.Identity;

            m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
            if (!m_terrainBody.HasPhysicalBody)
            {
                // DISASTER!!
                PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);

            // Set current terrain attributes
            PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
            PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
            PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
            PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
            PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);

            // Static objects are not very massive.
            PhysicsScene.PE.SetMassProps(m_terrainBody, 0.1f, Vector3.Zero);

            // Put the new terrain to the world of physical objects
            PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);

            // Redo its bounding box now that it is in the world
            PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);

            m_terrainBody.collisionType = CollisionType.Terrain;
            m_terrainBody.ApplyCollisionMask(PhysicsScene);

            if (BSParam.UseSingleSidedMeshes)
            {
                PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
                PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
            }

            // Make it so the terrain will not move or be considered for movement.
            PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
        }
 public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
 // Sometimes we have a pointer to a collision shape but don't know what type it is.
 // Figure out type and call the correct dereference routine.
 // Called at taint-time.
 void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape)
 {
     // TODO: figure a better way to go through all the shape types and find a possible instance.
     physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}",
         BSScene.DetailLogZero, pShape);
     BSShapeMesh meshDesc;
     if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc))
     {
         meshDesc.Dereference(physicsScene);
         // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape);
     }
     else
     {
         BSShapeHull hullDesc;
         if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc))
         {
             hullDesc.Dereference(physicsScene);
             // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape);
         }
         else
         {
             BSShapeConvexHull chullDesc;
             if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc))
             {
                 chullDesc.Dereference(physicsScene);
                 // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape);
             }
             else
             {
                 BSShapeGImpact gImpactDesc;
                 if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc))
                 {
                     gImpactDesc.Dereference(physicsScene);
                     // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape);
                 }
                 else
                 {
                     // Didn't find it in the lists of specific types. It could be compound.
                     BSShapeCompound compoundDesc;
                     if (TryGetCompoundByPtr(pShape, out compoundDesc))
                     {
                         compoundDesc.Dereference(physicsScene);
                         // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape);
                     }
                     else
                     {
                         // If none of the above, maybe it is a simple native shape.
                         if (physicsScene.PE.IsNativeShape(pShape))
                         {
                             // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape);
                             BSShapeNative nativeShape = new BSShapeNative(pShape);
                             nativeShape.Dereference(physicsScene);
                         }
                         else
                         {
                             physicsScene.Logger.WarnFormat(
                                 "{0} DereferenceAnonCollisionShape. Did not find shape. {1}",
                                 LogHeader, pShape);
                         }
                     }
                 }
             }
         }
     }
 }
 public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
 public BSShapeGImpact(BulletShape pShape) : base(pShape)
 {
 }
 public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
        // 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.FailedMeshing;
                physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}",
                    LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture);
                physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}",
                    prim.LocalID, UsefulPrimInfo(physicsScene, prim), 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.FailedAssetFetch
                    && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting
                    && prim.BaseShape.SculptTexture != OMV.UUID.Zero
                )
                {
                    physicsScene.DetailLog("{0},BSShapeCollection.VerifyMeshCreated,fetchAsset", prim.LocalID);
                    // Multiple requestors will know we're waiting for this asset
                    prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting;

                    BSPhysObject xprim = prim;
                    Util.FireAndForget(delegate
                        {
                            BSPhysObject yprim = xprim; // probably not necessary, but, just in case.
                            physicsScene.Scene.AssetService.Get(yprim.BaseShape.SculptTexture.ToString(), null,
                                delegate(string id, Object sender, AssetBase asset)
                                {
                                    bool assetFound = false;
                                    string mismatchIDs = String.Empty; // DEBUG DEBUG
                                    if (asset != null && yprim.BaseShape.SculptEntry)
                                    {
                                        if (yprim.BaseShape.SculptTexture == 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.ForceBodyShapeRebuild(false /* inTaintTime */);
                                            assetFound = true;
                                        }
                                        else
                                        {
                                            mismatchIDs = yprim.BaseShape.SculptTexture + "/" + asset.ID;
                                        }
                                    }
                                    if (assetFound)
                                        yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched;
                                    else
                                        yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch;
                                    physicsScene.DetailLog("{0},BSShapeCollection,fetchAssetCallback,found={1},isSculpt={2},ids={3}",
                                        yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs);
                                });
                        });
                }
                else
                {
                    if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch)
                    {
                        physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. obj={1}, texture={2}",
                            LogHeader, 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;
        }
 public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
 public BSShapeMesh(BulletShape pShape) : base(pShape)
 {
 }
 public abstract void SetMargin(BulletShape shape, float val);
        // Code that uses the mesher to create the index/vertices info for a trimesh shape.
        // This is used by the passed 'makeShape' call to create the Bullet mesh shape.
        // The actual build call is passed so this logic can be used by several of the shapes that use a
        //     simple mesh as their base shape.
        public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, UInt64 newMeshKey,
            PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape)
        {
            BulletShape newShape = new BulletShape();

            IMesh meshData;
            lock (physicsScene.mesher)
            {
                meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod,
                    false, // say it is not physical so a bounding box is not built
                    false // do not cache the mesh and do not use previously built versions
                    );
            }

            if (meshData != null)
            {
                if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
                {
                    // Release the fetched asset data once it has been used.
                    pbs.SculptData = new byte[0];
                    prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
                }

                int[] indices = meshData.getIndexListAsInt();
                int realIndicesIndex = indices.Length;
                float[] verticesAsFloats = meshData.getVertexListAsFloat();

                if (BSParam.ShouldRemoveZeroWidthTriangles)
                {
                    // Remove degenerate triangles. These are triangles with two of the vertices
                    //    are the same. This is complicated by the problem that vertices are not
                    //    made unique in sculpties so we have to compare the values in the vertex.
                    realIndicesIndex = 0;
                    for (int tri = 0; tri < indices.Length; tri += 3)
                    {
                        // Compute displacements into vertex array for each vertex of the triangle
                        int v1 = indices[tri + 0]*3;
                        int v2 = indices[tri + 1]*3;
                        int v3 = indices[tri + 2]*3;
                        // Check to see if any two of the vertices are the same
                        if (!((verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0]
                               && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1]
                               && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2])
                              || (verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0]
                                  && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1]
                                  && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2])
                              || (verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0]
                                  && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1]
                                  && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]))
                            )
                        {
                            // None of the vertices of the triangles are the same. This is a good triangle;
                            indices[realIndicesIndex + 0] = indices[tri + 0];
                            indices[realIndicesIndex + 1] = indices[tri + 1];
                            indices[realIndicesIndex + 2] = indices[tri + 2];
                            realIndicesIndex += 3;
                        }
                    }
                }
                physicsScene.DetailLog(
                    "{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}",
                    BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length/3, realIndicesIndex/3,
                    verticesAsFloats.Length/3);

                if (realIndicesIndex != 0)
                {
                    newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length/3,
                        verticesAsFloats);
                }
                else
                {
                    // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh.
                    prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing;
                    physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader,
                        UsefulPrimInfo(physicsScene, prim));
                    physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID,
                        newMeshKey);
                }
            }
            newShape.shapeKey = newMeshKey;

            return newShape;
        }
 public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
        BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, UInt64 newHullKey,
            PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
        {
            BulletShape newShape = new BulletShape();
            IMesh meshData;
            List<List<OMV.Vector3>> allHulls = null;

            lock (physicsScene.mesher)
            {
                // Pass true for physicalness as this prevents the creation of bounding box which is not needed
                meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */,
                    false /* shouldCache */);

                // If we should use the asset's hull info, fetch it out of the locked mesher
                if (meshData != null && BSParam.ShouldUseAssetHulls)
                {
                    Meshmerizer realMesher = physicsScene.mesher as Meshmerizer;
                    if (realMesher != null)
                    {
                        allHulls = realMesher.GetConvexHulls(size);
                    }
                    if (allHulls == null)
                    {
                        physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID);
                    }
                }
            }

            // If there is hull data in the mesh asset, build the hull from that
            if (allHulls != null && BSParam.ShouldUseAssetHulls)
            {
                int hullCount = allHulls.Count;
                shapeInfo.HullCount = hullCount;
                int totalVertices = 1; // include one for the count of the hulls
                // Using the structure described for HACD hulls, create the memory structure
                //      to pass the hull data to the creater.
                foreach (List<OMV.Vector3> hullVerts in allHulls)
                {
                    totalVertices += 4; // add four for the vertex count and centroid
                    totalVertices += hullVerts.Count*3; // one vertex is three dimensions
                }
                float[] convHulls = new float[totalVertices];

                convHulls[0] = (float) hullCount;
                int jj = 1;
                int hullIndex = 0;
                foreach (List<OMV.Vector3> hullVerts in allHulls)
                {
                    convHulls[jj + 0] = hullVerts.Count;
                    convHulls[jj + 1] = 0f; // centroid x,y,z
                    convHulls[jj + 2] = 0f;
                    convHulls[jj + 3] = 0f;
                    jj += 4;
                    foreach (OMV.Vector3 oneVert in hullVerts)
                    {
                        convHulls[jj + 0] = oneVert.X;
                        convHulls[jj + 1] = oneVert.Y;
                        convHulls[jj + 2] = oneVert.Z;
                        jj += 3;
                    }
                    shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count);
                    hullIndex++;
                }

                // create the hull data structure in Bullet
                newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
                physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,AssetHulls,hulls={1},totVert={2},shape={3}",
                    prim.LocalID, hullCount, totalVertices, newShape);
            }

            // If no hull specified in the asset and we should use Bullet's HACD approximation...
            if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD)
            {
                // Build the hull shape from an existing mesh shape.
                // The mesh should have already been created in Bullet.
                physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID);
                var meshShape = BSShapeMesh.GetReference(physicsScene, true, prim);

                if (meshShape.physShapeInfo.HasPhysicalShape)
                {
                    HACDParams parms = new HACDParams();
                    parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull;
                    parms.minClusters = BSParam.BHullMinClusters;
                    parms.compacityWeight = BSParam.BHullCompacityWeight;
                    parms.volumeWeight = BSParam.BHullVolumeWeight;
                    parms.concavity = BSParam.BHullConcavity;
                    parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints);
                    parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints);
                    parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints);
                    parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin);
                    parms.whichHACD = 0; // Use the HACD routine that comes with Bullet

                    physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID,
                        newShape.HasPhysicalShape);
                    newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms);
                    physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID,
                        newShape);

                    // Now done with the mesh shape.
                    shapeInfo.HullCount = 1;
                    BSShapeMesh maybeMesh = meshShape as BSShapeMesh;
                    if (maybeMesh != null)
                        shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices);
                    meshShape.Dereference(physicsScene);
                }
                physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID,
                    newShape.HasPhysicalShape);
            }

            // If no other hull specifications, use our HACD hull approximation.
            if (!newShape.HasPhysicalShape && meshData != null)
            {
                if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched)
                {
                    // Release the fetched asset data once it has been used.
                    pbs.SculptData = new byte[0];
                    prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown;
                }

                int[] indices = meshData.getIndexListAsInt();

                //format conversion from IMesh format to DecompDesc format
                List<int> convIndices = new List<int>();
                List<float3> convVertices = new List<float3>();
                for (int ii = 0; ii < indices.GetLength(0); ii++)
                {
                    convIndices.Add(indices[ii]);
                }

// greythane - use the integer array instead of OS type vertex list
//                List<OMV.Vector3> vertices = meshData.getVertexList();
//                foreach (OMV.Vector3 vv in vertices)
//                {
//                    convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
//                }
                var vertices = meshData.getVertexListAsFloat();
                var vertexCount = vertices.Length / 3;
                for (int i = 0; i < vertexCount; i++)
                {
                    convVertices.Add(new float3(vertices[3 * i + 0], vertices[3 * i + 1], vertices[3 * i + 2]));
                }

                uint maxDepthSplit = (uint) BSParam.CSHullMaxDepthSplit;
                if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes)
                {
                    // Simple primitive shapes we know are convex so they are better implemented with
                    //    fewer hulls.
                    // Check for simple shape (prim without cuts) and reduce split parameter if so.
                    if (BSShapeCollection.PrimHasNoCuts(pbs))
                    {
                        maxDepthSplit = (uint) BSParam.CSHullMaxDepthSplitForSimpleShapes;
                    }
                }

                // setup and do convex hull conversion
                m_hulls = new List<ConvexResult>();
                DecompDesc dcomp = new DecompDesc();
                dcomp.mIndices = convIndices;
                dcomp.mVertices = convVertices;
                dcomp.mDepth = maxDepthSplit;
                dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent;
                dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent;
                dcomp.mMaxVertices = (uint) BSParam.CSHullMaxVertices;
                dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth;
                ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
                // create the hull into the _hulls variable
                convexBuilder.process(dcomp);

                physicsScene.DetailLog(
                    "{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}",
                    BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Length, maxDepthSplit,
                    m_hulls.Count);

                // Convert the vertices and indices for passing to unmanaged.
                // The hull information is passed as a large floating point array.
                // The format is:
                //  convHulls[0] = number of hulls
                //  convHulls[1] = number of vertices in first hull
                //  convHulls[2] = hull centroid X coordinate
                //  convHulls[3] = hull centroid Y coordinate
                //  convHulls[4] = hull centroid Z coordinate
                //  convHulls[5] = first hull vertex X
                //  convHulls[6] = first hull vertex Y
                //  convHulls[7] = first hull vertex Z
                //  convHulls[8] = second hull vertex X
                //  ...
                //  convHulls[n] = number of vertices in second hull
                //  convHulls[n+1] = second hull centroid X coordinate
                //  ...
                //
                // TODO: is is very inefficient. Someday change the convex hull generator to return
                //   data structures that do not need to be converted in order to pass to Bullet.
                //   And maybe put the values directly into pinned memory rather than marshaling.
                int hullCount = m_hulls.Count;
                int totalVertices = 1; // include one for the count of the hulls
                foreach (ConvexResult cr in m_hulls)
                {
                    totalVertices += 4; // add four for the vertex count and centroid
                    totalVertices += cr.HullIndices.Count*3; // we pass just triangles
                }
                float[] convHulls = new float[totalVertices];

                convHulls[0] = (float) hullCount;
                int jj = 1;
                foreach (ConvexResult cr in m_hulls)
                {
                    // copy vertices for index access
                    float3[] verts = new float3[cr.HullVertices.Count];
                    int kk = 0;
                    foreach (float3 ff in cr.HullVertices)
                    {
                        verts[kk++] = ff;
                    }

                    // add to the array one hull's worth of data
                    convHulls[jj++] = cr.HullIndices.Count;
                    convHulls[jj++] = 0f; // centroid x,y,z
                    convHulls[jj++] = 0f;
                    convHulls[jj++] = 0f;
                    foreach (int ind in cr.HullIndices)
                    {
                        convHulls[jj++] = verts[ind].x;
                        convHulls[jj++] = verts[ind].y;
                        convHulls[jj++] = verts[ind].z;
                    }
                }
                // create the hull data structure in Bullet
                newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls);
            }
            newShape.shapeKey = newHullKey;
            return newShape;
        }
 public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot,
     bool shouldRecalculateLocalAabb);
 public BSShapeCompound(BulletShape pShape) : base(pShape)
 {
 }
        // Create terrain mesh from a heightmap.
        public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap,
                             Vector3 minCoords, Vector3 maxCoords)
            : base(physicsScene, regionBase, id)
        {
            int indicesCount;

            int[] indices;
            int   verticesCount;

            float[] vertices;

            m_savedHeightMap = initialMap;

            m_sizeX = (int)(maxCoords.X - minCoords.X);
            m_sizeY = (int)(maxCoords.Y - minCoords.Y);

            bool meshCreationSuccess = false;

            if (BSParam.TerrainMeshMagnification == 1)
            {
                // If a magnification of one, use the old routine that is tried and true.
                meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(PhysicsScene,
                                                                           initialMap, m_sizeX, m_sizeY, // input size
                                                                           Vector3.Zero,                 // base for mesh
                                                                           out indicesCount, out indices, out verticesCount, out vertices);
            }
            else
            {
                // Other magnifications use the newer routine
                meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(PhysicsScene,
                                                                            initialMap, m_sizeX, m_sizeY, // input size
                                                                            BSParam.TerrainMeshMagnification,
                                                                            physicsScene.TerrainManager.WorldMax,
                                                                            Vector3.Zero, // base for mesh
                                                                            out indicesCount, out indices, out verticesCount, out vertices);
            }
            if (!meshCreationSuccess)
            {
                // DISASTER!!
                PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}",
                                       BSScene.DetailLogZero, ID);
                PhysicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader,
                                                TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshid,id={1},indices={2},indSz={3},vertices={4},vertSz={5}",
                                   BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length);

            m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount,
                                                             vertices);

            if (!m_terrainShape.HasPhysicalShape)
            {
                // DISASTER!!
                PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero,
                                       ID);
                PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            Vector3    pos = regionBase;
            Quaternion rot = Quaternion.Identity;

            m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
            if (!m_terrainBody.HasPhysicalBody)
            {
                // DISASTER!!
                PhysicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
                // Something is very messed up and a crash is in our future.
                return;
            }

            physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin);

            // Set current terrain attributes
            PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
            PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
            PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
            PhysicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold);
            PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);

            // Static objects are not very massive.
            PhysicsScene.PE.SetMassProps(m_terrainBody, 0.1f, Vector3.Zero);

            // Put the new terrain to the world of physical objects
            PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);

            // Redo its bounding box now that it is in the world
            PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);

            m_terrainBody.collisionType = CollisionType.Terrain;
            m_terrainBody.ApplyCollisionMask(PhysicsScene);

            if (BSParam.UseSingleSidedMeshes)
            {
                PhysicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id);
                PhysicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
            }

            // Make it so the terrain will not move or be considered for movement.
            PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
        }