Ejemplo n.º 1
0
 public void Scan(Scanner scanner, Rectangle clip)
 {
     scanner.yMin = int.MaxValue;
     scanner.yMax = int.MinValue;
     for(int i = 0; i < Vertices.Length; i++)
     {
         scanner.yMin = Math.Min(scanner.yMin, (int)Vertices[i].Y);
         scanner.yMax = Math.Max(scanner.yMax, (int)Vertices[i].Y);
     }
     //clip to clip, but with leeway
     if(scanner.yMin < clip.Min.Y - 1) scanner.yMin = clip.Min.Y - 1;
     if(scanner.yMax > clip.Max.Y + 1) scanner.yMax = clip.Max.Y + 1;
     for(int y = scanner.yMin; y <= scanner.yMax; y++)
     {
         scanner[y] = new Scanner.Scan{min = float.PositiveInfinity, max = float.NegativeInfinity};
     }
     for(int i = 0; i < Vertices.Length; i++)
     {
         ScanLine(scanner, Vertices[i], Vertices[(i + 1) % Vertices.Length]);
     }
     //true clip
     if(scanner.yMin < clip.Min.Y)
     {
         scanner.yMin = clip.Min.Y;
         scanner.isYMinClipped = true;
     }
     if(scanner.yMax > clip.Max.Y)
     {
         scanner.yMax = clip.Max.Y;
         scanner.isYMaxClipped = true;
     }
 }
Ejemplo n.º 2
0
 public void Scan(Scanner scanner, Rectangle clip)
 {
     scanner.yMin = Rect.Min.Y;
     scanner.yMax = Rect.Max.Y;
     //clip to clip, but with leeway
     if(scanner.yMin < clip.Min.Y - 1) scanner.yMin = clip.Min.Y - 1;
     if(scanner.yMax > clip.Max.Y + 1) scanner.yMax = clip.Max.Y + 1;
     for(int y = scanner.yMin; y <= scanner.yMax; y++)
     {
         if(y < Rect.Min.Y + Radii.Y)
         {
             double dy = (Rect.Min.Y + Radii.Y) - y;
             double dx = Math.Sqrt(1 - (dy * dy) / (Radii.Y * Radii.Y)) * Radii.X;
             dx -= Radii.X;
             scanner[y] = new Scanner.Scan{min = Rect.Min.X - (float)dx, max = Rect.Max.X + (float)dx};
         }else
         if(y > Rect.Max.Y - Radii.Y)
         {
             double dy = y - (Rect.Max.Y - Radii.Y);
             double dx = Math.Sqrt(1 - (dy * dy) / (Radii.Y * Radii.Y)) * Radii.X;
             dx -= Radii.X;
             scanner[y] = new Scanner.Scan{min = Rect.Min.X - (float)dx, max = Rect.Max.X + (float)dx};
         }else
         {
             scanner[y] = new Scanner.Scan{min = Rect.Min.X, max = Rect.Max.X};
         }
     }
     //true clip
     if(scanner.yMin < clip.Min.Y)
     {
         scanner.yMin = clip.Min.Y;
         scanner.isYMinClipped = true;
     }
     if(scanner.yMax > clip.Max.Y)
     {
         scanner.yMax = clip.Max.Y;
         scanner.isYMaxClipped = true;
     }
 }
Ejemplo n.º 3
0
 public void Scan(Scanner scanner, Rectangle clip)
 {
     ((Ellipse)this).Scan(scanner, clip);
 }
