Beispiel #1
0
        /// <summary>
        /// Put it all together
        /// </summary>
        private unsafe void SmashMesh(
            int userId,
            int vertComponentCount,
            int polyCount,
            IntPtr vertComponentsPtr,

            int totalPolyIndexCount,                                            // count of all vertex indices in all polys
            IntPtr pIndexCountsPtr,
            IntPtr pIndicesPtr,
            IntPtr pNeighborsPtr,
            IntPtr pFlagsPtr,
            IntPtr polyAreasAndTypesPtr
            )
        {
            //var coords = GetTileCoords(userId);
            //var tile = Terrain.GetTile(coords);

            //if (tile == null)
            //{
            //    throw new Exception("Invalid tile: " + id);
            //}

            // read native data
            var vertComponents    = (float *)vertComponentsPtr;
            var pIndexCounts      = (byte *)pIndexCountsPtr;
            var pIndices          = (uint *)pIndicesPtr;
            var pNeighbors        = (uint *)pNeighborsPtr;
            var pFlags            = (ushort *)pFlagsPtr;
            var polyAreasAndTypes = (byte *)polyAreasAndTypesPtr;


            // create vertices array
            var indices   = new int[totalPolyIndexCount];
            var vertCount = vertComponentCount / 3;

            List <Vector3> vertexList;

            using (LargeObjectPools.Vector3ListPool.Borrow(out vertexList))
            {
                var min = new Vector3(Single.MaxValue, Single.MaxValue, Single.MaxValue);
                var max = new Vector3(Single.MinValue, Single.MinValue, Single.MinValue);

                for (int i = 0, v = 0; i < vertCount; i++, v += 3)
                {
                    var vert = new Vector3(vertComponents[v], vertComponents[v + 1], vertComponents[v + 2]);
                    RecastUtil.TransformRecastCoordsToWoWCoords(ref vert);
                    vertexList.Add(vert);

                    // expand bounding box
                    min.X = Math.Min(min.X, vert.X);
                    min.Y = Math.Min(min.Y, vert.Y);
                    min.Z = Math.Min(min.Z, vert.Z);

                    max.X = Math.Max(max.X, vert.X);
                    max.Y = Math.Max(max.Y, vert.Y);
                    max.Z = Math.Max(max.Z, vert.Z);
                }

                Min = min;
                Max = max;

                var vertices = EliminateDoubleVertices(vertexList, pIndices, totalPolyIndexCount);

                // polygon first pass -> Create polygons
                var polys         = new NavMeshPolygon[polyCount];
                var polyEdgeIndex = 0;
                var p             = 0;
                for (var i = 0; i < polyCount; i++)
                {
                    var polyIndexCount = pIndexCounts[i];
                    var poly           = polys[i] = new NavMeshPolygon();
                    poly.Indices   = new int[polyIndexCount];
                    poly.Neighbors = new int[polyIndexCount];

                    Debug.Assert(3 == polyIndexCount);

                    for (var j = 0; j < polyIndexCount; j++)
                    {
                        var idx = (int)pIndices[polyEdgeIndex + j];
                        indices[p++]      = idx;
                        poly.Indices[j]   = idx;
                        poly.Neighbors[j] = -1;

                        Debug.Assert(poly.Indices[j] >= 0 && poly.Indices[j] < vertCount);
                    }

                    // switch first and third index because our collision test needs the triangles to go in the other direction
                    var tmp = poly.Indices[0];
                    indices[p - 3] = poly.Indices[0] = poly.Indices[2];
                    indices[p - 1] = poly.Indices[2] = tmp;

                    polyEdgeIndex += polyIndexCount;
                }

                // polygon second pass -> Initialize neighbors
                polyEdgeIndex = 0;

                var undecidedNeighborRelations = new List <Tuple <int, int> >();
                for (var i = 0; i < polyCount; i++)
                {
                    var poly           = polys[i];
                    var polyIndexCount = pIndexCounts[i];
                    var a = poly.Indices[0];
                    var b = poly.Indices[1];
                    var c = poly.Indices[2];

                    for (var j = 0; j < polyIndexCount; j++)
                    {
                        var neighbor = (int)pNeighbors[polyEdgeIndex + j];
                        if (neighbor == -1)
                        {
                            continue;
                        }

                        var neighborPoly = polys[neighbor];

                        // sort the neighbor poly into the array of neighbors, correctly
                        var a2 = neighborPoly.Indices[0];
                        var b2 = neighborPoly.Indices[1];
                        var c2 = neighborPoly.Indices[2];


                        var nCount = 0;
                        var mask   = 0;
                        if (a == a2 || a == b2 || a == c2)
                        {
                            // some vertex matches the first vertex of the triangle
                            nCount++;
                            mask |= TerrainUtil.TrianglePointA;
                        }
                        if (b == a2 || b == b2 || b == c2)
                        {
                            // some vertex matches the second vertex of the triangle
                            nCount++;
                            mask |= TerrainUtil.TrianglePointB;
                        }
                        if (c == a2 || c == b2 || c == c2)
                        {
                            // some vertex matches the third vertex of the triangle
                            nCount++;
                            mask |= TerrainUtil.TrianglePointC;
                        }


                        //var va = vertices[a];
                        //var vb = vertices[b];
                        //var vc = vertices[c];
                        //var ua = vertices[a2];
                        //var ub = vertices[b2];
                        //var uc = vertices[c2];

                        //var vs = new List<Vector3>() { va, vb, vc };
                        //var us = new List<Vector3>() { ua, ub, uc };
                        //var mc = 0;
                        //for (var ii = 0; ii < vs.Count; ii++)
                        //{
                        //    var vv = vs[ii];
                        //    for (var jj = 0; jj < us.Count; jj++)
                        //    {
                        //        var uu = us[jj];
                        //        if (vv.Equals(uu))
                        //        {
                        //            mc++;
                        //            break;
                        //        }
                        //    }
                        //}
                        //Debug.Assert(mc == 2);
                        //Debug.Assert(nCount == 2);

                        if (nCount < 2)
                        {
                            undecidedNeighborRelations.Add(Tuple.Create(i, neighbor));
                        }

                        var edge = TerrainUtil.GetEdge(mask);
                        if (edge != -1)
                        {
                            poly.Neighbors[edge] = neighbor;
                        }
                    }

                    polyEdgeIndex += polyIndexCount;
                }

                // these relations are incorrect for some reason
                // the actual neighbor that is to replace the undecided neighbor is also in this set, though
                for (var i = 0; i < undecidedNeighborRelations.Count; i++)
                {
                    var rel = undecidedNeighborRelations[i];

                    var poly = polys[rel.Item1];
                    var tri  = poly.GetTriangle(vertices);

                    for (var j = 0; j < undecidedNeighborRelations.Count; j++)
                    {
                        if (i == j)
                        {
                            continue;
                        }

                        var index2 = undecidedNeighborRelations[j].Item1;
                        var poly2  = polys[index2];
                        var tri2   = poly2.GetTriangle(vertices);

                        var sharedMask = tri.GetSharedEdgeMask(tri2);
                        var edge       = TerrainUtil.GetEdge(sharedMask);
                        if (edge != -1)
                        {
                            // the two share an edge
                            poly.Neighbors[edge] = index2;
                            break;
                        }
                    }
                }

                // make sure, the neighbor relation is symmetric
                for (var i = 0; i < polys.Length; i++)
                {
                    var poly = polys[i];
                    for (int j = 0; j < poly.Neighbors.Length; j++)
                    {
                        var neighbor = poly.Neighbors[j];
                        if (neighbor == -1)
                        {
                            continue;
                        }

                        var neighborPoly = polys[neighbor];
                        var found        = false;
                        for (var k = 0; k < neighborPoly.Neighbors.Length; k++)
                        {
                            var neighneigh = neighborPoly.Neighbors[k];
                            if (neighneigh == i)
                            {
                                found = true;
                                break;
                            }
                        }

                        if (!found)
                        {
                            // neighbor of poly does not have poly as neighor
                            // find the edge and insert the neighbor
                            var tri        = poly.GetTriangle(vertices);
                            var tri2       = neighborPoly.GetTriangle(vertices);
                            var sharedMask = tri2.GetSharedEdgeMask(tri);
                            var edge       = TerrainUtil.GetEdge(sharedMask);
                            Debug.Assert(neighborPoly.Neighbors[edge] == -1);

                            neighborPoly.Neighbors[edge] = i;
                            break;
                        }
                    }
                }

                // create new NavMesh object
                Tile.NavMesh = new NavMesh(Tile, polys, vertices, indices);
            }
        }