public static void GenerateMSDF(Bitmap <Color4b> output, Shape shape, Rectangle region, double range, Vector2 scale, Vector2 translate, double edgeThreshold) { int contourCount = shape.Contours.Count; int[] windings = new int[contourCount]; for (int i = 0; i < shape.Contours.Count; i++) { windings[i] = shape.Contours[i].Winding; } int xStart = Math.Min(Math.Max(0, (int)region.Left), output.Width); int yStart = Math.Min(Math.Max(0, (int)region.Top), output.Height); int xEnd = Math.Min(Math.Max(0, (int)region.Right), output.Width); int yEnd = Math.Min(Math.Max(0, (int)region.Bottom), output.Height); MultiDistance[] contourSD = new MultiDistance[contourCount]; for (int y = yStart; y < yEnd; y++) { int row = shape.InverseYAxis ? yEnd - (y - yStart) - 1 : y; for (int x = xStart; x < xEnd; x++) { Vector2 p = (new Vector2(x, y) - region.Position - translate) / scale; output[x, row] = new Color4b(EvaluateMSDF(shape, windings, contourSD, p, range), 255); } } }
static Color3 EvaluateMSDF(Shape shape, int[] windings, MultiDistance[] contourSD, Vector2 p, double range) { int contourCount = contourSD.Length; p += new Vector2(0.5f, 0.5f); EdgePoint sr = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; EdgePoint sg = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; EdgePoint sb = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; double d = Math.Abs(SignedDistance.Infinite.distance); double negDist = -SignedDistance.Infinite.distance; double posDist = SignedDistance.Infinite.distance; int winding = 0; for (int i = 0; i < contourCount; i++) { Contour contour = shape.Contours[i]; EdgePoint r = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; EdgePoint g = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; EdgePoint b = new EdgePoint { minDistance = new SignedDistance(-1e240, 1) }; for (int j = 0; j < contour.Edges.Count; j++) { EdgeSegment edge = contour.Edges[j]; double param; SignedDistance distance = edge.GetSignedDistance(p, out param); if ((edge.Color & EdgeColor.Red) == EdgeColor.Red && distance < r.minDistance) { r.minDistance = distance; r.nearEdge = edge; r.nearParam = param; } if ((edge.Color & EdgeColor.Green) == EdgeColor.Green && distance < g.minDistance) { g.minDistance = distance; g.nearEdge = edge; g.nearParam = param; } if ((edge.Color & EdgeColor.Blue) == EdgeColor.Blue && distance < b.minDistance) { b.minDistance = distance; b.nearEdge = edge; b.nearParam = param; } } if (r.minDistance < sr.minDistance) { sr = r; } if (g.minDistance < sg.minDistance) { sg = g; } if (b.minDistance < sb.minDistance) { sb = b; } double medMinDistance = Math.Abs(Median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance)); if (medMinDistance < d) { d = medMinDistance; winding = -windings[i]; } if (r.nearEdge != null) { r.nearEdge.DistanceToPseudoDistance(ref r.minDistance, p, r.nearParam); } if (g.nearEdge != null) { g.nearEdge.DistanceToPseudoDistance(ref g.minDistance, p, g.nearParam); } if (b.nearEdge != null) { b.nearEdge.DistanceToPseudoDistance(ref b.minDistance, p, b.nearParam); } medMinDistance = Median(r.minDistance.distance, g.minDistance.distance, b.minDistance.distance); contourSD[i].r = r.minDistance.distance; contourSD[i].g = g.minDistance.distance; contourSD[i].b = b.minDistance.distance; contourSD[i].med = medMinDistance; if (windings[i] > 0 && medMinDistance >= 0 && Math.Abs(medMinDistance) < Math.Abs(posDist)) { posDist = medMinDistance; } if (windings[i] < 0 && medMinDistance <= 0 && Math.Abs(medMinDistance) < Math.Abs(negDist)) { negDist = medMinDistance; } } if (sr.nearEdge != null) { sr.nearEdge.DistanceToPseudoDistance(ref sr.minDistance, p, sr.nearParam); } if (sg.nearEdge != null) { sg.nearEdge.DistanceToPseudoDistance(ref sg.minDistance, p, sg.nearParam); } if (sb.nearEdge != null) { sb.nearEdge.DistanceToPseudoDistance(ref sb.minDistance, p, sb.nearParam); } MultiDistance msd = new MultiDistance { r = SignedDistance.Infinite.distance, g = SignedDistance.Infinite.distance, b = SignedDistance.Infinite.distance, med = SignedDistance.Infinite.distance, }; if (posDist >= 0 && Math.Abs(posDist) <= Math.Abs(negDist)) { msd.med = SignedDistance.Infinite.distance; winding = 1; for (int i = 0; i < contourCount; i++) { if (windings[i] > 0 && contourSD[i].med > msd.med && Math.Abs(contourSD[i].med) < Math.Abs(negDist)) { msd = contourSD[i]; } } } else if (negDist <= 0 && Math.Abs(negDist) <= Math.Abs(posDist)) { msd.med = -SignedDistance.Infinite.distance; winding = -1; for (int i = 0; i < contourCount; i++) { if (windings[i] < 0 && contourSD[i].med < msd.med && Math.Abs(contourSD[i].med) < Math.Abs(posDist)) { msd = contourSD[i]; } } } for (int i = 0; i < contourCount; i++) { if (windings[i] != winding && Math.Abs(contourSD[i].med) < Math.Abs(msd.med)) { msd = contourSD[i]; } } if (Median(sr.minDistance.distance, sg.minDistance.distance, sb.minDistance.distance) == msd.med) { msd.r = sr.minDistance.distance; msd.g = sg.minDistance.distance; msd.b = sb.minDistance.distance; } return(new Color3((float)(msd.r / range) + 0.5f, (float)(msd.g / range) + 0.5f, (float)(msd.b / range) + 0.5f)); }