public void SuperSampleRangeList_Single() { var ssRanges = new SuperSampleRangeList(); ssRanges.Populate(new[] { new EdgeIntersectionRange { FromX = 6, Width = 0 } }); Assert.AreEqual(1, ssRanges.Count); Assert.AreEqual(6, ssRanges[0].FromX); Assert.AreEqual(0, ssRanges[0].Width); }
public void SuperSampleRangeList_Adjacent_NoDistance() { var ssRanges = new SuperSampleRangeList(); ssRanges.Populate(new[] { new EdgeIntersectionRange { FromX = 5, Width = 10 }, new EdgeIntersectionRange { FromX = 14, Width = 10 } }); Assert.AreEqual(1, ssRanges.Count); Assert.AreEqual(5, ssRanges[0].FromX); Assert.AreEqual(19, ssRanges[0].Width); }
public void SuperSampleRangeList_Containing() { var ssRanges = new SuperSampleRangeList(); ssRanges.Populate(new[] { new EdgeIntersectionRange { FromX = 10, Width = 20 }, new EdgeIntersectionRange { FromX = 15, Width = 5 } }); Assert.AreEqual(1, ssRanges.Count); Assert.AreEqual(10, ssRanges[0].FromX); Assert.AreEqual(20, ssRanges[0].Width); }
public void SuperSampleRangeList_Overlapping() { var ssRanges = new SuperSampleRangeList(); ssRanges.Populate(new[] { new EdgeIntersectionRange { FromX = 5, Width = 10 }, new EdgeIntersectionRange { FromX = 10, Width = 10 } }); Assert.AreEqual(1, ssRanges.Count); Assert.AreEqual(5, ssRanges[0].FromX); Assert.AreEqual(15, ssRanges[0].Width); }
private ColorRange[] Render() { this.edges.Sort(); var writer = new BitmapWriter(BackgroundColor, width, height); var superSampleBuffer = new SuperSampleBuffer(width); var layers = new LayerManager[SuperSampling.SamplesPerPixelY]; var superSampleRanges = new SuperSampleRangeList(); // Keeps track of how many of the subpixellayers that are used for // the currently rendered scanline. Until a range requiring supersampling // is encountered only a single layer is needed. var usedLayers = 0; var color = default(Color); var intersections = new IntersectionList(); // Create a layer manager for every subpixel scanline for (var i = 0; i < layers.Length; i++) { layers[i] = new LayerManager(); } for (var ey = 0; ey < height; ey++) { var ranges = this.edges[ey]; if (ranges.Count == 0) { writer.Skip(width); continue; } for (var i = 0; i < usedLayers; i++) { layers[i].Clear(); } usedLayers = 1; superSampleRanges.Populate(ranges); writer.Skip(superSampleRanges[0].FromX); for (var rangeIndex = 0; rangeIndex < superSampleRanges.Count; rangeIndex++) { ref var superSampleRange = ref superSampleRanges[rangeIndex]; // If there is exactly one edge in the supersample range, and it is crossing // the entire scanline, we can perform the antialiasing by integrating the // edge function. if (superSampleRange.Count == 1 && ( superSampleRange[0].From.Y <= ey && superSampleRange[0].To.Y >= ey + 1 || superSampleRange[0].From.Y >= ey + 1 && superSampleRange[0].To.Y <= ey )) { var edge = superSampleRange[0]; // Determine the lower and upper x value where the edge // intersects the scanline. var xey = edge.Intersection(ey); var xey1 = edge.Intersection(ey + 1); var x0 = Math.Min(xey, xey1); var x1 = Math.Max(xey, xey1); var width = x1 - x0; // Compute the average color of all subpixel layers before // and after the edge intersection. var fromColorAverage = new AverageColor(); var toColorAverage = new AverageColor(); for (var sy = 0; sy < usedLayers; sy++) { var subScanlineLayers = layers[sy]; fromColorAverage.Add(subScanlineLayers.CurrentColor); toColorAverage.Add(subScanlineLayers.Add(edge)); } var fromColor = fromColorAverage.Color; color = toColorAverage.Color; // Render pixels for (var x = superSampleRange.FromX; x < superSampleRange.ToXExcl; x++) { if (x0 >= x + 1) { // Pixel not covered writer.Write(fromColor); continue; } if (x1 <= x) { // Pixel fully covered writer.Write(color); continue; } // toColor coverage in the range [0.0, 1.0] // Initialize to the fully covered range of the pixel. var coverage = x1 < x + 1 ? x + 1 - x1 : 0; // Compute integral for non-vertical edges if (width > 0.001f) { // Range to integrate var integralFrom = Math.Max(x0, x); var integralTo = Math.Min(x1, x + 1); coverage += ( (integralTo * integralTo - integralFrom * integralFrom) / 2 + x0 * (integralFrom - integralTo) ) / width; } writer.Write(Color.Mix(fromColor, color, coverage)); } } // /simplified antialiasing else { // There are more than a single intersecting edge in this range. // Use super sampling to render the pixels. intersections.Initialize(ranges.Count); var y = ey + SuperSampling.SampleHeight / 2; // Ensure all subpixel layers are initialized while (usedLayers < SuperSampling.SamplesPerPixelY) { layers[0].CopyTo(layers[usedLayers]); usedLayers++; } // Average color of the pixels following the current supersample range. var forwardColorAverage = new AverageColor(); for (var sy = 0; sy < SuperSampling.SamplesPerPixelY; sy++, y += SuperSampling.SampleHeight) { var subScanlineLayers = layers[sy]; color = subScanlineLayers.CurrentColor; superSampleRange.GetIntersections(ref intersections, y); for (var i = 0; i < intersections.Count; i++) { ref var intersection = ref intersections[i]; superSampleBuffer.Add(color, intersection.X - superSampleRange.FromX); color = subScanlineLayers.Add(intersection.Edge); } // Write an extra pixel that will contain the color that // will be forwarded until the next supersample range. superSampleBuffer.Add(color, superSampleRange.Width); superSampleBuffer.Rewind(); forwardColorAverage.Add(color); } // /subpixel // Get color to be forwarded color = forwardColorAverage.Color; // Blend subpixels superSampleBuffer.WriteTo(ref writer, superSampleRange.Width); superSampleBuffer.Clear(); } // /supersampling // Forward last color if (rangeIndex + 1 < superSampleRanges.Count) { var nextRangeX = superSampleRanges[rangeIndex + 1].FromX; writer.Write(color, nextRangeX - superSampleRange.ToXExcl); } else { writer.Write(color, width - superSampleRange.ToXExcl); } } // /range