private void ComputeDirectionFlags(GeoSpace geoSpace) { // run in 2 passes to avoid "collection was modified". for (int interleave = 0; interleave < 2; interleave++) { Parallel.For(0, m_blockHeight, new ParallelOptions { MaxDegreeOfParallelism = OPTION_PARALLEL_THREADS }, (y) => { if (y % 2 == interleave) { return; } int i = y * m_blockWidth; // index to floor cell for (int x = 0; x < m_blockWidth; x++, i++) { List <NavMeshBuilderFloorDesc> heights = m_floorData[i]; if (heights == null) { continue; } for (int f = 0; f < heights.Count; f++) { int z100 = heights[f].Z100i; byte newFlags = GetBlockedDirections(geoSpace, x, y, z100); heights[f] = new NavMeshBuilderFloorDesc(z100, newFlags); } } }); } }
// WARNING! on failure, m_floorData will be left in a bad state. private void FixDirectionFlagsToMatchSubgraphs(Dictionary <EdgeVertex, List <EdgeVertex> > edges, List <HashSet <EdgeVertex> > subgraphs) { // mark all directions as blocked, then for each subgraph // visit edges/vertices and unblock directions. // clear all to 'blocked' foreach (var fl in m_floorData) { if (fl != null) { for (int i = 0; i < fl.Count; i++) { fl[i] = new NavMeshBuilderFloorDesc(fl[i].Z100i, 0xFF); } } } foreach (var sg in subgraphs) { foreach (var v in sg) { var neighborEdges = edges[v]; foreach (var n in neighborEdges) { var dirToNeighbor = NavMeshUtil.DetermineDirection(v.BX, v.BY, n.BX, n.BY); var dirFromNeighbor = NavMeshUtil.GetInverseDirection(dirToNeighbor); // update 'to' neighbor // need to find which floor data entry is mine var meContainedInList = m_floorData[v.BY * m_blockWidth + v.BX]; // next, find me bool foundMe = false; for (int j = 0; j < meContainedInList.Count; j++) { if (meContainedInList[j].Z100i == v.Z100i) { // unblock me to neighbor meContainedInList[j] = new NavMeshBuilderFloorDesc(v.Z100i, (byte)(meContainedInList[j].DirectionFlags & ~dirToNeighbor)); foundMe = true; break; } } if (!foundMe) { throw new InvalidOperationException("vertex should exist in floor data!"); } // update 'from' neighbor var neighborContainedInList = m_floorData[n.BY * m_blockWidth + n.BX]; bool foundNeighbor = false; for (int j = 0; j < neighborContainedInList.Count; j++) { if (neighborContainedInList[j].Z100i == n.Z100i) { // unblock neighbor to me neighborContainedInList[j] = new NavMeshBuilderFloorDesc(n.Z100i, (byte)(neighborContainedInList[j].DirectionFlags & ~dirFromNeighbor)); foundNeighbor = true; break; } } if (!foundNeighbor) { throw new InvalidOperationException("neighbor vertex should exist in floor data!"); } } } } }