//
    // CALL THIS ON GAME OBJECT THAT HAS GEOMETRY ATTACHED TO IT
    //
    private int uploadMesh(IntPtr geometryHandle, GameObject meshObject, Matrix4x4 worldToLocal, bool ignoreStatic)
    {
        // Get the child mesh objects.
        List <MeshMaterial>    meshes   = new List <MeshMaterial>();
        List <TerrainMaterial> terrains = new List <TerrainMaterial>();

        traverseMeshHierarchy(meshObject, null, includeChildMeshes, meshes, terrains, ignoreStatic);

        //***********************************************************************
        // Count the number of vertices and indices.

        int  totalVertexCount   = 0;
        uint totalIndexCount    = 0;
        int  totalFaceCount     = 0;
        int  totalMaterialCount = 0;

        foreach (MeshMaterial m in meshes)
        {
            Mesh mesh = m.meshFilter.sharedMesh;

            totalMaterialCount += mesh.subMeshCount;
            totalVertexCount   += mesh.vertexCount;

            for (int i = 0; i < mesh.subMeshCount; i++)
            {
                MeshTopology topology = mesh.GetTopology(i);
                if (topology == MeshTopology.Triangles || topology == MeshTopology.Quads)
                {
                    uint meshIndexCount = mesh.GetIndexCount(i);
                    totalIndexCount += meshIndexCount;

                    if (topology == MeshTopology.Triangles)
                    {
                        totalFaceCount += (int)meshIndexCount / 3;
                    }
                    else if (topology == MeshTopology.Quads)
                    {
                        totalFaceCount += (int)meshIndexCount / 4;
                    }
                }
            }
        }

        foreach (TerrainMaterial t in terrains)
        {
            TerrainData terrain = t.terrain.terrainData;

            int w           = terrain.heightmapWidth;
            int h           = terrain.heightmapHeight;
            int wRes        = (w - 1) / terrainDecimation + 1;
            int hRes        = (h - 1) / terrainDecimation + 1;
            int vertexCount = wRes * hRes;
            int indexCount  = (wRes - 1) * (hRes - 1) * 6;

            totalMaterialCount++;
            totalVertexCount += vertexCount;
            totalIndexCount  += (uint)indexCount;
            totalFaceCount   += indexCount / 3;
        }

        //***********************************************************************
        // Copy the mesh data.

        List <Vector3> tempVertices = new List <Vector3>();
        List <int>     tempIndices  = new List <int>();

        MeshGroup[] groups   = new MeshGroup[totalMaterialCount];
        float[]     vertices = new float[totalVertexCount * 3];
        int[]       indices  = new int[totalIndexCount];

        int vertexOffset = 0;
        int indexOffset  = 0;
        int groupOffset  = 0;

        foreach (MeshMaterial m in meshes)
        {
            MeshFilter meshFilter = m.meshFilter;
            Mesh       mesh       = meshFilter.sharedMesh;

            // Compute the combined transform to go from mesh-local to geometry-local space.
            Matrix4x4 matrix = worldToLocal * meshFilter.gameObject.transform.localToWorldMatrix;

            // Get the mesh vertices.
            tempVertices.Clear();
            mesh.GetVertices(tempVertices);

            // Copy the Vector3 vertices into a packed array of floats for the API.
            int meshVertexCount = tempVertices.Count;
            for (int i = 0; i < meshVertexCount; i++)
            {
                // Transform into the parent space.
                Vector3 v      = matrix.MultiplyPoint3x4(tempVertices[i]);
                int     offset = (vertexOffset + i) * 3;
                vertices[offset + 0] = v.x;
                vertices[offset + 1] = v.y;
                vertices[offset + 2] = v.z;
            }

            // Copy the data for each submesh.
            for (int i = 0; i < mesh.subMeshCount; i++)
            {
                MeshTopology topology = mesh.GetTopology(i);

                if (topology == MeshTopology.Triangles || topology == MeshTopology.Quads)
                {
                    // Get the submesh indices.
                    tempIndices.Clear();
                    mesh.GetIndices(tempIndices, i);
                    int subMeshIndexCount = tempIndices.Count;

                    // Copy and adjust the indices.
                    for (int j = 0; j < subMeshIndexCount; j++)
                    {
                        indices[indexOffset + j] = tempIndices[j] + vertexOffset;
                    }

                    // Initialize the group.
                    if (topology == MeshTopology.Triangles)
                    {
                        groups[groupOffset + i].faceType  = FaceType.TRIANGLES;
                        groups[groupOffset + i].faceCount = (UIntPtr)(subMeshIndexCount / 3);
                    }
                    else if (topology == MeshTopology.Quads)
                    {
                        groups[groupOffset + i].faceType  = FaceType.QUADS;
                        groups[groupOffset + i].faceCount = (UIntPtr)(subMeshIndexCount / 4);
                    }

                    groups[groupOffset + i].indexOffset = (UIntPtr)indexOffset;

                    if (m.materials != null && m.materials.Length != 0)
                    {
                        int matIndex = i;
                        if (matIndex >= m.materials.Length)
                        {
                            matIndex = m.materials.Length - 1;
                        }
                        m.materials[matIndex].StartInternal();
                        groups[groupOffset + i].material = m.materials[matIndex].materialHandle;
                    }
                    else
                    {
                        groups[groupOffset + i].material = IntPtr.Zero;
                    }

                    indexOffset += subMeshIndexCount;
                }
            }

            vertexOffset += meshVertexCount;
            groupOffset  += mesh.subMeshCount;
        }

        foreach (TerrainMaterial t in terrains)
        {
            TerrainData terrain = t.terrain.terrainData;

            // Compute the combined transform to go from mesh-local to geometry-local space.
            Matrix4x4 matrix = worldToLocal * t.terrain.gameObject.transform.localToWorldMatrix;

            int w = terrain.heightmapWidth;
            int h = terrain.heightmapHeight;
            float[,] tData = terrain.GetHeights(0, 0, w, h);

            Vector3 meshScale = terrain.size;
            meshScale = new Vector3(meshScale.x / (w - 1) * terrainDecimation, meshScale.y, meshScale.z / (h - 1) * terrainDecimation);
            int wRes          = (w - 1) / terrainDecimation + 1;
            int hRes          = (h - 1) / terrainDecimation + 1;
            int vertexCount   = wRes * hRes;
            int triangleCount = (wRes - 1) * (hRes - 1) * 2;

            // Initialize the group.
            groups[groupOffset].faceType    = FaceType.TRIANGLES;
            groups[groupOffset].faceCount   = (UIntPtr)triangleCount;
            groups[groupOffset].indexOffset = (UIntPtr)indexOffset;

            if (t.materials != null && 0 < t.materials.Length)
            {
                t.materials[0].StartInternal();
                groups[groupOffset].material = t.materials[0].materialHandle;
            }
            else
            {
                groups[groupOffset].material = IntPtr.Zero;
            }

            // Build vertices and UVs
            for (int y = 0; y < hRes; y++)
            {
                for (int x = 0; x < wRes; x++)
                {
                    int     offset = (vertexOffset + y * wRes + x) * 3;
                    Vector3 v      = matrix.MultiplyPoint3x4(Vector3.Scale(meshScale, new Vector3(y, tData[x * terrainDecimation, y * terrainDecimation], x)));
                    vertices[offset + 0] = v.x;
                    vertices[offset + 1] = v.y;
                    vertices[offset + 2] = v.z;
                }
            }

            // Build triangle indices: 3 indices into vertex array for each triangle
            for (int y = 0; y < hRes - 1; y++)
            {
                for (int x = 0; x < wRes - 1; x++)
                {
                    // For each grid cell output two triangles
                    indices[indexOffset + 0] = (vertexOffset + (y * wRes) + x);
                    indices[indexOffset + 1] = (vertexOffset + ((y + 1) * wRes) + x);
                    indices[indexOffset + 2] = (vertexOffset + (y * wRes) + x + 1);

                    indices[indexOffset + 3] = (vertexOffset + ((y + 1) * wRes) + x);
                    indices[indexOffset + 4] = (vertexOffset + ((y + 1) * wRes) + x + 1);
                    indices[indexOffset + 5] = (vertexOffset + (y * wRes) + x + 1);
                    indexOffset += 6;
                }
            }

            vertexOffset += vertexCount;
            groupOffset++;
        }

        // Upload mesh data
        return(PropIFace.AudioGeometryUploadMeshArrays(geometryHandle,
                                                       vertices, totalVertexCount,
                                                       indices, indices.Length,
                                                       groups, groups.Length));
    }