/// <summary> /// Gets the data from the mesh buffers. /// </summary> /// <remarks> /// <para> /// This method is useful for extracting mesh data so it can be inspected or altered /// and reloaded. /// </para> /// </remarks> /// <param name="includeBuffer"> /// If true, includes the unused buffer space. Otherwise only the used buffer data is /// returned. /// </param> /// <returns>The data from the mesh buffers.</returns> public PolyMeshData GetData(bool includeBuffer) { int mp = (includeBuffer ? root.maxPolys : root.polyCount); int mv = (includeBuffer ? mMaxVerts : root.vertCount); PolyMeshData buffer = new PolyMeshData(mv , mp , root.maxVertsPerPoly); FillData(buffer); return(buffer); }
/// <summary> /// Loads the data from the mesh buffers into the data object. /// </summary> /// <remarks> /// <para> /// A new buffer will be returned if the buffer argument is null. /// </para> /// <para> /// The buffer will be automatically resized if it is too small to hold the result. /// </para> /// <para> /// Only the used portions of the mesh buffers are copied. /// </para> /// </remarks> /// <param name="buffer">A buffer to load the data into.</param> /// <returns>A reference to the mesh data.</returns> public PolyMeshData GetData(PolyMeshData buffer) { if (IsDisposed) { return(null); } if (buffer == null) { return(GetData(true)); } if (!buffer.CanFit(root.vertCount , root.polyCount , root.maxVertsPerPoly)) { buffer.Resize(mMaxVerts, root.maxPolys, root.maxVertsPerPoly); } FillData(buffer); return(buffer); }
private void FillData(PolyMeshData buffer) { buffer.maxVertsPerPoly = root.maxVertsPerPoly; buffer.boundsMax = BoundsMax; buffer.boundsMin = BoundsMin; buffer.yCellSize = root.yCellSize; buffer.xzCellSize = root.xzCellSize; buffer.polyCount = root.polyCount; buffer.vertCount = root.vertCount; buffer.walkableStep = mWalkableStep; buffer.walkableHeight = mWalkableHeight; buffer.walkableRadius = mWalkableRadius; buffer.borderSize = root.borderSize; UtilEx.Copy(root.polys , buffer.polys , root.polyCount * 2 * root.maxVertsPerPoly); Marshal.Copy(root.areas, buffer.areas, 0, root.polyCount); UtilEx.Copy(root.flags, buffer.flags, root.polyCount); UtilEx.Copy(root.regions, buffer.regions, root.polyCount); UtilEx.Copy(root.verts, buffer.verts, root.vertCount * 3); }
/// <summary> /// Draws a debug view of a <see cref="PolyMeshData"/> object. /// </summary> /// <remarks> /// <para> /// Meant to be called during the MonoBehavior.OnRenderObject() method. /// </para> /// </remarks> /// <param name="polyData">The polygon mesh to draw.</param> public static void Draw(PolyMeshData polyData) { DebugDraw.SimpleMaterial.SetPass(0); Color walkableColor = new Color(0, 0.75f, 1.0f, 0.25f); Color nullRegionColor = new Color(0, 0, 0, 0.25f); int[] pTargetVert = new int[3]; GL.Begin(GL.TRIANGLES); for (int iPoly = 0; iPoly < polyData.polyCount; iPoly++) { int pPoly = iPoly * polyData.maxVertsPerPoly * 2; if (polyData.areas[iPoly] == NMGen.MaxArea) GL.Color(walkableColor); else if (polyData.areas[iPoly] == NMGen.NullRegion) GL.Color(nullRegionColor); else GL.Color(ColorUtil.IntToColor(polyData.areas[iPoly], 1.0f)); pTargetVert[0] = polyData.polys[pPoly + 0] * 3; for (int iPolyVert = 2 ; iPolyVert < polyData.maxVertsPerPoly ; iPolyVert++) { if (polyData.polys[pPoly + iPolyVert] == PolyMesh.NullIndex) break; pTargetVert[1] = polyData.polys[pPoly + iPolyVert] * 3; pTargetVert[2] = polyData.polys[pPoly + iPolyVert - 1] * 3; for (int i = 0; i < 3; i++) { int p = pTargetVert[i]; int x = polyData.verts[p + 0]; // Offset y a little to ensure it clears the // source geometry. int y = polyData.verts[p + 1] + 1; int z = polyData.verts[p + 2]; GL.Vertex3(polyData.boundsMin[0] + x * polyData.xzCellSize , polyData.boundsMin[1] + y * polyData.yCellSize , polyData.boundsMin[2] + z * polyData.xzCellSize); } } } GL.End(); Color internalEdgeColor = new Color(0, 0.2f, 0.25f, 0.25f); Color boundaryEdgeColor = new Color(0.65f, 0.2f, 0, 0.9f); GL.Begin(GL.LINES); for (int iPoly = 0; iPoly < polyData.polyCount; iPoly++) { int pPoly = iPoly * polyData.maxVertsPerPoly * 2; for (int iPolyVert = 0; iPolyVert < polyData.maxVertsPerPoly; iPolyVert++) { int iv = polyData.polys[pPoly + iPolyVert]; if (iv == PolyMesh.NullIndex) break; if (polyData.polys[pPoly + polyData.maxVertsPerPoly + iPolyVert] == PolyMesh.NullIndex) { GL.Color(boundaryEdgeColor); } else GL.Color(internalEdgeColor); // Note: Using only first two indexes. pTargetVert[0] = iv * 3; if (iPolyVert + 1 >= polyData.maxVertsPerPoly) { // Reached hard end of polygon. Loop back. iv = polyData.polys[pPoly + 0]; } else { iv = polyData.polys[pPoly + iPolyVert + 1]; if (iv == PolyMesh.NullIndex) // Reached soft end of polygon. Loop back. iv = polyData.polys[pPoly + 0]; } pTargetVert[1] = iv * 3; for (int i = 0; i < 2; i++) { int p = pTargetVert[i]; int x = polyData.verts[p + 0]; // Offset y a little to ensure it clears the // source geometry. int y = polyData.verts[p + 1] + 1; int z = polyData.verts[p + 2]; GL.Vertex3(polyData.boundsMin[0] + x * polyData.xzCellSize , polyData.boundsMin[1] + y * polyData.yCellSize , polyData.boundsMin[2] + z * polyData.xzCellSize); } } } GL.End(); }
/// <summary> /// Creates a standard <see cref="NavmeshTileBuildData"/> object from the provided /// parameters. /// </summary> /// <remarks> /// <para> /// Errors will be logged to the build context. /// </para> /// </remarks> /// <param name="tx">The x-index of the tile.</param> /// <param name="tz">The z-index of the tile.</param> /// <param name="polyMesh">The polygon mesh data.</param> /// <param name="detailMesh">The detail mesh data. (Optional)</param> /// <param name="connections">The off-mesh connections. (Null allowed.)</param> /// <param name="bvTreeEnabled">True if bounding volumes should be generated.</param> /// <param name="context">The build context.</param> /// <returns>The tile build data, or null on error.</returns> public static NavmeshTileBuildData GetBuildData(BuildContext context , int tx, int tz , PolyMeshData polyMesh, PolyMeshDetailData detailMesh , ConnectionSet connections , bool bvTreeEnabled) { if (context == null) // Silent. return null; Vector3[] verts = null; float[] radii = null; byte[] dirs = null; byte[] areas = null; ushort[] flags = null; uint[] userIds = null; Vector3 bmin = polyMesh.boundsMin; Vector3 bmax = polyMesh.boundsMax; int connCount = (connections == null) ? 0 : connections.GetConnections(bmin.x, bmin.z, bmax.x, bmax.z , out verts, out radii, out dirs, out areas, out flags, out userIds); NavmeshTileBuildData result = new NavmeshTileBuildData( polyMesh.vertCount , polyMesh.polyCount , polyMesh.maxVertsPerPoly , (detailMesh == null ? 0 : detailMesh.vertCount) , (detailMesh == null ? 0 : detailMesh.triCount) , connCount); if (!result.LoadBase(tx, tz, 0, 0 , polyMesh.boundsMin , polyMesh.boundsMax , polyMesh.xzCellSize , polyMesh.yCellSize , polyMesh.walkableHeight , polyMesh.walkableRadius , polyMesh.walkableStep , bvTreeEnabled)) { context.LogError("Base data load failed. Bad configuration data or internal error." , null); return null; } if (!result.LoadPolys(polyMesh.verts , polyMesh.vertCount , polyMesh.polys , polyMesh.flags , polyMesh.areas , polyMesh.polyCount)) { context.LogError("Polygon load failed. Bad mesh data or internal error.", null); return null; } if (detailMesh != null) { if (!result.LoadDetail(detailMesh.verts , detailMesh.vertCount , detailMesh.tris , detailMesh.triCount , detailMesh.meshes , detailMesh.meshCount)) { context.LogError("Detail load failed. Bad mesh data or internal error.", null); return null; } } if (connCount > 0) { if (!result.LoadConns(verts, radii, dirs, areas, flags, userIds, connCount)) { context.LogError("Off-mesh connection load failed. Bad data or internal error." , null); return null; } } return result; }
/// <summary> /// Loads the data into the mesh buffers, overwriting existing content. /// </summary> /// <param name="data">The data to load.</param> /// <returns>True if the load was successful.</returns> public bool Load(PolyMeshData data) { int vcount = (data.verts == null || data.vertCount < 3 ? 0 : data.vertCount); int pcount = (data.polys == null || data.polyCount < 1 ? 0 : data.polyCount); if (pcount == 0 || pcount > root.maxPolys || vcount == 0 || vcount > mMaxVerts || data.xzCellSize < NMGen.MinCellSize || data.yCellSize < NMGen.MinCellSize || data.walkableHeight < NMGen.MinWalkableHeight * NMGen.MinCellSize || data.walkableStep < 0 || data.walkableRadius < 0 || data.borderSize < 0 || data.polys.Length < (pcount * 2 * root.maxVertsPerPoly) || data.verts.Length < (vcount * 3) || (data.areas != null && data.areas.Length < pcount) || (data.regions != null && data.regions.Length < pcount) || (data.flags != null && data.flags.Length < pcount)) { return(false); } root.polyCount = pcount; root.vertCount = vcount; root.xzCellSize = data.xzCellSize; root.yCellSize = data.yCellSize; mWalkableHeight = data.walkableHeight; mWalkableRadius = data.walkableRadius; mWalkableStep = data.walkableStep; root.borderSize = data.borderSize; root.boundsMin = data.boundsMin; root.boundsMax = data.boundsMax; UtilEx.Copy(data.verts, 0, root.verts, root.vertCount * 3); UtilEx.Copy(data.polys , 0 , root.polys , root.polyCount * 2 * root.maxVertsPerPoly); if (data.regions == null) { UtilEx.ZeroMemory(root.regions, sizeof(ushort) * root.polyCount); } else { UtilEx.Copy(data.regions, 0, root.regions, root.polyCount); } if (data.flags == null) { UtilEx.ZeroMemory(root.flags, sizeof(ushort) * root.polyCount); } else { UtilEx.Copy(data.flags, 0, root.flags, root.polyCount); } if (data.areas == null) { UtilEx.ZeroMemory(root.areas, sizeof(byte) * root.polyCount); } else { Marshal.Copy(data.areas, 0, root.areas, root.polyCount); } return(true); }
/// <summary> /// Loads the data from the mesh buffers into the data object. /// </summary> /// <remarks> /// <para> /// A new buffer will be returned if the buffer argument is null. /// </para> /// <para> /// The buffer will be automatically resized if it is too small to hold the result. /// </para> /// <para> /// Only the used portions of the mesh buffers are copied. /// </para> /// </remarks> /// <param name="buffer">A buffer to load the data into.</param> /// <returns>A reference to the mesh data.</returns> public PolyMeshData GetData(PolyMeshData buffer) { if (IsDisposed) return null; if (buffer == null) return GetData(true); if (!buffer.CanFit(root.vertCount , root.polyCount , root.maxVertsPerPoly)) { buffer.Resize(mMaxVerts, root.maxPolys, root.maxVertsPerPoly); } FillData(buffer); return buffer; }
/// <summary> /// Gets the data from the mesh buffers. /// </summary> /// <remarks> /// <para> /// This method is useful for extracting mesh data so it can be inspected or altered /// and reloaded. /// </para> /// </remarks> /// <param name="includeBuffer"> /// If true, includes the unused buffer space. Otherwise only the used buffer data is /// returned. /// </param> /// <returns>The data from the mesh buffers.</returns> public PolyMeshData GetData(bool includeBuffer) { int mp = (includeBuffer ? root.maxPolys : root.polyCount); int mv = (includeBuffer ? mMaxVerts : root.vertCount); PolyMeshData buffer = new PolyMeshData(mv , mp , root.maxVertsPerPoly); FillData(buffer); return buffer; }
/// <summary> /// Loads the data into the mesh buffers, overwriting existing content. /// </summary> /// <param name="data">The data to load.</param> /// <returns>True if the load was successful.</returns> public bool Load(PolyMeshData data) { int vcount = (data.verts == null || data.vertCount < 3 ? 0 : data.vertCount); int pcount = (data.polys == null || data.polyCount < 1 ? 0 : data.polyCount); if (pcount == 0 || pcount > root.maxPolys || vcount == 0 || vcount > mMaxVerts || data.xzCellSize < NMGen.MinCellSize || data.yCellSize < NMGen.MinCellSize || data.walkableHeight < NMGen.MinWalkableHeight * NMGen.MinCellSize || data.walkableStep < 0 || data.walkableRadius < 0 || data.borderSize < 0 || data.polys.Length < (pcount * 2 * root.maxVertsPerPoly) || data.verts.Length < (vcount * 3) || (data.areas != null && data.areas.Length < pcount) || (data.regions != null && data.regions.Length < pcount) || (data.flags != null && data.flags.Length < pcount)) { return false; } root.polyCount = pcount; root.vertCount = vcount; root.xzCellSize = data.xzCellSize; root.yCellSize = data.yCellSize; mWalkableHeight = data.walkableHeight; mWalkableRadius = data.walkableRadius; mWalkableStep = data.walkableStep; root.borderSize = data.borderSize; root.boundsMin = data.boundsMin; root.boundsMax = data.boundsMax; UtilEx.Copy(data.verts, 0, root.verts, root.vertCount * 3); UtilEx.Copy(data.polys , 0 , root.polys , root.polyCount * 2 * root.maxVertsPerPoly); if (data.regions == null) UtilEx.ZeroMemory(root.regions, sizeof(ushort) * root.polyCount); else UtilEx.Copy(data.regions, 0, root.regions, root.polyCount); if (data.flags == null) UtilEx.ZeroMemory(root.flags, sizeof(ushort) * root.polyCount); else UtilEx.Copy(data.flags, 0, root.flags, root.polyCount); if (data.areas == null) UtilEx.ZeroMemory(root.areas, sizeof(byte) * root.polyCount); else Marshal.Copy(data.areas, 0, root.areas, root.polyCount); return true; }