private void SetPixel(float x, float z)
{
//Debug.Log("Pixel set at: x=" + x + " z=" + z);
bool Continue = true;
if (x > Width - 1) Continue = false;
if (x < 0) Continue = false;
if (z > Width - 1) Continue = false;
if (z < 0) Continue = false;
if (Continue) pixels[(int)x * Width + (int)z] = color; //!
}
private void SetPixelAA(float x, float z, double a)
{
//Debug.Log("PixelAA set at: x=" + x + " z=" + z);
bool Continue = true;
if (x > Width - 1) Continue = false;
if (x < 0) Continue = false;
if (z > Width - 1) Continue = false;
if (z < 0) Continue = false;
if (Continue && !double.IsNaN(a))
switch (colorID)
{
case 0: pixels[(int)x * Width + (int)z] = Color.yellow * (float)a; break; //yellow
case 1: pixels[(int)x * Width + (int)z] = Color.blue * (float)a; break; //blue
case 2: pixels[(int)x * Width + (int)z] = Color.red * (float)a; break; //red
}
}
private void plotQuadRationalBezierWidthSeg(Vector3 start, Vector3 offset, Vector3 end, float w, float th)
{
float x0 = (int)start.x;
float z0 = (int)start.z;
float x1 = (int)offset.x;
float z1 = (int)offset.z;
float x2 = (int)end.x;
float z2 = (int)end.z;
float sx = x2 - x1;
float sz = z2 - z1;
float dx = x0 - x2;
float dz = z0 - z2;
float xx = x0 - x1;
float zz = z0 - z1;
float xz = xx * sz + zz * sx;
float cur = xx * sz - zz * sx;
float err, e2, ed;
if (cur != 0f && w > 0f)
{
if (sx * sx + sz * sz > xx * xx + zz * zz)
{
x2 = x0; x0 -= dx; z2 = z0; z0 -= dz; cur = -cur;
}
xx = 2f * (4f * w * sx * xx + dx * dx);
zz = 2f * (4f * w * sz * zz + dz * dz);
sx = x0 < x2 ? 1 : -1;
sz = z0 < z2 ? 1 : -1;
xz = -2f * sx * sz * (2f * w * xz + dx * dz);
if (cur * sx * sz < 0)
{
xx = -xx; zz = -zz; cur = -cur; xz = -xz;
}
dx = 4f * w * (x1 - x0) * sz * cur + xx / 2f;
dz = 4f * w * (z0 - z1) * sx * cur + zz / 2f;
if (w < 0.5f && (dx + xx <= 0 || dz + zz >= 0))
{
cur = (w + 1f) / 2f; w = Mathf.Sqrt(w); xz = 1f / (w + 1f);
sx = Mathf.Floor((x0 + 2f * w * x1 + x2) * xz / 2f + 0.5f);
sz = Mathf.Floor((z0 + 2f * w * z1 + z2) * xz / 2f + 0.5f);
dx = Mathf.Floor((w * x1 + x0) * xz + 0.5f);
dz = Mathf.Floor((z1 * w + z0) * xz + 0.5f);
plotQuadRationalBezierWidthSeg(new Vector3(x0, 0, z0), new Vector3(dx, 0, dz), new Vector3(sx, 0, sz), cur, th);
dx = Mathf.Floor((w * x1 + x2) * xz + 0.5f);
dz = Mathf.Floor((z1 * w + z2) * xz + 0.5f);
plotQuadRationalBezierWidthSeg(new Vector3(sx, 0, sz),new Vector3(dx, 0, dz), new Vector3(x2, 0, z2), cur, th);
}
fail:
for (err = 0; dz + 2 * zz < 0 && dx + 2 * xx > 0;)
if (dx + dz + xz < 0)
{
do
{
ed = -dz - 2 * dz * dx * dx / (4f * dz * dz + dx * dx);
w = (th - 1) * ed;
x1 = Mathf.Floor((err - ed - w / 2) / dz);
e2 = err - x1 * dz - w / 2;
x1 = x0 - x1 * sx;
SetPixelAA(x1, z0, e2 / ed);
for (e2 = -w - dz - e2; e2 - dz < ed; e2 -= dz)
SetPixel(x1 += sx, z0);
SetPixelAA(x1 + sx, z0, e2 / ed);
if (z0 == z2) return;
z0 += sz; dz += xz; err += dx; dx += xx;
if (2 * err + dz > 0)
{
x0 += sx; dx += xz; err += dz; dz += zz;
}
if (x0 != x2 && (dx + 2 * xx <= 0 || dz + 2 * zz >= 0))
if (Mathf.Abs(z2 - z0) > Mathf.Abs(x2 - x0)) goto fail;
else break;
} while (dx + dz + xz < 0);
for (cur = err - dz - w / 2, z1 = z0; cur < ed; z1 += sz, cur += dx)
{
for (e2 = cur, x1 = x0; e2 - dz < ed; e2 -= dz)
SetPixel(x1 -= sx, z1);
SetPixelAA(x1 - sx, z1, e2 / ed);
}
}
else
{
do
{
ed = dx + 2 * dx * dz * dz / (4f * dx * dx + dz * dz);
w = (th - 1) * ed;
z1 = Mathf.Floor((err + ed + w / 2) / dx);
e2 = z1 * dx - w / 2 - err;
z1 = z0 - z1 * sz;
SetPixelAA(x0, z1, e2 / ed);
for (e2 = dx - e2 - w; e2 + dx < ed; e2 += dx)
SetPixel(x0, z1 += sz);
SetPixelAA(x0, z1 + sz, e2 / ed);
if (x0 == x2) return;
x0 += sx; dx += xz; err += dz; dz += zz;
if (2 * err + dx < 0)
{
z0 += sz; dz += xz; err += dx; dx += xx;
}
if (z0 != z2 && (dx + 2 * xx <= 0 || dz + 2 * zz >= 0))
if (Mathf.Abs(z2 - z0) <= Mathf.Abs(x2 - x0)) goto fail;
else break;
} while (dx + dz + xz >= 0);
for (cur = -err + dx - w / 2, x1 = x0; cur < ed; x1 += sx, cur -= dz)
{
for (e2 = cur, z1 = z0; e2 + dx < ed; e2 += dx)
SetPixel(x1, z1 -= sz);
SetPixelAA(x1, z1 - sz, e2 / ed);
}
}
}
plotLineWidth(new Vector3(x0, 0, z0), new Vector3(x2, 0, z2), th);
}
private void plotQuadRationalBezierWidth(Vector3 start, Vector3 offset, Vector3 end, float w, float th)
{
float x0 = (int)start.x;
float z0 = (int)start.z;
float x1 = (int)offset.x;
float z1 = (int)offset.z;
float x2 = (int)end.x;
float z2 = (int)end.z;
float x = x0 - 2 * x1 + x2;
float z = z0 - 2 * z1 + z2;
float xx = x0 - x1;
float zz = z0 - z1;
float ww, t, q;
if (xx * (x2 - x1) > 0)
{
if (zz * (z2 - z1) > 0)
if (Mathf.Abs(xx * z) > Mathf.Abs(zz * x))
{
x0 = x2; x2 = xx + x1; z0 = z2; z2 = zz + z1;
}
if (x0 == x2 || w == 1f) t = (x0 - x1) / x;
else
{
q = Mathf.Sqrt(4f * w * w * (x0 - x1) * (x2 - x1) + (x2 - x0) * (x2 - x0));
if (x1 < x0) q = -q;
t = (2f * w * (x0 - x1) - x0 + x2 + q) / (2f * (1f - w) * (x2 - x0));
}
q = 1f / (2f * t * (1f - t) * (w - 1f) + 1f);
xx = (t * t * (x0 - 2f * w * x1 + x2) + 2f * t * (w * x1 - x0) + x0) * q;
zz = (t * t * (z0 - 2f * w * z1 + z2) + 2f * t * (w * z1 - z0) + z0) * q;
ww = t * (w - 1f) + 1f; ww *= ww * q;
w = ((1f - t) * (w - 1f) + 1f) * Mathf.Sqrt(q);
x = Mathf.Floor(xx + 0.5f); z = Mathf.Floor(zz + 0.5f);
zz = (xx - x0) * (z1 - z0) / (x1 - x0) + z0;
plotQuadRationalBezierWidthSeg(new Vector3(x0, 0, z0),new Vector3(x, 0, Mathf.Floor(zz + 0.5f)), new Vector3(x, 0, z), ww, th);
zz = (xx - x2) * (z1 - z2) / (x1 - x2) + z2;
z1 = Mathf.Floor(zz + 0.5f); x0 = x1 = x; z0 = z;
}
if ((z0 - z1) * (z2 - z1) > 0)
{
if (z0 == z2 || w == 1f) t = (z0 - z1) / (z0 - 2f * z1 + z2);
else
{
q = Mathf.Sqrt(4f * w * w * (z0 - z1) * (z2 - z1) + (z2 - z0) * (z2 - z0));
if (z1 < z0) q = -q;
t = (2f * w * (z0 - z1) - z0 + z2 + q) / (2f * (1f - w) * (z2 - z0));
}
q = 1f / (2f * t * (1f - t) * (w - 1f) + 1f);
xx = (t * t * (x0 - 2f * w * x1 + x2) + 2f * t * (w * x1 - x0) + x0) * q;
zz = (t * t * (z0 - 2f * w * z1 + z2) + 2f * t * (w * z1 - z0) + z0) * q;
ww = t * (w - 1f) + 1f; ww *= ww * q;
w = ((1f - t) * (w - 1f) + 1f) * Mathf.Sqrt(q);
x = Mathf.Floor(xx + 0.5f); z = Mathf.Floor(zz + 0.5f);
xx = (x1 - x0) * (zz - z0) / (z1 - z0) + x0;
plotQuadRationalBezierWidthSeg(new Vector3(x0, 0, z0), new Vector3(Mathf.Floor(xx + 0.5f), 0, z), new Vector3(x, 0, z), ww, th);
xx = (x1 - x2) * (zz - z2) / (z1 - z2) + x2;
x1 = Mathf.Floor(xx + 0.5f); x0 = x; z0 = z1 = z;
}
plotQuadRationalBezierWidthSeg(new Vector3(x0, 0, z0), new Vector3(x1, 0, z1), new Vector3(x2, 0, z2), w * w, th);
}
private void plotLineWidth(Vector3 start, Vector3 end, float th)
{
float x0 = (int)start.x;
float z0 = (int)start.z;
float x1 = (int)end.x;
float z1 = (int)end.z;
float dx = Mathf.Abs(x1 - x0);
float sx = x0 < x1 ? 1 : -1;
float dz = Mathf.Abs(z1 - z0);
float sz = z0 < z1 ? 1 : -1;
float err, e2 = Mathf.Sqrt(dx * dx + dz * dz);
dx *= 255 / e2; dz *= 255 / e2; th = 255 * (th - 1);
if (dx < dz)
{
x1 = Mathf.Round((e2 + th / 2) / dz);
err = x1 * dz - th / 2;
for (x0 -= x1 * sx; ; z0 += sz)
{
SetPixelAA(x1 = x0, z0, err);
for (e2 = dz - err - th; e2 + dz < 255; e2 += dz)
SetPixel(x1 += sx, z0);
SetPixelAA(x1 + sx, z0, e2);
if (z0 == z1) break;
err += dx;
if (err > 255) { err -= dz; x0 += sx; }
}
}
else
{
z1 = Mathf.Round((e2 + th / 2) / dx);
err = z1 * dx - th / 2;
for (z0 -= z1 * sz; ; x0 += sx)
{
SetPixelAA(x0, z1 = z0, err / 255);
for (e2 = dx - err - th; e2 + dx < 255; e2 += dx)
SetPixel(x0, z1 += sz);
SetPixelAA(x0, z1 + sz, e2 / 255);
if (x0 == x1) break;
err += dz;
if (err > 255) { err -= dx; z0 += sz; }
}
}
}
private void plotLineAA(Vector3 start, Vector3 end)
{
float x0 = (int)start.x;
float y0 = (int)start.z;
float x1 = (int)end.x;
float y1 = (int)end.z;
float dx = Mathf.Abs(x1 - x0);
float sx = x0 < x1 ? 1 : -1;
float dy = Mathf.Abs(y1 - y0);
float sy = y0 < y1 ? 1 : -1;
float err = dx - dy, e2, x2;
float ed = dx + dy == 0 ? 1 : Mathf.Sqrt(dx * dx + dy * dy);
for (; ; )
{
SetPixelAA(x0, y0, Mathf.Abs(err - dx + dy) / ed);
e2 = err; x2 = x0;
if (2 * e2 >= -dx)
{
if (x0 == x1) break;
if (e2 + dy < ed) SetPixelAA(x0, y0 + sy, (e2 + dy) / ed);
err -= dy; x0 += sx;
}
if (2 * e2 <= dy)
{
if (y0 == y1) break;
if (dx - e2 < ed) SetPixelAA(x2 + sx, y0, (dx - e2) / ed);
err += dx; y0 += sy;
}
}
}
private void plotQuadRationalBezierSeg(Vector3 start, Vector3 offset, Vector3 end, float w)
{
float x0 = (int)start.x;
float y0 = (int)start.z;
float x1 = (int)offset.x;
float y1 = (int)offset.z;
float x2 = (int)end.x;
float y2 = (int)end.z;
float sx = x2 - x1;
float sy = y2 - y1;
float dx = x0 - x2;
float dy = y0 - y2;
float xx = x0 - x1;
float yy = y0 - y1;
float xy = xx * sy + yy * sx;
float cur = xx * sy - yy * sx;
float err;
//assert(xx * sx <= 0f && yy * sy <= 0f); /* sign of gradient must not change */
if (cur != 0f && w > 0f)
{ /* no straight line */
if (sx * sx + sy * sy > xx * xx + yy * yy)
{ /* begin with shorter part */
x2 = x0; x0 -= dx; y2 = y0; y0 -= dy; cur = -cur; /* swap P0 P2 */
}
xx = 2f * (4f * w * sx * xx + dx * dx); /* differences 2nd degree */
yy = 2f * (4f * w * sy * yy + dy * dy);
sx = x0 < x2 ? 1 : -1; /* x step direction */
sy = y0 < y2 ? 1 : -1; /* y step direction */
xy = -2f * sx * sy * (2f * w * xy + dx * dy);
if (cur * sx * sy < 0f)
{ /* negated curvature? */
xx = -xx; yy = -yy; xy = -xy; cur = -cur;
}
dx = 4f * w * (x1 - x0) * sy * cur + xx / 2f + xy; /* differences 1st degree */
dy = 4f * w * (y0 - y1) * sx * cur + yy / 2f + xy;
if (w < 0.5f && (dy > xy || dx < xy))
{ /* flat ellipse, algorithm fails */
cur = (w + 1f) / 2f; w = Mathf.Sqrt(w); xy = 1f / (w + 1f);
sx = Mathf.Floor((x0 + 2f * w * x1 + x2) * xy / 2f + 0.5f);/*subdivide curve in half */
sy = Mathf.Floor((y0 + 2f * w * y1 + y2) * xy / 2f + 0.5f);
dx = Mathf.Floor((w * x1 + x0) * xy + 0.5f);
dy = Mathf.Floor((y1 * w + y0) * xy + 0.5f);
plotQuadRationalBezierSeg(new Vector3(x0, 0, y0), new Vector3(dx, 0, dy), new Vector3(sx, 0, sy), cur);
dx = Mathf.Floor((w * x1 + x2) * xy + 0.5f);
dy = Mathf.Floor((y1 * w + y2) * xy + 0.5f);
plotQuadRationalBezierSeg(new Vector3(sx, 0, sy), new Vector3(dx, 0, dy), new Vector3(x2, 0, y2), cur);
return;
}
err = dx + dy - xy; /* error 1.step */
do
{
SetPixel(x0, y0); /* plot curve */
if (x0 == x2 && y0 == y2) return; /* last pixel -> curve finished */
bool x1b = 2 * err > dy;
bool y1b = 2 * (err + yy) < -dy;/* save value for test of x step */
if (2 * err < dx || y1b) { y0 += sy; dy += xy; err += dx += xx; }/* y step */
if (2 * err > dx || x1b) { x0 += sx; dx += xy; err += dy += yy; }/* x step */
} while (dy <= xy && dx >= xy); /* gradient negates -> algorithm fails */
}
plotLine(new Vector3(x0, 0, y0), new Vector3(x2, 0, y2));
}
private void plotQuadRationalBezier(Vector3 start, Vector3 offset, Vector3 end, float w)
{ /* plot any quadratic rational Bezier curve */
float x0 = (int)start.x;
float y0 = (int)start.z;
float x1 = (int)offset.x;
float y1 = (int)offset.z;
float x2 = (int)end.x;
float y2 = (int)end.z;
float x = x0 - 2 * x1 + x2;
float y = y0 - 2 * y1 + y2;
float xx = x0 - x1;
float yy = y0 - y1;
float ww, t, q;
//assert(w >= 0f);
if (xx * (x2 - x1) > 0)
{ /* horizontal cut at P4? */
if (yy * (y2 - y1) > 0) /* vertical cut at P6 too? */
if (Mathf.Abs(xx * y) > Mathf.Abs(yy * x))
{ /* which first? */
x0 = x2; x2 = xx + x1; y0 = y2; y2 = yy + y1; /* swap points */
} /* now horizontal cut at P4 comes first */
if (x0 == x2 || w == 1f) t = (x0 - x1) / x;
else
{ /* non-rational or rational case */
q = Mathf.Sqrt(4f * w * w * (x0 - x1) * (x2 - x1) + (x2 - x0) * (x2 - x0));
if (x1 < x0) q = -q;
t = (2f * w * (x0 - x1) - x0 + x2 + q) / (2f * (1f - w) * (x2 - x0)); /* t at P4 */
}
q = 1f / (2f * t * (1f - t) * (w - 1f) + 1f);
xx = (t * t * (x0 - 2f * w * x1 + x2) + 2f * t * (w * x1 - x0) + x0) * q; /* = P4 */
yy = (t * t * (y0 - 2f * w * y1 + y2) + 2f * t * (w * y1 - y0) + y0) * q;
ww = t * (w - 1f) + 1f; ww *= ww * q; /* squared weight P3 */
w = ((1f - t) * (w - 1f) + 1f) * Mathf.Sqrt(q); /* weight P8 */
x = Mathf.Floor(xx + 0.5f);
y = Mathf.Floor(yy + 0.5f);
yy = (xx - x0) * (y1 - y0) / (x1 - x0) + y0; /* intersect P3 | P0 P1 */
plotQuadRationalBezierSeg(new Vector3(x0, 0, y0), new Vector3(x, 0, Mathf.Floor(yy + 0.5f)), new Vector3(x, 0, y), ww);
yy = (xx - x2) * (y1 - y2) / (x1 - x2) + y2; /* intersect P4 | P1 P2 */
y1 = Mathf.Floor(yy + 0.5f); x0 = x1 = x; y0 = y; /* P0 = P4, P1 = P8 */
}
if ((y0 - y1) * (y2 - y1) > 0)
{ /* vertical cut at P6? */
if (y0 == y2 || w == 1.0) t = (y0 - y1) / (y0 - 2f * y1 + y2);
else
{ /* non-rational or rational case */
q = Mathf.Sqrt(4f * w * w * (y0 - y1) * (y2 - y1) + (y2 - y0) * (y2 - y0));
if (y1 < y0) q = -q;
t = (2f * w * (y0 - y1) - y0 + y2 + q) / (2f * (1f - w) * (y2 - y0)); /* t at P6 */
}
q = 1f / (2f * t * (1f - t) * (w - 1f) + 1f); /* sub-divide at t */
xx = (t * t * (x0 - 2f * w * x1 + x2) + 2f * t * (w * x1 - x0) + x0) * q; /* = P6 */
yy = (t * t * (y0 - 2f * w * y1 + y2) + 2f * t * (w * y1 - y0) + y0) * q;
ww = t * (w - 1f) + 1f; ww *= ww * q; /* squared weight P5 */
w = ((1f - t) * (w - 1f) + 1f) * Mathf.Sqrt(q); /* weight P7 */
x = Mathf.Floor(xx + 0.5f);
y = Mathf.Floor(yy + 0.5f); /* P6 */
xx = (x1 - x0) * (yy - y0) / (y1 - y0) + x0; /* intersect P6 | P0 P1 */
plotQuadRationalBezierSeg(new Vector3(x0, 0, y0), new Vector3(Mathf.Floor(xx + 0.5f), 0, y), new Vector3(x, 0, y), ww);
xx = (x1 - x2) * (yy - y2) / (y1 - y2) + x2; /* intersect P7 | P1 P2 */
x1 = Mathf.Floor(xx + 0.5f); x0 = x; y0 = y1 = y; /* P0 = P6, P1 = P7 */
}
plotQuadRationalBezierSeg(new Vector3(x0, 0, y0), new Vector3(x1, 0, y1), new Vector3(x2, 0, y2), w * w);
}
private void plotLine(Vector3 start, Vector3 end)
{
float x0 = (int)start.x;
float y0 = (int)start.z;
float x1 = (int)end.x;
float y1 = (int)end.z;
float dx = Mathf.Abs(x1 - x0);
float sx = x0 < x1 ? 1 : -1;
float dy = -Mathf.Abs(y1 - y0);
float sy = y0 < y1 ? 1 : -1;
float err = dx + dy, e2; /* error value e_xy */
for (; ; )
{ /* loop */
SetPixel(x0, y0);
if (x0 == x1 && y0 == y1) break;
e2 = 2 * err;
if (e2 >= dy) { err += dy; x0 += sx; } /* x step */
if (e2 <= dx) { err += dx; y0 += sy; } /* y step */
}
}