944 lines
36 KiB
C#
944 lines
36 KiB
C#
// Copyright (c) 2013-2015 Robert Rouhani <robert.rouhani@gmail.com> and other contributors (see CONTRIBUTORS file).
|
|
// Licensed under the MIT License - https://raw.github.com/Robmaister/SharpNav/master/LICENSE
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using SharpNav.Geometry;
|
|
|
|
#if MONOGAME
|
|
using Vector3 = Microsoft.Xna.Framework.Vector3;
|
|
#elif OPENTK
|
|
using Vector3 = OpenTK.Vector3;
|
|
#elif SHARPDX
|
|
using Vector3 = SharpDX.Vector3;
|
|
#endif
|
|
|
|
namespace SharpNav
|
|
{
|
|
/// <content>
|
|
/// This file contains various methods to rasterize objects into voxel data.
|
|
/// </content>
|
|
public partial class Heightfield
|
|
{
|
|
//private ConcurrentQueue<Tuple<int, int, Span>> spanQueue;
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesIndexedWithAreas(Vector3[] verts, int[] inds, Area[] areas)
|
|
{
|
|
RasterizeTrianglesIndexedWithAreas(verts, inds, 0, 1, 0, inds.Length / 3, areas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="vertOffset">An offset into the vertex array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (one Vector3 per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesIndexedWithAreas(Vector3[] verts, int[] inds, int vertOffset, int vertStride, int indexOffset, int triCount, Area[] areas)
|
|
{
|
|
int indexEnd = triCount * 3 + indexOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (inds == null)
|
|
throw new ArgumentNullException("inds");
|
|
|
|
if (indexEnd > inds.Length)
|
|
throw new ArgumentOutOfRangeException("indexCount", "The specified index offset and length end outside the provided index array.");
|
|
|
|
if (vertOffset < 0)
|
|
throw new ArgumentOutOfRangeException("vertOffset", "vertOffset must be greater than or equal to 0.");
|
|
|
|
if (vertStride < 0)
|
|
throw new ArgumentOutOfRangeException("vertStride", "vertStride must be greater than or equal to 0.");
|
|
else if (vertStride == 0)
|
|
vertStride = 1;
|
|
|
|
if (areas.Length < triCount)
|
|
throw new ArgumentException("There must be at least as many AreaFlags as there are triangles.", "areas");
|
|
|
|
for (int i = indexOffset, j = 0; i < indexEnd; i += 3, j++)
|
|
{
|
|
int indA = inds[i] * vertStride + vertOffset;
|
|
int indB = inds[i + 1] * vertStride + vertOffset;
|
|
int indC = inds[i + 2] * vertStride + vertOffset;
|
|
|
|
RasterizeTriangle(ref verts[indA], ref verts[indB], ref verts[indC], areas[j]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesIndexedWithAreas(float[] verts, int[] inds, Area[] areas)
|
|
{
|
|
RasterizeTrianglesIndexedWithAreas(verts, inds, 0, 3, 0, inds.Length / 3, areas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="floatOffset">An offset into the vertex array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesIndexedWithAreas(float[] verts, int[] inds, int floatOffset, int floatStride, int indexOffset, int triCount, Area[] areas)
|
|
{
|
|
int indexEnd = triCount * 3 + indexOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (inds == null)
|
|
throw new ArgumentNullException("inds");
|
|
|
|
if (indexEnd > inds.Length)
|
|
throw new ArgumentOutOfRangeException("indexCount", "The specified index offset and length end outside the provided index array.");
|
|
|
|
if (floatOffset < 0)
|
|
throw new ArgumentOutOfRangeException("floatOffset", "floatOffset must be greater than or equal to 0.");
|
|
|
|
if (floatStride < 0)
|
|
throw new ArgumentOutOfRangeException("floatStride", "floatStride must be greater than or equal to 0.");
|
|
else if (floatStride == 0)
|
|
floatStride = 3;
|
|
|
|
if (areas.Length < triCount)
|
|
throw new ArgumentException("There must be at least as many AreaFlags as there are triangles.", "areas");
|
|
|
|
Vector3 a, b, c;
|
|
|
|
for (int i = indexOffset, j = 0; i < indexEnd; i += 3, j++)
|
|
{
|
|
int indA = inds[i] * floatStride + floatOffset;
|
|
int indB = inds[i + 1] * floatStride + floatOffset;
|
|
int indC = inds[i + 2] * floatStride + floatOffset;
|
|
|
|
a.X = verts[indA];
|
|
a.Y = verts[indA + 1];
|
|
a.Z = verts[indA + 2];
|
|
|
|
b.X = verts[indB];
|
|
b.Y = verts[indB + 1];
|
|
b.Z = verts[indB + 2];
|
|
|
|
c.X = verts[indC];
|
|
c.Y = verts[indC + 1];
|
|
c.Z = verts[indC + 2];
|
|
|
|
RasterizeTriangle(ref a, ref b, ref c, areas[j]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(Triangle3[] tris, Area[] areas)
|
|
{
|
|
RasterizeTrianglesWithAreas(tris, 0, tris.Length, areas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
/// <param name="triOffset">An offset into the array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(Triangle3[] tris, int triOffset, int triCount, Area[] areas)
|
|
{
|
|
int triEnd = triOffset + triCount;
|
|
|
|
if (tris == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (triOffset < 0)
|
|
throw new ArgumentOutOfRangeException("triOffset", "triOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (triEnd > tris.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset and count end outside the bounds of the provided array.");
|
|
|
|
if (areas.Length < triCount)
|
|
throw new ArgumentException("There must be at least as many AreaFlags as there are triangles.", "areas");
|
|
|
|
for (int i = triOffset, j = 0; i < triEnd; i++, j++)
|
|
RasterizeTriangle(ref tris[i].A, ref tris[i].B, ref tris[i].C, areas[j]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 3, the extra vertices at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(Vector3[] verts, Area[] areas)
|
|
{
|
|
RasterizeTrianglesWithAreas(verts, 0, 1, verts.Length / 3, areas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="vertOffset">An offset into the array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (1 Vector3 per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(Vector3[] verts, int vertOffset, int vertStride, int triCount, Area[] areas)
|
|
{
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (vertOffset < 0)
|
|
throw new ArgumentOutOfRangeException("vertOffset", "vertOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (vertStride < 0)
|
|
throw new ArgumentOutOfRangeException("vertStride", "vertStride must be greater than or equal to 0.");
|
|
else if (vertStride == 0)
|
|
vertStride = 1;
|
|
|
|
int vertEnd = triCount * vertStride + vertOffset;
|
|
|
|
if (vertEnd > verts.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset, count, and stride end outside the bounds of the provided array.");
|
|
|
|
if (areas.Length < triCount)
|
|
throw new ArgumentException("There must be at least as many AreaFlags as there are triangles.", "areas");
|
|
|
|
for (int i = vertOffset, j = 0; i < vertEnd; i += vertStride * 3, j++)
|
|
RasterizeTriangle(ref verts[i], ref verts[i + vertStride], ref verts[i + vertStride * 2], areas[j]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 9, the extra floats at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(float[] verts, Area[] areas)
|
|
{
|
|
RasterizeTrianglesWithAreas(verts, 0, 3, verts.Length / 9, areas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once with per-triangle area flags.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="floatOffset">An offset into the array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="areas">An array of area flags, one for each triangle.</param>
|
|
public void RasterizeTrianglesWithAreas(float[] verts, int floatOffset, int floatStride, int triCount, Area[] areas)
|
|
{
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (floatOffset < 0)
|
|
throw new ArgumentOutOfRangeException("floatOffset", "floatOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (floatStride < 0)
|
|
throw new ArgumentOutOfRangeException("floatStride", "floatStride must be a positive integer.");
|
|
else if (floatStride == 0)
|
|
floatStride = 3;
|
|
|
|
int floatEnd = triCount * (floatStride * 3) + floatOffset;
|
|
|
|
if (floatEnd > verts.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset, count, and stride end outside the bounds of the provided array.");
|
|
|
|
if (areas.Length < triCount)
|
|
throw new ArgumentException("There must be at least as many AreaFlags as there are triangles.", "areas");
|
|
|
|
Vector3 a, b, c;
|
|
|
|
for (int i = floatOffset, j = 0; i < floatEnd; i += floatStride * 3, j++)
|
|
{
|
|
int floatStride2 = floatStride * 2;
|
|
|
|
a.X = verts[i];
|
|
a.Y = verts[i + 1];
|
|
a.Z = verts[i + 2];
|
|
|
|
b.X = verts[i + floatStride];
|
|
b.Y = verts[i + floatStride + 1];
|
|
b.Z = verts[i + floatStride + 2];
|
|
|
|
c.X = verts[i + floatStride2];
|
|
c.Y = verts[i + floatStride2 + 1];
|
|
c.Z = verts[i + floatStride2 + 2];
|
|
|
|
RasterizeTriangle(ref a, ref b, ref c, areas[j]);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
public void RasterizeTrianglesIndexed(Vector3[] verts, int[] inds)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, 0, 1, 0, inds.Length / 3, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="area">The area flags for all the triangles.</param>
|
|
public void RasterizeTrianglesIndexed(Vector3[] verts, int[] inds, Area area)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, 0, 1, 0, inds.Length / 3, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="vertOffset">An offset into the vertex array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (one Vector3 per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
public void RasterizeTrianglesIndexed(Vector3[] verts, int[] inds, int vertOffset, int vertStride, int indexOffset, int triCount)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, vertOffset, vertStride, indexOffset, triCount, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="vertOffset">An offset into the vertex array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (one Vector3 per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTrianglesIndexed(Vector3[] verts, int[] inds, int vertOffset, int vertStride, int indexOffset, int triCount, Area area)
|
|
{
|
|
int indexEnd = triCount * 3 + indexOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (inds == null)
|
|
throw new ArgumentNullException("inds");
|
|
|
|
if (indexEnd > inds.Length)
|
|
throw new ArgumentOutOfRangeException("indexCount", "The specified index offset and length end outside the provided index array.");
|
|
|
|
if (vertOffset < 0)
|
|
throw new ArgumentOutOfRangeException("vertOffset", "vertOffset must be greater than or equal to 0.");
|
|
|
|
if (vertStride < 0)
|
|
throw new ArgumentOutOfRangeException("vertStride", "vertStride must be greater than or equal to 0.");
|
|
else if (vertStride == 0)
|
|
vertStride = 1;
|
|
|
|
for (int i = indexOffset; i < indexEnd; i += 3)
|
|
{
|
|
int indA = inds[i] * vertStride + vertOffset;
|
|
int indB = inds[i + 1] * vertStride + vertOffset;
|
|
int indC = inds[i + 2] * vertStride + vertOffset;
|
|
|
|
RasterizeTriangle(ref verts[indA], ref verts[indB], ref verts[indC], area);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
public void RasterizeTrianglesIndexed(float[] verts, int[] inds)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, 0, 3, 0, inds.Length / 3, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="area">The area flags for all the triangles.</param>
|
|
public void RasterizeTrianglesIndexed(float[] verts, int[] inds, Area area)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, 0, 3, 0, inds.Length / 3, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="floatOffset">An offset into the vertex array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
public void RasterizeTrianglesIndexed(float[] verts, int[] inds, int floatOffset, int floatStride, int indexOffset, int triCount)
|
|
{
|
|
RasterizeTrianglesIndexed(verts, inds, floatOffset, floatStride, indexOffset, triCount, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once from an indexed array.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="inds">An array of indices.</param>
|
|
/// <param name="floatOffset">An offset into the vertex array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="indexOffset">An offset into the index array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTrianglesIndexed(float[] verts, int[] inds, int floatOffset, int floatStride, int indexOffset, int triCount, Area area)
|
|
{
|
|
int indexEnd = triCount * 3 + indexOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (inds == null)
|
|
throw new ArgumentNullException("inds");
|
|
|
|
if (indexEnd > inds.Length)
|
|
throw new ArgumentOutOfRangeException("indexCount", "The specified index offset and length end outside the provided index array.");
|
|
|
|
if (floatOffset < 0)
|
|
throw new ArgumentOutOfRangeException("floatOffset", "floatOffset must be greater than or equal to 0.");
|
|
|
|
if (floatStride < 0)
|
|
throw new ArgumentOutOfRangeException("floatStride", "floatStride must be greater than or equal to 0.");
|
|
else if (floatStride == 0)
|
|
floatStride = 3;
|
|
|
|
Vector3 a, b, c;
|
|
|
|
for (int i = indexOffset; i < indexEnd; i += 3)
|
|
{
|
|
int indA = inds[i] * floatStride + floatOffset;
|
|
int indB = inds[i + 1] * floatStride + floatOffset;
|
|
int indC = inds[i + 2] * floatStride + floatOffset;
|
|
|
|
a.X = verts[indA];
|
|
a.Y = verts[indA + 1];
|
|
a.Z = verts[indA + 2];
|
|
|
|
b.X = verts[indB];
|
|
b.Y = verts[indB + 1];
|
|
b.Z = verts[indB + 2];
|
|
|
|
c.X = verts[indC];
|
|
c.Y = verts[indC + 1];
|
|
c.Z = verts[indC + 2];
|
|
|
|
RasterizeTriangle(ref a, ref b, ref c, area);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">A collection of triangles.</param>
|
|
public void RasterizeTriangles(IEnumerable<Triangle3> tris)
|
|
{
|
|
RasterizeTriangles(tris, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">A collection of triangles.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(IEnumerable<Triangle3> tris, Area area)
|
|
{
|
|
foreach (var t in tris) {
|
|
Triangle3 tref = t;
|
|
RasterizeTriangle(ref tref, area);
|
|
}
|
|
/*
|
|
Parallel.ForEach(tris, t =>
|
|
{
|
|
RasterizeTriangle(ref t, area);
|
|
});
|
|
*/
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
public void RasterizeTriangles(Triangle3[] tris)
|
|
{
|
|
RasterizeTriangles(tris, 0, tris.Length, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(Triangle3[] tris, Area area)
|
|
{
|
|
RasterizeTriangles(tris, 0, tris.Length, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
/// <param name="triOffset">An offset into the array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
public void RasterizeTriangles(Triangle3[] tris, int triOffset, int triCount)
|
|
{
|
|
RasterizeTriangles(tris, triOffset, triCount, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="tris">An array of triangles.</param>
|
|
/// <param name="triOffset">An offset into the array.</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(Triangle3[] tris, int triOffset, int triCount, Area area)
|
|
{
|
|
int triEnd = triOffset + triCount;
|
|
|
|
if (tris == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (triOffset < 0)
|
|
throw new ArgumentOutOfRangeException("triOffset", "triOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (triEnd > tris.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset and count end outside the bounds of the provided array.");
|
|
|
|
int numBatches = 8;
|
|
int threads = (triCount / numBatches) + 1;
|
|
|
|
/*spanQueue = new ConcurrentQueue<Tuple<int, int, Span>>();
|
|
bool allProcessed;
|
|
|
|
var task = Task.Factory.StartNew(() =>
|
|
{
|
|
while (true)
|
|
{
|
|
if (spanQueue.IsEmpty)
|
|
Thread.Sleep(1);
|
|
|
|
Tuple<int, int, Span> spanEntry;
|
|
while (spanQueue.TryDequeue(out spanEntry))
|
|
cells[spanEntry.Item2 * width + spanEntry.Item1].AddSpan(spanEntry.Item3);
|
|
}
|
|
});*/
|
|
|
|
//Parallel.For(0, threads, i =>
|
|
for (int i = 0; i < threads; i++)
|
|
{
|
|
int start = triOffset + i * numBatches;
|
|
int end = triOffset + (i + 1) * numBatches;
|
|
if (end > triEnd)
|
|
end = triEnd;
|
|
|
|
for (int j = start; j < end; j++)
|
|
{
|
|
Triangle3 t = tris[j];
|
|
RasterizeTriangle(ref t.A, ref t.B, ref t.C, area);
|
|
}
|
|
}
|
|
//});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 3, the extra vertices at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
public void RasterizeTriangles(Vector3[] verts)
|
|
{
|
|
RasterizeTriangles(verts, 0, 1, verts.Length / 3, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 3, the extra vertices at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(Vector3[] verts, Area area)
|
|
{
|
|
RasterizeTriangles(verts, 0, 1, verts.Length / 3, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="vertOffset">An offset into the array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (1 Vector3 per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
public void RasterizeTriangles(Vector3[] verts, int vertOffset, int vertStride, int triCount)
|
|
{
|
|
RasterizeTriangles(verts, vertOffset, vertStride, triCount, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="vertOffset">An offset into the array.</param>
|
|
/// <param name="vertStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (1 Vector3 per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize, starting from the offset.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(Vector3[] verts, int vertOffset, int vertStride, int triCount, Area area)
|
|
{
|
|
int vertEnd = triCount * vertStride + vertOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (vertOffset < 0)
|
|
throw new ArgumentOutOfRangeException("vertOffset", "vertOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (vertStride < 0)
|
|
throw new ArgumentOutOfRangeException("vertStride", "vertStride must be greater than or equal to 0.");
|
|
else if (vertStride == 0)
|
|
vertStride = 1;
|
|
|
|
if (vertEnd > verts.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset, count, and stride end outside the bounds of the provided array.");
|
|
|
|
//Parallel.For(0, triCount, i => {
|
|
for (int i = 0; i < triCount; i++) {
|
|
i = vertOffset + (i * vertStride * 3);
|
|
RasterizeTriangle(ref verts[i], ref verts[i + vertStride], ref verts[i + vertStride * 2], area);
|
|
}
|
|
//});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 9, the extra floats at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
public void RasterizeTriangles(float[] verts)
|
|
{
|
|
RasterizeTriangles(verts, 0, 3, verts.Length / 9, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If the length of the array is not a multiple of 9, the extra floats at the end will be skipped.
|
|
/// </remarks>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(float[] verts, Area area)
|
|
{
|
|
RasterizeTriangles(verts, 0, 3, verts.Length / 9, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="floatOffset">An offset into the array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
public void RasterizeTriangles(float[] verts, int floatOffset, int floatStride, int triCount)
|
|
{
|
|
RasterizeTriangles(verts, floatOffset, floatStride, triCount, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes several triangles at once.
|
|
/// </summary>
|
|
/// <param name="verts">An array of vertices.</param>
|
|
/// <param name="floatOffset">An offset into the array.</param>
|
|
/// <param name="floatStride">The number of array elements that make up a vertex. A value of 0 is interpreted as tightly-packed data (3 floats per vertex).</param>
|
|
/// <param name="triCount">The number of triangles to rasterize.</param>
|
|
/// <param name="area">The area flags for all of the triangles.</param>
|
|
public void RasterizeTriangles(float[] verts, int floatOffset, int floatStride, int triCount, Area area)
|
|
{
|
|
int floatEnd = triCount * (floatStride * 3) + floatOffset;
|
|
|
|
if (verts == null)
|
|
throw new ArgumentNullException("verts");
|
|
|
|
if (floatOffset < 0)
|
|
throw new ArgumentOutOfRangeException("floatOffset", "floatOffset must be greater than or equal to 0.");
|
|
|
|
if (triCount < 0)
|
|
throw new ArgumentOutOfRangeException("triCount", "triCount must be greater than or equal to 0.");
|
|
|
|
if (floatStride < 0)
|
|
throw new ArgumentOutOfRangeException("floatStride", "floatStride must be a positive integer.");
|
|
else if (floatStride == 0)
|
|
floatStride = 3;
|
|
|
|
if (floatEnd > verts.Length)
|
|
throw new ArgumentOutOfRangeException("triCount", "The specified offset, count, and stride end outside the bounds of the provided array.");
|
|
|
|
Vector3 a, b, c;
|
|
|
|
//Parallel.For(0, triCount, i =>
|
|
for (int i = 0; i < triCount; i++)
|
|
{
|
|
i = floatOffset + (i * floatStride * 3);
|
|
int floatStride2 = floatStride * 2;
|
|
|
|
a.X = verts[i];
|
|
a.Y = verts[i + 1];
|
|
a.Z = verts[i + 2];
|
|
|
|
b.X = verts[i + floatStride];
|
|
b.Y = verts[i + floatStride + 1];
|
|
b.Z = verts[i + floatStride + 2];
|
|
|
|
c.X = verts[i + floatStride2];
|
|
c.Y = verts[i + floatStride2 + 1];
|
|
c.Z = verts[i + floatStride2 + 2];
|
|
|
|
RasterizeTriangle(ref a, ref b, ref c, area);
|
|
}
|
|
//});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="tri">The triangle as a <see cref="Triangle3"/> struct.</param>
|
|
public void RasterizeTriangle(ref Triangle3 tri)
|
|
{
|
|
RasterizeTriangle(ref tri.A, ref tri.B, ref tri.C, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="tri">The triangle as a <see cref="Triangle3"/> struct.</param>
|
|
/// <param name="area">The area flags for the triangle.</param>
|
|
public void RasterizeTriangle(ref Triangle3 tri, Area area)
|
|
{
|
|
RasterizeTriangle(ref tri.A, ref tri.B, ref tri.C, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="ax">The X component of the first vertex of the triangle.</param>
|
|
/// <param name="ay">The Y component of the first vertex of the triangle.</param>
|
|
/// <param name="az">The Z component of the first vertex of the triangle.</param>
|
|
/// <param name="bx">The X component of the second vertex of the triangle.</param>
|
|
/// <param name="by">The Y component of the second vertex of the triangle.</param>
|
|
/// <param name="bz">The Z component of the second vertex of the triangle.</param>
|
|
/// <param name="cx">The X component of the third vertex of the triangle.</param>
|
|
/// <param name="cy">The Y component of the third vertex of the triangle.</param>
|
|
/// <param name="cz">The Z component of the third vertex of the triangle.</param>
|
|
public void RasterizeTriangle(float ax, float ay, float az, float bx, float by, float bz, float cx, float cy, float cz)
|
|
{
|
|
RasterizeTriangle(ax, ay, az, bx, by, bz, cx, cy, cz, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="ax">The X component of the first vertex of the triangle.</param>
|
|
/// <param name="ay">The Y component of the first vertex of the triangle.</param>
|
|
/// <param name="az">The Z component of the first vertex of the triangle.</param>
|
|
/// <param name="bx">The X component of the second vertex of the triangle.</param>
|
|
/// <param name="by">The Y component of the second vertex of the triangle.</param>
|
|
/// <param name="bz">The Z component of the second vertex of the triangle.</param>
|
|
/// <param name="cx">The X component of the third vertex of the triangle.</param>
|
|
/// <param name="cy">The Y component of the third vertex of the triangle.</param>
|
|
/// <param name="cz">The Z component of the third vertex of the triangle.</param>
|
|
/// <param name="area">The area flags for the triangle.</param>
|
|
public void RasterizeTriangle(float ax, float ay, float az, float bx, float by, float bz, float cx, float cy, float cz, Area area)
|
|
{
|
|
Vector3 a, b, c;
|
|
|
|
a.X = ax;
|
|
a.Y = ay;
|
|
a.Z = az;
|
|
b.X = bx;
|
|
b.Y = by;
|
|
b.Z = bz;
|
|
c.X = cx;
|
|
c.Y = cy;
|
|
c.Z = cz;
|
|
|
|
RasterizeTriangle(ref a, ref b, ref c, area);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="a">The first vertex of the triangle.</param>
|
|
/// <param name="b">The second vertex of the triangle.</param>
|
|
/// <param name="c">The third vertex of the triangle.</param>
|
|
public void RasterizeTriangle(ref Vector3 a, ref Vector3 b, ref Vector3 c)
|
|
{
|
|
RasterizeTriangle(ref a, ref b, ref c, Area.Default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rasterizes a triangle using conservative voxelization.
|
|
/// </summary>
|
|
/// <param name="a">The first vertex of the triangle.</param>
|
|
/// <param name="b">The second vertex of the triangle.</param>
|
|
/// <param name="c">The third vertex of the triangle.</param>
|
|
/// <param name="area">The area flags for the triangle.</param>
|
|
public void RasterizeTriangle(ref Vector3 a, ref Vector3 b, ref Vector3 c, Area area)
|
|
{
|
|
//distances buffer for ClipPolygonToBounds
|
|
float[] distances = new float[12];
|
|
|
|
float invCellSize = 1f / cellSize;
|
|
float invCellHeight = 1f / cellHeight;
|
|
float boundHeight = bounds.Max.Y - bounds.Min.Y;
|
|
|
|
//calculate the triangle's bounding box
|
|
BBox3 bbox;
|
|
Triangle3.GetBoundingBox(ref a, ref b, ref c, out bbox);
|
|
|
|
//make sure that the triangle is at least in one cell.
|
|
if (!BBox3.Overlapping(ref bbox, ref bounds))
|
|
return;
|
|
|
|
//figure out which rows.
|
|
int z0 = (int)((bbox.Min.Z - bounds.Min.Z) * invCellSize);
|
|
int z1 = (int)((bbox.Max.Z - bounds.Min.Z) * invCellSize);
|
|
|
|
//clamp to the field boundaries.
|
|
MathHelper.Clamp(ref z0, 0, length - 1);
|
|
MathHelper.Clamp(ref z1, 0, length - 1);
|
|
|
|
Vector3[] inVerts = new Vector3[7], outVerts = new Vector3[7], inRowVerts = new Vector3[7];
|
|
|
|
for (int z = z0; z <= z1; z++)
|
|
{
|
|
//copy the original vertices to the array.
|
|
inVerts[0] = a;
|
|
inVerts[1] = b;
|
|
inVerts[2] = c;
|
|
|
|
//clip the triangle to the row
|
|
int nvrow = 3;
|
|
float cz = bounds.Min.Z + z * cellSize;
|
|
nvrow = MathHelper.ClipPolygonToPlane(inVerts, outVerts, distances, nvrow, 0, 1, -cz);
|
|
if (nvrow < 3)
|
|
continue;
|
|
nvrow = MathHelper.ClipPolygonToPlane(outVerts, inRowVerts, distances, nvrow, 0, -1, cz + cellSize);
|
|
if (nvrow < 3)
|
|
continue;
|
|
|
|
float minX = inRowVerts[0].X, maxX = minX;
|
|
for (int i = 1; i < nvrow; i++)
|
|
{
|
|
float vx = inRowVerts[i].X;
|
|
if (minX > vx)
|
|
minX = vx;
|
|
if (maxX < vx)
|
|
maxX = vx;
|
|
}
|
|
|
|
int x0 = (int)((minX - bounds.Min.X) * invCellSize);
|
|
int x1 = (int)((maxX - bounds.Min.X) * invCellSize);
|
|
|
|
MathHelper.Clamp(ref x0, 0, width - 1);
|
|
MathHelper.Clamp(ref x1, 0, width - 1);
|
|
|
|
for (int x = x0; x <= x1; x++)
|
|
{
|
|
//clip the triangle to the column
|
|
int nv = nvrow;
|
|
float cx = bounds.Min.X + x * cellSize;
|
|
nv = MathHelper.ClipPolygonToPlane(inRowVerts, outVerts, distances, nv, 1, 0, -cx);
|
|
if (nv < 3)
|
|
continue;
|
|
nv = MathHelper.ClipPolygonToPlane(outVerts, inVerts, distances, nv, -1, 0, cx + cellSize);
|
|
if (nv < 3)
|
|
continue;
|
|
|
|
//calculate the min/max of the polygon
|
|
float polyMin = inVerts[0].Y, polyMax = polyMin;
|
|
for (int i = 1; i < nv; i++)
|
|
{
|
|
float y = inVerts[i].Y;
|
|
polyMin = Math.Min(polyMin, y);
|
|
polyMax = Math.Max(polyMax, y);
|
|
}
|
|
|
|
//normalize span bounds to bottom of heightfield
|
|
float boundMinY = bounds.Min.Y;
|
|
polyMin -= boundMinY;
|
|
polyMax -= boundMinY;
|
|
|
|
//if the spans are outside the heightfield, skip.
|
|
if (polyMax < 0f || polyMin > boundHeight)
|
|
continue;
|
|
|
|
//clamp the span to the heightfield.
|
|
if (polyMin < 0)
|
|
polyMin = 0;
|
|
if (polyMax > boundHeight)
|
|
polyMax = boundHeight;
|
|
|
|
//snap to grid
|
|
int spanMin = (int)(polyMin * invCellHeight);
|
|
int spanMax = (int)Math.Ceiling(polyMax * invCellHeight);
|
|
|
|
//add the span
|
|
cells[z * width + x].AddSpan(new Span(spanMin, spanMax, area));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|