public unsafe void RenderRectWithAlpha (int rad, ISurface src, ISurface dst, Rectangle rect)
{
int width = src.Width;
int height = src.Height;
int* leadingEdgeX = stackalloc int[rad + 1];
int stride = src.Stride / sizeof (ColorBgra);
// approximately (rad + 0.5)^2
int cutoff = ((rad * 2 + 1) * (rad * 2 + 1) + 2) / 4;
for (int v = 0; v <= rad; ++v) {
for (int u = 0; u <= rad; ++u) {
if (u * u + v * v <= cutoff) {
leadingEdgeX[v] = u;
}
}
}
const int hLength = 256;
int* hb = stackalloc int[hLength];
int* hg = stackalloc int[hLength];
int* hr = stackalloc int[hLength];
uint hSize = (uint)(sizeof (int) * hLength);
for (int y = rect.Top; y <= rect.Bottom; y++) {
SetToZero (hb, hSize);
SetToZero (hg, hSize);
SetToZero (hr, hSize);
int area = 0;
int sum = 0;
ColorBgra* ps = src.GetPointAddress (rect.Left, y);
ColorBgra* pd = dst.GetPointAddress (rect.Left, y);
// assert: v + y >= 0
int top = -Math.Min (rad, y);
// assert: v + y <= height - 1
int bottom = Math.Min (rad, height - 1 - y);
// assert: u + x >= 0
int left = -Math.Min (rad, rect.Left);
// assert: u + x <= width - 1
int right = Math.Min (rad, width - 1 - rect.Left);
for (int v = top; v <= bottom; ++v) {
ColorBgra* psamp = src.GetPointAddress (rect.Left + left, y + v);
for (int u = left; u <= right; ++u) {
byte w = psamp->A;
if ((u * u + v * v) <= cutoff) {
++area;
sum += w;
hb[psamp->B] += w;
hg[psamp->G] += w;
hr[psamp->R] += w;
}
++psamp;
}
}
for (int x = rect.Left; x <= rect.Right; x++) {
*pd = ApplyWithAlpha (*ps, area, sum, hb, hg, hr);
// assert: u + x >= 0
left = -Math.Min (rad, x);
// assert: u + x <= width - 1
right = Math.Min (rad + 1, width - 1 - x);
// Subtract trailing edge top half
int v = -1;
while (v >= top) {
int u = leadingEdgeX[-v];
if (-u >= left) {
break;
}
--v;
}
while (v >= top) {
int u = leadingEdgeX[-v];
ColorBgra* p = unchecked (ps + (v * stride)) - u;
byte w = p->A;
hb[p->B] -= w;
hg[p->G] -= w;
hr[p->R] -= w;
sum -= w;
--area;
--v;
}
// add leading edge top half
v = -1;
while (v >= top) {
int u = leadingEdgeX[-v];
if (u + 1 <= right) {
break;
}
--v;
}
while (v >= top) {
int u = leadingEdgeX[-v];
ColorBgra* p = unchecked (ps + (v * stride)) + u + 1;
byte w = p->A;
hb[p->B] += w;
hg[p->G] += w;
hr[p->R] += w;
sum += w;
++area;
--v;
}
// Subtract trailing edge bottom half
v = 0;
while (v <= bottom) {
int u = leadingEdgeX[v];
if (-u >= left) {
break;
}
++v;
}
while (v <= bottom) {
int u = leadingEdgeX[v];
ColorBgra* p = ps + v * stride - u;
byte w = p->A;
hb[p->B] -= w;
hg[p->G] -= w;
hr[p->R] -= w;
sum -= w;
--area;
++v;
}
// add leading edge bottom half
v = 0;
while (v <= bottom) {
int u = leadingEdgeX[v];
if (u + 1 <= right) {
break;
}
++v;
}
while (v <= bottom) {
int u = leadingEdgeX[v];
ColorBgra* p = ps + v * stride + u + 1;
byte w = p->A;
hb[p->B] += w;
hg[p->G] += w;
hr[p->R] += w;
sum += w;
++area;
++v;
}
++ps;
++pd;
}
}
}
}