using System.Numerics; using ILGPU; using ILGPU.Runtime; namespace SDFMapCreator; public partial class SdfKernels { private const float LUMA_THRESHOLD = 0.0f; static void SelfMaskKernel(Index2D index, ArrayView2D input, ArrayView2D mask) { var x = index.X; var y = index.Y; var value = input[x, y]; var lumaA = value.X; var r = lumaA > LUMA_THRESHOLD ? 1f : 0f; mask[x, y] = new(r, 0f, 0f); } static void ABMaskKernel(Index2D index, ArrayView2D A, ArrayView2D B, ArrayView2D mask ) { var x = index.X; var y = index.Y; var valueA = A[x, y]; var valueB = B[x, y]; var lumaA = valueA.X; var lumaB = valueB.X; var r = lumaA > LUMA_THRESHOLD || lumaB > LUMA_THRESHOLD ? 1f : 0f; mask[x, y] = new(r, 0f, 0f); } static void EdgeKernel(Index2D index, ArrayView2D mask, uint width, uint height ) { // early exit if not on mask if (mask[index].X == 0f) return; var x = index.X; var y = index.Y; //if we are on the edge of the image, return false if (x == 0 || y == 0 || x == width - 1 || y == height - 1) return; //check the 3x3 kernel for (var xi = x - 1; xi <= x + 1; xi++) { for (var yi = y - 1; yi <= y + 1; yi++) { if (xi < 0 || xi >= width || yi < 0 || yi >= height) continue; //skip out of bounds pixels if (mask[xi, yi].X == 0f) mask[index].Y = 1f; //if we find a black pixel, return true } } } static void SdfKernel(Index2D index, ArrayView2D sdf, ArrayView1D edges, int width, int height ) { Vector2 pos = new((float)index.X / width, (float)index.Y / height); var minDist = 2f; var count = edges.IntExtent.Size; for (var i = 0; i < count; i++) { Vector2 edgeNrm = new(edges[i].X / width, edges[i].Y / height); var dist = Vector2.Distance(pos, edgeNrm); if (dist < minDist) minDist = dist; } if (minDist > 1f) minDist = 1f; sdf[index] = new(minDist); } static void GradientKernel(Index2D index, ArrayView2D mask, ArrayView2D sdfa, ArrayView2D sdfb, ArrayView2D gradient ) { //early exit if not on mask if (mask[index].X == 0f || mask[index].Y > 0f) return; var a = sdfa[index].X; var b = sdfb[index].X; gradient[index] = new(a / (a + b)); } static void DirectionalBlurKernel(Index2D index, ArrayView2D image, ArrayView2D mask, ArrayView2D output, float radius, float step, float sigma, int width, int height ) { var x = index.X; var y = index.Y; var value = image[x, y]; var maskValue = mask[x, y]; if (maskValue.X == 0f) { output[x, y] = value; return; } var gradient = Vector2.Zero; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if (x + dx < 0 || x + dx >= width || y + dy < 0 || y + dy >= height) continue; gradient += new Vector2(dx, dy) * image[x + dx, y + dy].X; } } if (gradient == Vector2.Zero) { output[x, y] = value; return; } gradient = Vector2.Normalize(gradient); float sum = 0; // now we follow the direction line and sample the image for length; for (var l = -radius; l <= radius; l += step) { var xOffset = (int)(gradient.X * l); var yOffset = (int)(gradient.Y * l); var xSample = x + xOffset; var ySample = y + yOffset; if (xSample < 0 || xSample >= width || ySample < 0 || ySample >= height) continue; var sampleValue = image[xSample, ySample]; var weight = MathF.Exp(-l * l / (2f * sigma * sigma)); output[x, y] += sampleValue * weight; sum += weight; } output[x, y] /= sum; } }