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);
        }
Beispiel #5
0
        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