Files
CypherCore/Source/Framework/RecastDetour/Recast/RecastRasterization.cs
T
Fabian a3dc7b3f48 Ported .Net Core commits:
hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
2017-10-26 17:23:44 +02:00

430 lines
12 KiB
C#

using System;
using System.Diagnostics;
public static partial class Recast{
static bool overlapBounds(float[] amin, float[] amax, float[] bmin, float[] bmax)
{
bool overlap = true;
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
overlap = (amin[1] > bmax[1] || amax[1] < bmin[1]) ? false : overlap;
overlap = (amin[2] > bmax[2] || amax[2] < bmin[2]) ? false : overlap;
return overlap;
}
static bool overlapInterval(ushort amin, ushort amax,
ushort bmin, ushort bmax)
{
if (amax < bmin) return false;
if (amin > bmax) return false;
return true;
}
static rcSpan allocSpan(rcHeightfield hf)
{
// If running out of memory, allocate new page and update the freelist.
if (hf.freelist == null || hf.freelist.next == null)
{
// Create new page.
// Allocate memory for the new pool.
//rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM);
rcSpanPool pool = new rcSpanPool();
if (pool == null)
return null;
pool.next = null;
// Add the pool into the list of pools.
pool.next = hf.pools;
hf.pools = pool;
// Add new items to the free list.
rcSpan freelist = hf.freelist;
//rcSpan head = pool.items[0];
//rcSpan it = pool.items[RC_SPANS_PER_POOL];
int itIndex = RC_SPANS_PER_POOL;
do
{
--itIndex;
pool.items[itIndex].next = freelist;
freelist = pool.items[itIndex];
}
while (itIndex != 0);
hf.freelist = pool.items[itIndex];
}
// Pop item from in front of the free list.
rcSpan it = hf.freelist;
hf.freelist = hf.freelist.next;
return it;
}
static void freeSpan(rcHeightfield hf, rcSpan ptr)
{
if (ptr == null) {
return;
}
// Add the node in front of the free list.
ptr.next = hf.freelist;
hf.freelist = ptr;
}
static void addSpan(rcHeightfield hf, int x, int y,
ushort smin, ushort smax,
byte area, int flagMergeThr)
{
int idx = x + y*hf.width;
rcSpan s = allocSpan(hf);
s.smin = smin;
s.smax = smax;
s.area = area;
s.next = null;
// Empty cell, add the first span.
if (hf.spans[idx] == null)
{
hf.spans[idx] = s;
return;
}
rcSpan prev = null;
rcSpan cur = hf.spans[idx];
// Insert and merge spans.
while (cur != null)
{
if (cur.smin > s.smax)
{
// Current span is further than the new span, break.
break;
}
else if (cur.smax < s.smin)
{
// Current span is before the new span advance.
prev = cur;
cur = cur.next;
}
else
{
// Merge spans.
if (cur.smin < s.smin)
s.smin = cur.smin;
if (cur.smax > s.smax)
s.smax = cur.smax;
// Merge flags.
if (Math.Abs((int)s.smax - (int)cur.smax) <= flagMergeThr){
s.area = Math.Max(s.area, cur.area);
}
// Remove current span.
rcSpan next = cur.next;
freeSpan(hf, cur);
if (prev != null)
prev.next = next;
else
hf.spans[idx] = next;
cur = next;
}
}
// Insert new span.
if (prev != null)
{
s.next = prev.next;
prev.next = s;
}
else
{
s.next = hf.spans[idx];
hf.spans[idx] = s;
}
}
/// @par
///
/// The span addition can be set to favor flags. If the span is merged to
/// another span and the new @p smax is within @p flagMergeThr units
/// from the existing span, the span flags are merged.
///
/// @see rcHeightfield, rcSpan.
static void rcAddSpan(rcContext ctx, rcHeightfield hf, int x, int y,
ushort smin, ushort smax,
byte area, int flagMergeThr)
{
// Debug.Assert(ctx != null, "rcContext is null");
addSpan(hf, x,y, smin, smax, area, flagMergeThr);
}
// divides a convex polygons into two convex polygons on both sides of a line
static void dividePoly(float[] _in, int nin,
float[] out1, ref int nout1,
float[] out2, ref int nout2,
float x, int axis)
{
float[] d = new float[12];
for (int i = 0; i < nin; ++i){
d[i] = x - _in[i*3+axis];
}
int m = 0, n = 0;
for (int i = 0, j = nin-1; i < nin; j=i, ++i)
{
bool ina = d[j] >= 0;
bool inb = d[i] >= 0;
if (ina != inb)
{
float s = d[j] / (d[j] - d[i]);
out1[m*3+0] = _in[j*3+0] + (_in[i*3+0] - _in[j*3+0])*s;
out1[m*3+1] = _in[j*3+1] + (_in[i*3+1] - _in[j*3+1])*s;
out1[m*3+2] = _in[j*3+2] + (_in[i*3+2] - _in[j*3+2])*s;
rcVcopy(out2, n*3, out1, m*3);
m++;
n++;
// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
// since these were already added above
if (d[i] > 0)
{
rcVcopy(out1,m*3, _in, i*3);
m++;
}
else if (d[i] < 0)
{
rcVcopy(out2,n*3, _in, i*3);
n++;
}
}
else // same side
{
// add the i'th point to the right polygon. Addition is done even for points on the dividing line
if (d[i] >= 0)
{
rcVcopy(out1, m*3, _in, i*3);
m++;
if (d[i] != 0)
continue;
}
rcVcopy(out2, n*3, _in, i*3);
n++;
}
}
nout1 = m;
nout2 = n;
}
static void rasterizeTri(float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
byte area, rcHeightfield hf,
float[] bmin, float[] bmax,
float cs, float ics, float ich,
int flagMergeThr)
{
int w = hf.width;
int h = hf.height;
float[] tmin = new float[3];
float[] tmax = new float[3];
float by = bmax[1] - bmin[1];
// Calculate the bounding box of the triangle.
rcVcopy(tmin, 0, v0, v0Start);
rcVcopy(tmax, 0, v0, v0Start);
rcVmin(tmin, 0, v1, v1Start);
rcVmin(tmin, 0, v2, v2Start);
rcVmax(tmax, 0, v1, v1Start);
rcVmax(tmax, 0, v2, v2Start);
// If the triangle does not touch the bbox of the heightfield, skip the triagle.
if (!overlapBounds(bmin, bmax, tmin, tmax))
return;
// Calculate the footprint of the triangle on the grid's y-axis
int y0 = (int)((tmin[2] - bmin[2])*ics);
int y1 = (int)((tmax[2] - bmin[2])*ics);
y0 = rcClamp(y0, 0, h-1);
y1 = rcClamp(y1, 0, h-1);
// Clip the triangle into all grid cells it touches.
//float[] buf = new float[7*3*4];
float[] _in = new float[7*3];
float[] inrow = new float[7*3];
float[] p1 = new float[7*3];
float[] p2 = new float[7*3];
rcVcopy(_in,0 , v0, v0Start);
rcVcopy(_in,1*3, v1, v1Start);
rcVcopy(_in,2*3, v2, v2Start);
int nvrow = 0;
int nvIn = 3;
for (int y = y0; y <= y1; ++y)
{
// Clip polygon to row. Store the remaining polygon as well
float cz = bmin[2] + y*cs;
dividePoly(_in, nvIn, inrow, ref nvrow, p1, ref nvIn, cz+cs, 2);
//rcSwap(_in, p1);
float[] tmp = _in;
_in = p1;
p1 = tmp;
if (nvrow < 3)
continue;
// find the horizontal bounds in the row
float minX = inrow[0], maxX = inrow[0];
for (int i=1; i<nvrow; ++i)
{
if (minX > inrow[i*3]) minX = inrow[i*3];
if (maxX < inrow[i*3]) maxX = inrow[i*3];
}
int x0 = (int)((minX - bmin[0])*ics);
int x1 = (int)((maxX - bmin[0])*ics);
x0 = rcClamp(x0, 0, w-1);
x1 = rcClamp(x1, 0, w-1);
int nv = 0;
int nv2 = nvrow;
for (int x = x0; x <= x1; ++x)
{
// Clip polygon to column. store the remaining polygon as well
float cx = bmin[0] + x*cs;
dividePoly(inrow, nv2, p1, ref nv, p2, ref nv2, cx+cs, 0);
//rcSwap(inrow, p2);
tmp = inrow;
inrow = p2;
p2 = tmp;
if (nv < 3) {
continue;
}
// Calculate min and max of the span.
float smin = p1[1], smax = p1[1];
for (int i = 1; i < nv; ++i)
{
smin = Math.Min(smin, p1[i*3+1]);
smax = Math.Max(smax, p1[i*3+1]);
}
smin -= bmin[1];
smax -= bmin[1];
// Skip the span if it is outside the heightfield bbox
if (smax < 0.0f) continue;
if (smin > by) continue;
// Clamp the span to the heightfield bbox.
if (smin < 0.0f) smin = 0;
if (smax > by) smax = by;
// Snap the span to the heightfield height grid.
ushort ismin = (ushort)rcClamp((int)Math.Floor(smin * ich), 0, RC_SPAN_MAX_HEIGHT);
ushort ismax = (ushort)rcClamp((int)Math.Ceiling(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT);
addSpan(hf, x, y, ismin, ismax, area, flagMergeThr);
}
}
}
/// @par
///
/// No spans will be added if the triangle does not overlap the heightfield grid.
///
/// @see rcHeightfield
public static void rcRasterizeTriangle(rcContext ctx, float[] v0, int v0Start, float[] v1, int v1Start, float[] v2, int v2Start,
byte area, rcHeightfield solid,
int flagMergeThr)
{
Debug.Assert(ctx != null, "rcContext is null");
ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float ics = 1.0f/solid.cs;
float ich = 1.0f/solid.ch;
rasterizeTri(v0, v0Start, v1, v1Start, v2, v2Start, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
}
/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
public static void rcRasterizeTriangles(rcContext ctx, float[] verts, int nv,
int[] tris, byte[] areas, int nt,
rcHeightfield solid, int flagMergeThr)
{
Debug.Assert(ctx != null, "rcContext is null");
ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float ics = 1.0f/solid.cs;
float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
int v0Start = tris[i*3+0]*3;
int v1Start = tris[i*3+1]*3;
int v2Start = tris[i*3+2]*3;
// Rasterize.
rasterizeTri(verts, v0Start, verts, v1Start, verts, v2Start, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}
ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
}
/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
public static void rcRasterizeTriangles(rcContext ctx, float[] verts, int nv,
ushort[] tris, byte[] areas, int nt,
rcHeightfield solid, int flagMergeThr)
{
Debug.Assert(ctx != null, "rcContext is null");
ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float ics = 1.0f/solid.cs;
float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
int v0Start = tris[i*3+0]*3;
int v1Start = tris[i*3+1]*3;
int v2Start = tris[i*3+2]*3;
// Rasterize.
rasterizeTri(verts, v0Start, verts, v1Start, verts, v2Start, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}
ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
}
/// @par
///
/// Spans will only be added for triangles that overlap the heightfield grid.
///
/// @see rcHeightfield
public static void rcRasterizeTriangles(rcContext ctx, float[] verts, byte[] areas, int nt,
rcHeightfield solid, int flagMergeThr)
{
Debug.Assert(ctx != null, "rcContext is null");
ctx.startTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
float ics = 1.0f/solid.cs;
float ich = 1.0f/solid.ch;
// Rasterize triangles.
for (int i = 0; i < nt; ++i)
{
int v0Start = (i*3+0)*3;
int v1Start = (i*3+1)*3;
int v2Start = (i*3+2)*3;
// Rasterize.
rasterizeTri(verts, v0Start, verts, v1Start, verts, v2Start, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr);
}
ctx.stopTimer(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES);
}
}