Ejemplo n.º 4
0
 public void Scan(Scanner scanner, Rectangle clip)
 {
     new Rectangle{Min = Min.Round(), Max = Max.Round()}.Scan(scanner, clip);
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Basic implementation of a constant src solid filling renderer.
        /// </summary>
        /// <param name="clip">The clipping rectangle.</param>
        /// <param name="scanner">The scans to render.</param>
        /// <param name="dest">The map to render to.</param>
        /// <param name="value">The constant value.</param>
        /// <param name="mode">The color blending mode to use.</param>
        /// <param name="isAA">True if anti-aliasing is enabled.</param>
        public static void SolidConstRender(Rectangle clip, Scanner scanner, DataMap<ARGB> dest, ARGB value, ColorMode mode = ColorMode.NORMAL, bool isAA = true)
        {
            //for constants, we can early return on blend and mask when alpha is 0
            if((mode == ColorMode.BLEND || mode == ColorMode.MASK) && value.A == 0) return;
            //mask at non-zero is equivalent to normal
            if(mode == ColorMode.MASK) mode = ColorMode.NORMAL;
            //blend at opaque is equivalent to normal
            if(mode == ColorMode.BLEND && value.A == 255) mode = ColorMode.NORMAL;

            IUnsafeMap uDest = dest as IUnsafeMap;
            if(uDest == null)
            {
                throw new InvalidOperationException("Destination image does not support advanced color rendering!");
            }
            byte* addr = uDest.BeginUnsafeOperation();
            int width = dest.Width;
            int stride = uDest.GetStride();

            for(int y = scanner.yMin; y <= scanner.yMax; y++)
            {
                double x1 = Max(scanner[y].min, clip.Min.X);
                double x2 = Min(scanner[y].max, clip.Max.X);
                //Anti-Aliasing variables
                //x1 vars are x min side
                //x2 vars are x max side
                //xb vars are y min side
                //xa vars are y max side
                double x1b = 0, x1a = 0;
                double x2b = 0, x2a = 0;
                int left;
                int right;
                if(isAA)
                {
                    bool hasMin = false, hasMax = false;
                    //if not at ymin or ymin is a clipped min (aka we have another "ghost" scan)
                    if(y > scanner.yMin || scanner.isYMinClipped)
                    {
                        x1b = Max(scanner[y - 1].min, clip.Min.X);
                        x2b = Min(scanner[y - 1].max, clip.Max.X);
                        x1b = (x1b + x1) / 2;
                        x2b = (x2b + x2) / 2;
                        hasMin = true;
                    }
                    //if not at ymax or ymax is a clipped max (aka we have another "ghost" scan)
                    if(y < scanner.yMax || scanner.isYMaxClipped)
                    {
                        x1a = Max(scanner[y + 1].min, clip.Min.X);
                        x2a = Min(scanner[y + 1].max, clip.Max.X);
                        x1a = (x1a + x1) / 2;
                        x2a = (x2a + x2) / 2;
                        hasMax = true;
                    }

                    if(!hasMin)
                    {
                        //if single line shape, just make everything literal
                        if(!hasMax)
                        {
                            x1b = x1a = x1;
                            x2b = x2a = x2;
                        }else//if at ymin, extrapolate max->current into current->min
                        {
                            x1b = x1 - (x1a - x1);
                            x2b = x2 - (x2a - x2);
                        }
                    }else//if at ymax, extrapolate min->current into current->max
                    if(!hasMax)
                    {
                        x1a = x1 + (x1 - x1b);
                        x2a = x2 + (x2 - x2b);
                    }

                    //if aa, round toward center
                    left = (int)Math.Ceiling(Max(x1b, x1a));
                    right = (int)Math.Floor(Min(x2b, x2a));
                }else
                {
                    //if not aa, round away from center to match default renderer
                    left = (int)Math.Floor(x1);
                    right = (int)Math.Ceiling(x2);
                }
                //if valid center
                if(left <= right)
                {
                    //solid fill with blend modes
                    byte* ptr = addr + (left + (y * width)) * stride;
                    byte* endPtr = ptr + (right - left + 1) * stride;
                    switch(mode)
                    {
                        case ColorMode.BLEND:
                        {
                            //precalc value
                            ARGB preValue = new ARGB{A = (byte)(255 - value.A),
                                                     R = (byte)((value.R * value.A) >> 8),
                                                     G = (byte)((value.G * value.A) >> 8),
                                                     B = (byte)((value.B * value.A) >> 8)};
                            while(ptr != endPtr)
                            {
                                //*((ARGB*)ptr) &= value;
                                //manually inline blending
                                ARGB color = *(ARGB*)ptr;
                                color = new ARGB{A = (byte)(value.A + color.A),
                                                 R = (byte)(preValue.R + ((color.R * preValue.A) >> 8)),
                                                 G = (byte)(preValue.G + ((color.G * preValue.A) >> 8)),
                                                 B = (byte)(preValue.B + ((color.B * preValue.A) >> 8))};
                                *(ARGB*)ptr = color;
                                ptr += stride;
                            }
                            break;
                        }
                        case ColorMode.NORMAL:
                        {
                            while(ptr != endPtr)
                            {
                                *((ARGB*)ptr) = value;
                                ptr += stride;
                            }
                            break;
                        }
                    }
                }
                //if aa, add smoothing to edges
                if(isAA)
                {
                    int center = (left + right) / 2;
                    if(Min(x1b, x1a) != left)
                        AAEdgeConst(addr, width, stride, x1b, x1a, y, value, true, clipMax: Min(center, clip.Max.X));
                    if(Max(x2b, x2a) != right)
                        AAEdgeConst(addr, width, stride, x2b + 1, x2a + 1, y, value, false, clipMin: Max(center + 1, clip.Min.X));
                }
            }

            uDest.EndUnsafeOperation();
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Basic implementation of a map src solid filling renderer.
        /// </summary>
        /// <param name="clip">The clipping rectangle.</param>
        /// <param name="scanner">The scans to render.</param>
        /// <param name="dest">The map to render to.</param>
        /// <param name="src">The source map.</param>
        /// <param name="offset">The offset of the source map.</param>
        /// <param name="mode">The color blending mode to use.</param>
        /// <param name="isAA">True if anti-aliasing is enabled.</param>
        public static void SolidCopyRender(Rectangle clip, Scanner scanner, DataMap<ARGB> dest, DataMap<ARGB> src, Point2D offset, ColorMode mode = ColorMode.NORMAL, bool isAA = true)
        {
            IUnsafeMap uDest = dest as IUnsafeMap;
            IUnsafeMap uSrc = src as IUnsafeMap;
            if(uDest == null)
            {
                throw new InvalidOperationException("Destination image does not support advanced color rendering!");
            }
            if(uSrc == null)
            {
                throw new InvalidOperationException("Source image does not support advanced color rendering!");
            }
            byte* addr = uDest.BeginUnsafeOperation();
            int width = dest.Width;
            int stride = uDest.GetStride();
            byte* srcAddr = uSrc.BeginUnsafeOperation();
            int srcWidth = src.Width;
            int srcStride = uSrc.GetStride();

            for(int y = scanner.yMin; y <= scanner.yMax; y++)
            {
                double x1 = Max(scanner[y].min, clip.Min.X);
                double x2 = Min(scanner[y].max, clip.Max.X);
                //Anti-Aliasing variables
                //x1 vars are x min side
                //x2 vars are x max side
                //xb vars are y min side
                //xa vars are y max side
                double x1b = 0, x1a = 0;
                double x2b = 0, x2a = 0;
                int left;
                int right;
                if(isAA)
                {
                    bool hasMin = false, hasMax = false;
                    //if not at ymin or ymin is a clipped min (aka we have another "ghost" scan)
                    if(y > scanner.yMin || scanner.isYMinClipped)
                    {
                        x1b = Max(scanner[y - 1].min, clip.Min.X);
                        x2b = Min(scanner[y - 1].max, clip.Max.X);
                        x1b = (x1b + x1) / 2;
                        x2b = (x2b + x2) / 2;
                        hasMin = true;
                    }
                    //if not at ymax or ymax is a clipped max (aka we have another "ghost" scan)
                    if(y < scanner.yMax || scanner.isYMaxClipped)
                    {
                        x1a = Max(scanner[y + 1].min, clip.Min.X);
                        x2a = Min(scanner[y + 1].max, clip.Max.X);
                        x1a = (x1a + x1) / 2;
                        x2a = (x2a + x2) / 2;
                        hasMax = true;
                    }

                    if(!hasMin)
                    {
                        //if single line shape, just make everything literal
                        if(!hasMax)
                        {
                            x1b = x1a = x1;
                            x2b = x2a = x2;
                        }else//if at ymin, extrapolate max->current into current->min
                        {
                            x1b = x1 - (x1a - x1);
                            x2b = x2 - (x2a - x2);
                        }
                    }else//if at ymax, extrapolate min->current into current->max
                    if(!hasMax)
                    {
                        x1a = x1 + (x1 - x1b);
                        x2a = x2 + (x2 - x2b);
                    }

                    //if aa, round toward center, otherwise round away to match default renderer
                    left = (int)Math.Ceiling(Max(x1b, x1a));
                    right = (int)Math.Floor(Min(x2b, x2a));
                }else
                {
                    //if not aa, round away to match default renderer
                    left = (int)Math.Floor(x1);
                    right = (int)Math.Ceiling(x2);
                }

                //if valid center
                if(left <= right)
                {
                    //solid fill with blend modes
                    byte* ptr = addr + (left + (y * width)) * stride;
                    byte* srcPtr = srcAddr + ((left + offset.X) + ((y + offset.Y) * srcWidth)) * srcStride;
                    byte* endPtr = ptr + (right - left + 1) * stride;
                    switch(mode)
                    {
                        case ColorMode.BLEND:
                        {
                            while(ptr != endPtr)
                            {
                                //*((ARGB*)ptr) &= *((ARGB*)srcPtr);
                                //manually inline blending
                                ARGB srcColor = *(ARGB*)srcPtr;
                                ARGB color = *(ARGB*)ptr;
                                int aComp = 255 - srcColor.A;
                                color = new ARGB{A = (byte)(srcColor.A + color.A),
                                                 R = (byte)(((srcColor.R * srcColor.A) + (color.R * aComp)) >> 8),
                                                 G = (byte)(((srcColor.G * srcColor.A) + (color.G * aComp)) >> 8),
                                                 B = (byte)(((srcColor.B * srcColor.A) + (color.B * aComp)) >> 8)};
                                *(ARGB*)ptr = color;
                                ptr += stride;
                                srcPtr += srcStride;
                            }
                            break;
                        }
                        case ColorMode.NORMAL:
                        {
                            while(ptr != endPtr)
                            {
                                *((ARGB*)ptr) = *((ARGB*)srcPtr);
                                ptr += stride;
                                srcPtr += srcStride;
                            }
                            break;
                        }
                        case ColorMode.MASK:
                        {
                            while(ptr != endPtr)
                            {
                                if((*((ARGB*)srcPtr)).A != 0)
                                    *((ARGB*)ptr) = *((ARGB*)srcPtr);
                                ptr += stride;
                                srcPtr += srcStride;
                            }
                            break;
                        }
                    }
                }
                //if aa, add smoothing to edges
                if(isAA)
                {
                    int center = (left + right) / 2;
                    if(Min(x1b, x1a) != left)
                        AAEdgeCopy(addr, width, stride, x1b, x1a, y, srcAddr, srcWidth, srcStride, offset, true, clipMax: Min(center, clip.Max.X));
                    if(Max(x2b, x2a) != right)
                        AAEdgeCopy(addr, width, stride, x2b + 1, x2a + 1, y, srcAddr, srcWidth, srcStride, offset, false, clipMin: Max(center + 1, clip.Min.X));
                }
            }

            uDest.EndUnsafeOperation();
            uSrc.EndUnsafeOperation();
        }
Ejemplo n.º 7
0
 public void Scan(Scanner scanner, Rectangle clip)
 {
     Point2D center = (Point2D)Position.Round();
     scanner.yMin = center.Y - (int)Radii.Y;
     scanner.yMax = center.Y + (int)Radii.Y;
     //clip to clip, but with leeway
     if(scanner.yMin < clip.Min.Y - 1) scanner.yMin = clip.Min.Y - 1;
     if(scanner.yMax > clip.Max.Y + 1) scanner.yMax = clip.Max.Y + 1;
     for(int y = scanner.yMin; y <= scanner.yMax; y++)
     {
         double dy = center.Y - y;
         double dx = Math.Sqrt(1 - (dy * dy) / (Radii.Y * Radii.Y)) * Radii.X;
         scanner[y] = new Scanner.Scan{min = center.X - (float)dx, max = center.X + (float)dx};
     }
     //true clip
     if(scanner.yMin < clip.Min.Y)
     {
         scanner.yMin = clip.Min.Y;
         scanner.isYMinClipped = true;
     }
     if(scanner.yMax > clip.Max.Y)
     {
         scanner.yMax = clip.Max.Y;
         scanner.isYMaxClipped = true;
     }
 }
Ejemplo n.º 8
0
 /// <summary>
 /// Returns a scanner for the given height.
 /// </summary>
 /// <param name="height">The height of the target.</param>
 /// <returns>A scanner obj.</returns>
 public static Scanner Get(int height)
 {
     lock(scanners)
     {
         foreach(var node in scanners.GetNodes())
         {
             if(node.Value.Length >= height)
             {
                 scanners.Remove(node);
                 return node.Value;
             }
         }
     }
     Scanner result = scanners.Pop();
     if(result == null) result = new Scanner();
     result.EnsureSize(height);
     return result;
 }
Ejemplo n.º 9
0
 /// <summary>
 /// Returns a scanner to the pool after it's done being used.
 /// </summary>
 /// <param name="scanner">The scanner to return.</param>
 public static void Put(Scanner scanner)
 {
     scanners.AddSorted(scanner, (a, b) => a.Length - b.Length);
 }
Ejemplo n.º 10
0
        private void ScanLine(Scanner scanner, Vec2D v1, Vec2D v2)
        {
            if((int)v1.Y == (int)v2.Y)
            {
                int ly = (int)v1.Y;
                if(ly > scanner.yMin && ly < scanner.yMax)
                {
                    double minX = Math.Min(v1.X, v2.X);
                    double maxX = Math.Max(v1.X, v2.X);
                    Scanner.Scan scan = scanner[ly];
                    scan.min = Math.Min(scan.min, (float)minX);
                    scan.max = Math.Max(scan.max, (float)maxX);
                    scanner[ly] = scan;
                }
                return;
            }

            //v1.Y always less than v2.Y
            if(v1.Y > v2.Y)
            {
                Util.Swap(ref v1, ref v2);
            }
            //skip if out of bounds
            if(v2.Y < scanner.yMin || v1.Y > scanner.yMax) return;

            double x = v1.X;
            double dx = (v2.X - v1.X) / ((int)v2.Y - (int)v1.Y);
            int y = (int)v1.Y;
            int maxY = Math.Min((int)v2.Y, scanner.yMax);
            //start at beginning
            if(y < scanner.yMin)
            {
                x += dx * (scanner.yMin - y);
                y = scanner.yMin;
            }
            for(; y <= maxY; y++, x += dx)
            {
                Scanner.Scan scan = scanner[y];
                scan.min = Math.Min(scan.min, (float)x);
                scan.max = Math.Max(scan.max, (float)x);
                scanner[y] = scan;
            }
        }